代表的な面接トピック

コーディング面接: 耐久性のあるテスト成果物のためにGo 1.26のArtifactDirをどのように活用しますか?

コーディング難しい
Offer.cc 編集チーム公開日 更新日

質問

Goのテストが断続的に失敗しますが、ログだけでは不十分です。Go 1.26ではArtifactDirが追加されます。成果物(アーティファクト)戦略を設計し、いつ書き込むべきか、並行処理による競合をどのように回避するか、ローカルとCIでの保持の違い、および認証情報の漏洩を防ぐ方法について説明してください。

質問と範囲

あるGoサービスで、単体テスト、ベンチマーク、ファズテストが断続的に失敗しています。開発者は、成功したCI実行を汚染したり、並行テストが互いに上書きし合ったりすることなく、リクエストのサンプル、パフォーマンスの概要、およびデバッグダンプを取得したいと考えています。Go 1.26のtesting.T.ArtifactDirtesting.B.ArtifactDir、およびtesting.F.ArtifactDirを使用して、成果物ポリシーを設計してください。

go test -artifactsを指定すると、Go 1.26は出力ディレクトリ配下に永続的なディレクトリを返します。指定しない場合、返される一時ディレクトリはテスト後に削除されます。エビデンスを書き込むコードとそれを保持する決定を分離し、テストフレームワークにディレクトリのライフサイクルを制御させてください。

コンテキストと境界条件

Goのテストコード、並行性の分離、CIのアーカイブ、および機密データに焦点を当てます。CIプラットフォームはアップロード、権限、保持期間、およびオブジェクトストレージを提供します。失敗トリガー、命名規則、サイズ制限、マスキング(墨消し)、およびリトライの境界を明示してください。

面接官がテストしていること

  • T、B、およびFのコンテキストごとに成果物ディレクトリを区別できているか。
  • 失敗したテストがエビデンスを保持しつつ、成功した実行が永続的なノイズにならないようにできているか。
  • t.Parallel、サブテスト、ベンチマークループ、およびファズの再生用命名を適切に処理できているか。
  • ファイルがリトライ可能で、サイズが制限され、アーカイブ可能であり、コミットとテスト名に追跡可能であるか。
  • トークン、ユーザーデータ、プライベートURL、およびコアダンプが公開CIの成果物から除外されているか。

30秒の回答

「すべてのテストはArtifactDirからディレクトリを取得します。ファイル名には、推測されたワークスペースのパスではなく、テストパス、実行ID、およびイベントシーケンスを使用します。コードは、失敗時、しきい値超過時、または明示的な診断時に重要なエビデンスを書き込みます。CIではgo test -artifactsを有効にしてディレクトリをアーカイブしますが、ローカルのデフォルトではクリーンアップされる一時ディレクトリを使用します。書き込みには一時ファイルと名前変更(アトミックリネーム)を使用し、バイト数とファイル数の制限を設けます。マニフェストによってコミット、パッケージ、テスト、プラットフォーム、ハッシュ、およびマスキング状態を関連付けます。アップロードの失敗はアラートを発しますが、元のテスト結果を変更することはありません。」

ステップバイステップの解決策

  1. 単一の成果物エントリポイントを使用する。 テストは*testing.T*testing.B、または*testing.Fを受け取り、対応するArtifactDirを呼び出します。テストロジックにos.TempDir、作業ディレクトリ、またはプライベートなCIパスをハードコードしないでください。
  1. 保持と書き込みを分離する。 テストコードは失敗の前後に書き込むことができますが、永続化はgo test -artifactsが有効な場合にのみ期待されます。デフォルトの実行ではクリーンアップされる一時ディレクトリが使用され、CIでは明示的に成果物を有効にしてアップロードします。
  1. 並行処理を考慮した命名を設計する。 パッケージ、テスト、実行ID、サブテストのパス、および単調増加シーケンスから論理キーを構築します。区切り文字や印刷不能文字をサニタイズします。並行して実行されるインスタンス間で固定のdebug.jsonを決して共有してはなりません。
  1. 制限を設けてアトミックに書き込む。 成果物ディレクトリ内に一時ファイルを作成し、正常に閉じてから名前を変更します。ファイル単位、テスト単位、実行単位でのバイト数およびカウント数の制限を適用します。上限を超えた場合はランナーを枯渇させるのではなく、サマリーを生成します。
go
func writeArtifact(t *testing.T, name string, data []byte) {
    t.Helper()
    dir := t.ArtifactDir()
    path := filepath.Join(dir, safeName(name)+".json")
    tmp, err := os.CreateTemp(dir, ".partial-")
    if err != nil { t.Fatalf("create artifact: %v", err) }
    defer tmp.Close()
    if _, err := tmp.Write(data); err != nil { t.Fatalf("write artifact: %v", err) }
    if err := tmp.Close(); err != nil { t.Fatalf("close artifact: %v", err) }
    if err := os.Rename(tmp.Name(), path); err != nil { t.Fatalf("publish artifact: %v", err) }
}

この例では、サイズチェック、マスキング、および移植性のあるファイル名の処理を省略しています。本番環境のコードでは、これらを共有テスト制約とする必要があります。

  1. 失敗またはしきい値でトリガーする。 失敗したテストは、最小限の再現手順、リクエストのサマリー、トレース識別子、および環境のサマリーを保持します。ベンチマークでは、リグレッションのしきい値を超えた場合や明示的な診断モードでのみプロファイルやサンプルを保存します。ファズテストでは、機密情報を含む完全なリクエストではなく、再生可能なシードとマスキング済みのサイズ制限された入力を保存します。
  1. CI成果物にインデックスを付ける。 コミットSHA、パッケージ、テスト、Goのバージョン、OS/アーキテクチャ、相対パス、サイズ、ハッシュ、およびマスキング状態を含むマニフェストを出力します。アップロードは実行IDごとに分離します。アップロードの失敗はアラートを発するべきですが、失敗しているアサーションを合格に変えてはなりません。
  1. 安全性を確保してクリーンアップする。 書き込みを行う前に、トークン、Cookie、Authorizationヘッダー、個人データ、およびプライベートホスト名を削除します。デフォルトでコアダンプを無効にします。最小権限の読み取りと短い保持期間を設定し、自動的に期限切れになるようにします。ダウンロードには依然としてコンテンツレベルのレビューが必要です。
  1. ライフサイクルをテストする。 失敗するサブテスト、並行サブテスト、go test -artifactsを実行するケース、およびデフォルトで実行するケースを網羅します。適切なクリーンアップ、インデックス可能な失敗エビデンス、重複しないリトライID、およびアップロード中断時におけるローカルエビデンスの保持を検証します。

模範回答

すべての診断ファイルは、T、B、またはFのArtifactDirを起点とする必要があります。テストロジックが物理パスを意識すべきではありません。永続性はgo test -artifactsによって制御されます。CIではこれを有効にしてアーカイブし、ローカル実行ではクリーンアップされる一時ディレクトリを使用します。並行処理での衝突を防ぐため、名前にはパッケージ、テスト、サブテストのパス、実行ID、およびシーケンスを含めます。書き込みには一時ファイルと名前変更を使用し、バイト数とカウント数の制限を設けます。

失敗したテストは、最小限の入力、リクエストのサマリー、および環境データを保持します。ベンチマークは、リグレッションのしきい値または明示的な診断モードがトリガーされた場合にのみプロファイルを保持します。ファズテストは、シードと再生可能な入力を保持します。マスキングは書き込み前に行われ、マニフェストにはコミット、Goバージョン、プラットフォーム、ハッシュ、およびサイズが記録されます。アップロードの失敗はテストステータスを変更せずにアラートを発します。リグレッションテストでは、並行性、失敗、デフォルトの一時ストレージ、および永続的な-artifactsストレージをカバーします。

よくある間違い

  • 間違い: ArtifactDirを恒久的なものとして扱う → 失敗する理由: デフォルトの一時ディレクトリはテスト後に削除される → 修正方法: CIで-artifactsを有効にし、アーカイブを設定する。
  • 間違い: すべての並行テストがdebug.jsonに書き込む → 失敗する理由: ファイルが上書きされたりインターリーブ(混在)したりする → 修正方法: テストパス、実行ID、およびシーケンスによって名前を付ける。
  • 間違い: 失敗時に完全なHTTPリクエストをアップロードする → 失敗する理由: トークンや個人データが漏洩する → 修正方法: マスキング、要約を行い、保持期間を制限する。
  • 間違い: 成果物の書き込み失敗によってテストをパスさせてしまう → 失敗する理由: 失敗のエビデンスが失われ、環境の問題が隠蔽される → 修正方法: アサーションを変更することなく、必要なエビデンスに対して失敗させるか明示的にアラートを出す。
  • 間違い: ベンチマークのイテレーションごとにプロファイルを書き込む → 失敗する理由: 成果物の容量と実行時間が無制限に増大する → 修正方法: リグレッションのしきい値に達した際や明示的な診断時のみ収集する。

フォローアップの質問と回答

なぜos.TempDirを直接使用しないのですか?

ArtifactDirを使用することで、テストフレームワークとCIがライフサイクルの決定権を持つことができ、T、B、Fに統一されたインターフェースが提供され、実行環境固有のパスを避けることができます。使い捨てのヘルパーファイルにはos.TempDirで十分ですが、成果物プロトコルとしては適していません。

ファズの成果物を再生可能な状態に保つにはどうすればよいですか?

Goのバージョン、パッケージ、テスト、シード、制限された入力のハッシュ、および必要な環境変数を記録します。サイズが大きすぎる場合や機密情報を含む入力の場合は、マスキングされたサマリーを保存し、完全なエビデンスは保護されたストレージにのみ保持します。

ベンチマークはいつ成果物を書き込むべきですか?

まずベンチマークを完了させ、ベースラインと比較します。しきい値を超えるリグレッションが発生した場合、明示的な-bench診断時、または失敗した後にのみプロファイルを書き込みます。通常の実行が永続的なアーカイブにならないよう、サンプル数、CPU、実行時間、およびコミット情報を含めます。

成果物のアップロード失敗によってCIを失敗させるべきですか?

アサーションの失敗は必ず失敗と判定しなければなりません。アップロードの失敗によってリリースをブロックするかどうかはチームのエビデンス基準に依存しますが、少なくともアラートを発し、ローカルパスを保持する必要があります。ネットワークの状態をテストステータスに偽装してはなりません。

リトライはどのように処理しますか?

試行ごとに個別の実行IDを生成します。アーカイブキーにはコミット、プラットフォーム、パッケージ、テスト、および試行回数を含めます。インデックスでは試行をグループ化できますが、生ファイル同士が決して上書きされないようにします。リトライでランダムシードが再利用されたかどうかを記録します。

参考資料

  • Go 1.26 リリースノート (Go公式)
  • testing パッケージ (Go公式)
  • Go リリース履歴 (Go公式)

面接チェックリスト

まずArtifactDirのライフサイクルを説明し、次に並行処理用の命名、アトミックな書き込み、失敗トリガー、マニフェスト、マスキング、CIアーカイブ、およびリグレッションテストを追加します。

一行のまとめ

ArtifactDirはライフサイクルのエントリポイントを提供します。信頼性の高い診断には、分離、制限、マスキング、インデックス作成、および再生可能なエビデンスが依然として必要です。

練習を続けましょう

CIでファズテスト、ベンチマーク、統合テストを同時に実行する場合は、共有マニフェスト、クォータ、および失敗優先のアップロードスケジューラを設計してください。

公開情報ソース

関連する質問

関連面接ツール

コーディング問題にはスクリーンショットを使用

問題をキャプチャし、制約条件、解法アプローチ、コード、エッジケース、計算量の順に進めます。

ツールを見る