Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 10364] exp/ssh クライアント機能テストの追加

コミット

  • コミットハッシュ: 34466a14911163fadcc54725143b04c47d4080aa
  • 作者: Dave Cheney dave@cheney.net
  • 日付: 2011年11月13日 20:58:51 -0500
  • コミットメッセージ: exp/ssh: add client functional tests

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/34466a14911163fadcc54725143b04c47d4080aa

元コミット内容

exp/ssh: add client functional tests

Requires CL 5373055

R=rsc, agl, n13m3y3r
CC=golang-dev
https://golang.org/cl/5320053

このコミットは、Goの実験的SSH パッケージ(exp/ssh)にクライアント機能テストを追加しました。61行のコードで新しいファイル client_func_test.go を作成し、パスワード認証と公開鍵認証の両方をテストする機能を実装しました。

変更の背景

2011年当時、GoはSSHクライアント機能の実装を実験的パッケージ(exp/ssh)として開発していました。このパッケージは、外部依存なしにGoアプリケーションからSSH接続を可能にする重要な機能でした。

Dave Cheneyは、2011年11月21日のブログ投稿で「Three new SSH client features in Go weekly.2011-11-18」として、以下の主要機能を発表しました:

  1. 公開鍵認証のサポート: クライアントが公開鍵認証をサポートするようになりました
  2. ClientKeyring インターフェース: 公開鍵認証を使用するためのインターフェースが追加されました
  3. 直接TCP/IP接続: SSH接続を介してTCP接続をトンネリングする実験的サポートが追加されました

これらの機能をテストするために、実際のSSHサーバーとの接続を試験する機能テストが必要となり、このコミットが作成されました。

前提知識の解説

SSH認証方式

SSH(Secure Shell)は、リモートシステムへの安全な接続を提供するネットワークプロトコルです。主要な認証方式には以下があります:

  1. パスワード認証:

    • 最も基本的な認証方式
    • ユーザー名とパスワードを使用
    • 比較的簡単だが、パスワードの漏洩リスクがある
  2. 公開鍵認証:

    • 暗号化鍵ペア(公開鍵と秘密鍵)を使用
    • より高いセキュリティレベルを提供
    • 自動化されたパスワードレスログインが可能
    • 攻撃者がサーバーに保存された公開鍵に対応する秘密鍵のコピーを必要とするため、ランダムな攻撃を防げる

Go の testing パッケージ

Go言語のtestingパッケージは、自動テストのサポートを提供します。2011年当時から、Goのテストフレームワークは以下の特徴を持っていました:

  • テスト関数はTestで始まり、_test.goで終わるファイルに記述
  • flagパッケージとの統合により、コマンドラインフラグを使用可能
  • gotestコマンド(後のgo test)でテストを実行

機能テスト vs 単体テスト

  • 単体テスト: 個別の関数や機能をテストするもの
  • 機能テスト: 実際のサービスや外部システムと連携してテストするもの

このコミットで追加されたのは機能テストで、実際のSSHサーバーとの接続を必要とします。

技術的詳細

ファイル構成

新しく追加されたファイル:

  • src/pkg/exp/ssh/client_func_test.go: 61行のテストファイル

実装の特徴

  1. 条件付きテスト実行:

    • SSHサーバーが利用可能で、適切なフラグが設定されている場合のみテストが実行される
    • フラグが設定されていない場合は、テストをスキップする
  2. フラグベースの設定:

    • -ssh.user: SSH ユーザー名
    • -ssh.pass: SSH パスワード
    • -ssh.privkey: SSH 秘密鍵ファイル
  3. 両方の認証方式のテスト:

    • パスワード認証のテスト
    • 公開鍵認証のテスト
  4. リソース管理:

    • defer conn.Close() で接続のクリーンアップを保証

コアとなるコードの変更箇所

ファイル: src/pkg/exp/ssh/client_func_test.go

// 新規ファイル作成(61行)
// ClientConn functional tests.
// These tests require a running ssh server listening on port 22
// on the local host. Functional tests will be skipped unless 
// -ssh.user and -ssh.pass must be passed to gotest.

主要な変更点:

  1. パッケージ宣言: package ssh
  2. フラグ定義: sshuser, sshpass, sshprivkey
  3. テスト関数: TestFuncPasswordAuth, TestFuncPublickeyAuth

コアとなるコードの解説

フラグ定義部分

var (
    sshuser    = flag.String("ssh.user", "", "ssh username")
    sshpass    = flag.String("ssh.pass", "", "ssh password")
    sshprivkey = flag.String("ssh.privkey", "", "ssh privkey file")
)

この部分では、コマンドラインフラグを定義しています。flag.String関数は、以下の引数を受け取ります:

  • フラグ名
  • デフォルト値
  • 説明文

パスワード認証テスト

func TestFuncPasswordAuth(t *testing.T) {
    if *sshuser == "" {
        t.Log("ssh.user not defined, skipping test")
        return
    }
    config := &ClientConfig{
        User: *sshuser,
        Auth: []ClientAuth{
            ClientAuthPassword(password(*sshpass)),
        },
    }
    conn, err := Dial("tcp", "localhost:22", config)
    if err != nil {
        t.Fatalf("Unable to connect: %s", err)
    }
    defer conn.Close()
}

このテストでは:

  1. sshuserフラグが設定されているかチェック
  2. パスワード認証用のClientConfigを作成
  3. localhost:22への接続を試行
  4. 接続に失敗した場合、テストを失敗させる
  5. 成功した場合、deferで接続をクローズ

公開鍵認証テスト

func TestFuncPublickeyAuth(t *testing.T) {
    if *sshuser == "" {
        t.Log("ssh.user not defined, skipping test")
        return
    }
    kc := new(keychain)
    if err := kc.loadPEM(*sshprivkey); err != nil {
        t.Fatalf("unable to load private key: %s", err)
    }
    config := &ClientConfig{
        User: *sshuser,
        Auth: []ClientAuth{
            ClientAuthPublickey(kc),
        },
    }
    conn, err := Dial("tcp", "localhost:22", config)
    if err != nil {
        t.Fatalf("unable to connect: %s", err)
    }
    defer conn.Close()
}

このテストでは:

  1. sshuserフラグが設定されているかチェック
  2. 新しいkeychainオブジェクトを作成
  3. 秘密鍵ファイルを読み込み
  4. 公開鍵認証用のClientConfigを作成
  5. 接続を試行し、結果を検証

設計上の重要な考慮事項

  1. テストの条件付き実行: ユーザーが適切なフラグを設定していない場合、テストは静かにスキップされます。これにより、CI/CDパイプラインでテストが常に失敗することを防げます。

  2. エラーハンドリング: t.Fatalfを使用してテストの失敗を明確に示し、詳細なエラーメッセージを提供します。

  3. リソース管理: defer文を使用して、テスト完了後に接続が確実にクローズされるようにします。

  4. 実際のサービスへの依存: これらのテストは実際のSSHサーバーへの接続を必要とするため、統合テストの性質を持ちます。

関連リンク

参考にした情報源リンク