ブログに戻る

フォロー&ご登録

Fastly Fiddle 用スクリプトテストの紹介

Andrew Betts

Principal Developer Advocate, Fastly

Fastly Fiddle では、Fastly アカウントのセットアップを行うことなく Fastly のエッジクラウドプラットフォームの動作をすぐに試すことができます。現在、Fastly はユーザーが作成を試みている動作を指定するアサーションを定義する機能を追加しようとしています。

Fastly での構築をより簡単にするクラウドソリューションのレシピライブラリが先日公開され、その中でFastly 上で実行するために作成された一部のソリューションの提供が開始されました。増え続けているレシピライブラリは 100 近くに迫ります。こういったレシピを構築することで、私たちのネットワークの進化に伴って継続的にソリューションが機能していることを確認するだけでなく、そのソリューションによってどんなことができているかを明確にする優れた方法が必要であるということに気付きました。

Fiddle 用テスト

Fiddle が表示する情報は多く、圧倒されるかもしれません。ソリューションが実際に達成できた鍵となるポイントは何か、どうすればわかるのでしょうか。これまでは、皆さんの VCL コードの分析に基づいて自動で「注目すべき」HTTP ヘッダーがハイライトされていましたが、現在は Fiddle の想定動作を明確に定義できるようになりました。

テストを定義するには、まずテスト対象のロジックを含む Fiddle を記述します。簡単な例として、新しいヘッダーの情報がオリジンサーバーに転送されるように Fastly が受け取る各リクエストにヘッダーを付与してみます。

こちらがこの動作を行う Fiddle です。自由に試してみてください。

外部監視によって通常の Fastly サービス内でのこの動作をテストするのは困難です。オリジンサーバーへのリクエストにヘッダーが付与された証拠はブラウザに返されるレスポンス内にはありません。ここで必要なのは、Fastly 内部の動作に関することをアサートする機能です。

ターゲットのテスト: テストできること

Fastly を通過するリクエストのデータには主に 3 つのソース (クライアントサイドのリクエスト/レスポンス、オリジンサーバーのリクエスト/レスポンス、および Fastly プラットフォーム内でトリガーされたイベント) があります。これらをテストシンタックス内でそれぞれ clientFetchoriginFetches (複数の可能性があります)、および events として扱います。

この3つのトップレベルオブジェクトには多くの興味深い便利なプロパティがあります。

clientFetch Obj クライアントから Fastly へのリクエスト (および Fastly からのレスポンス)
.req Str リクエストメソッド、パス、HTTP バージョン、ヘッダーのキー/値のペア、リクエストボディを含む HTTP リクエストのブロック
.resp Str レスポンスのステータス行とレスポンスヘッダー (ボディ以外) を含む HTTP レスポンスヘッダー
.respType Str 解析された Content-type レスポンスヘッダーの値 (MIME タイプのみ)
.isText Bool レスポンスボディをテキストとして扱うことができるかどうか
.isImage Bool レスポンスボディを画像として扱うことができるかどうか
.status Num HTTP レスポンスのステータス
.bodyPreview Str ボディを UTF-8 テキストでプレビュー (1,000字で切り捨て)
.bodyBytesReceived Num 受信したデータ量
.bodyChunkCount Num 受信したチャンクの数
.complete Bool レスポンスが完了したかどうか
.trailers Str HTTP レスポンスのトレーラー
originFetches Array リクエスト中に行われたオリジンフェッチ
[idx] Obj 各フェッチは1つのオブジェクトです
.vclFlowKey Str このフェッチをトリガーした VCL フローの ID
.req Str リクエストメソッド、パス、HTTP バージョン、ヘッダーのキー/値のペア、リクエストボディを含む HTTP リクエストのブロック
.resp Str レスポンスのステータス行とレスポンスヘッダー (ボディ以外) を含む HTTP レスポンスヘッダー
.remoteAddr Str オリジンの解決済み IP アドレス
.remotePort Num オリジンサーバーのポート
.remoteHost Str オリジンサーバーのホスト名
.elapsedTime Num オリジンフェッチに要した合計時間 (ミリ秒)
events Array リクエストに関連する、VCL フロー順の Fastly VCL イベント。リスタートや ESI、オリジンシールドがある場合は、複数の VCL フローが含まれる可能性があります。
[idx] Obj 各配列要素は1つの VCL イベントです
.fnName Str イベントの種類。「recv」、「hash」、「hit」、「miss」、「pass」、「waf」、「fetch」、「deliver」、「error」、「log」のいずれかです。
.datacenter Str このイベントが発生した Fastly データセンターの所在地を識別する3文字のコード (「LCY」、「JFK」、「SYD」など)
.nodeID Str このイベントが発生したサーバーの識別番号
.originFetch Obj このイベントに関連するオリジンフェッチ (前述のこのモデルの originFetches を参照)。originFetch プロパティを使用するのは FETCH イベントのみです。
.logs Array このイベントから記録されたメッセージ文字列の配列
.<various> イベントについて Fiddle UI で報告されるあらゆるプロパティをテスト対象にすることができます。たとえば、MISS イベントでは staleExists プロパティが報告されます。
logs Array すべての VCL イベントから記録されたメッセージ文字列の配列
insights Array このリクエストのインサイトタグ。インサイトタグは、推奨事項またはベストプラクティスとの相違を識別します。例 : [client-cc-missing、invalid-header ]

オリジンサーバーのリクエストに追加したヘッダーを取得するには、originRequests コレクション内の 1 つ目の項目にある req プロパティにアクセスする必要があります。

originRequests[0].req

これは簡単ですが、キャッシュされたオリジンサーバーからのレスポンスもチェックしたい場合はどうすれば良いのでしょうか。この場合は、フェッチイベントの .ttlプロパティを利用する必要がありますが、どれがイベントコレクション内のフェッチイベントを示すインデックスかわかりません。必要なのはフェッチイベントのイベントコレクションをフィルタリングして 1 つ目のものを取得する方法です。

集合関数

テスト対象により簡単にアクセスできるよう集合関数を用意しています。対象の文字列にこれらを使用してデータを変換してください。

listBy(field) Array => Array

オブジェクトの配列を取得し、配列の配列を作成します。その配列の各サブ配列では、すべてのオブジェクトが同じ「field」の値を共有します。出力配列の項目の順序は、選択したフィールドの値が最初に入力に出現する順序に基づきます。

events.listBy(vclflowkey)[1][0].fnName is "recv"

where(field=val) Array => Array

オブジェクトの配列を取得し、「field」プロパティの値が「val」であるオブジェクトだけを残すようにフィルタリングします。

events.where(fnName=recv)[0].url startsWith "/a/"

groupBy(field) Array => Obj

オブジェクトの配列を取得して、それぞれが同じプロパティ「field」の値を持つ複数の配列に分割し、結果のデータを「field」値をキーとするオブジェクトに編成します。

events.groupBy(fnName).recv[0].url startsWith "/a/"

transpose() Array => Obj

オブジェクトの配列を取得し、配列のオブジェクトを作成します。複数の入力オブジェクトが同じプロパティ名を共有する場合、すべての値を含む配列が返され、そのプロパティが最上位レベルのプロパティになります。

events.transpose().return notIncludes "error"

count() Array => Num

配列を取得し、長さを返します

originFetches.count() greaterThan 1

concat() Array => Str

配列を取得し、改行処理で区切られた、すべての配列項目を結合した文字列表現を返します。

logs.concat() includes "Hello"

1 つ目のフェッチイベントの ttl プロパティは、次の方法で識別できます。

events.where(fnName=fetch)[0].ttl

最後に、この対象データにアサーションを行う必要があります。

アサーション

Fastly では、Chai で定義されたアサーションをサポートするほか、いくつかの追加を行いました。以下に便利なものを紹介します。

Name 値のタイプ 説明
is 任意 非厳密な等価 (== を使用)
isJSON なし ターゲットが有効な JSON である (基準値は不要であるため、2つのパラメーターのみ)
isTrue なし ターゲットが True である
isAtLeast、
isAbove
JSON の数値 ターゲットが数値的に基準値よりも高い
isAtMost、
isBelow
JSON の数値 ターゲットが数値的に基準値よりも低い
includes 任意 ターゲットに基準値が含まれている。配列、文字列の部分文字列、またはオブジェクト内のプロパティのサブセットに値が含まれていることをアサートするのに使用できる
matches JS 正規表現 ターゲットが正規表現に一致する。正規表現は / で区切る必要があり、修飾子 (/abc/i など) が後に続く場合がある
oneOf JSON 配列 ターゲットの値が基準の配列内の1つ以上の値と等しいことを確認する
startsWith JSON 文字列 ターゲットの値が基準の文字列で始まることを確認する
endsWith JSON 文字列 ターゲットの値が基準の文字列で終わることを確認する

これでサンプルの Fiddle のテストが作成できます。

originFetches[0].req includes "custom-header"
events.where(fnName=fetch)[0].ttl isAtLeast 3600000000

ttl プロパティと Fastly が報告するすべてのタイミングプロパティはマイクロ秒表記であることに注意してください。つまり、3600 秒 (1時間) であれば 3,600,000,000 マイクロ秒になります。では、この UI からこれらのテスト Fiddle に追加する方法を確認してみましょう。

再度 Fiddle を実行してみます。今回はテストが実行されるのを確認してください。

Fiddle が実行されるとテストが解析され、テストシンタックスに解析不可能なものがあるかどうかが通知されます。

デバッグ

テストが成功すれば問題ありませんが、失敗したらどうすれば良いのでしょうか。テストを正しく記述できたのか、それとも Fiddle 自体にバグがあったのか、どう判断すればいいででしょうか。

実行時にテストが失敗した場合、Fiddle は障害の状態だけでなく対象の実際の値も表示します。

これは対象の文字列を構築する際にも大いに役立ちます。対象となるパスにどんなプロパティがあるのかわからない場合は、そのパスを使用したテストを記述してみてください。そのテストが失敗した場合、対象がどのようになっているのか確認することができます。

テストは非同期で実行され、非同期の計測が配信されるまで待機する必要があります。対象によっては計測データの配信が他より時間がかかります。これは各テストの砂時計アイコンで表示されます。砂時計アイコンがなければ遅延なし、砂が落ちている途中の砂時計の表示なら少々の遅れ、砂が落ち終わった砂時計の表示の場合はより大きな遅延ということです。

Fastly は Fiddle でのテスト実行が可能になったことで、Fastly の設定の確認ができ、また皆さんのロジックをエッジに移すことができると願っています。ご意見がある場合は本投稿にコメントを記載していただくか、私までご連絡ください