ようへいの日々精進XP

よかろうもん

【俺の一行チップス】 Nginx で固定レスポンスを返す (ことを Go の testing パッケージで検証する)

やりたいこと

前回, Nginx で特定のパスにおいて固定のレスポンス (ステータスコード, ボディ) を返す為の設定についてメモったけど, 今回は, これを検証するにあたって Go の testing パッケージでテストコードを書いて検証したお話を少し.

inokara.hateblo.jp

諸注意

動作確認環境は以下の通り.

$ nginx -V
nginx version: nginx/1.15.10
built by gcc 6.3.0 20170516 (Debian 6.3.0-18+deb9u1)
built with OpenSSL 1.1.0j  20 Nov 2018
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-g -O2 -fdebug-prefix-map=/data/builder/debuild/nginx-1.15.10/debian/debuild-base/nginx-1.15.10=. -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie'

$ go version
go version go1.13.6 linux/amd64

やったこと

Nginx の設定

前回の記事を参考にして, こんな感じで設定を書いて /etc/nginx/conf.d/ 以下におくようにした.

server {
    listen 80;
    server_name localhost;
    server_tokens off;

    location /healthcheck {
        access_log off;
    }

    location ~ ^/(foo/*|bar/*|baz/*)/ {
        default_type text/plan;
        return 400 'Bad Request!!!';
    }
}

上記の場合, /foo/xxxxx/bar/xxxxx 等にアクセスした場合, レスポンスコード 400Bad Request!!! というボディを返す! (はず)

Go コードによるテスト

以下にプッシュしております.

github.com

コアとなる部分は以下の箇所.

func runTests(urls []string, t *testing.T) {
    for _, url := range urls {
        t.Run("URL: "+url, func(t *testing.T) {
            // Build Request
            req, _ := http.NewRequest("GET", url, nil)
            // Execute Request
            res, err := executeRequest(req)
            if err != nil {
                t.Fatalf("http.Get: %v", err)
            }
            defer res.Body.Close()

            // Display Test Result
            testResults(res, t)
        })
    }
}

func executeRequest(req *http.Request) (*http.Response, error) {
(略)
}

http.NewRequest でリクエスト型のオブジェクトを生成して, 自分で作った executeRequest 関数に投げています. 例えば, リクエストヘッダに何かヘッダ情報を追加したい場合には, 以下のように書きます.

req.Header.Set("Content-Type", "application/json")

また, 本記事では詳しく触れませんが, リダイレクトの動作検証を行いたい場合, 自分はリダイレクト先まで転送されるかよりも, ステータスコード301 または 302 が返却されるか, Location ヘッダにリダイレクト先の URL が設定されているかを検証したかったので以下のように書きました.

func executeRequest(req *http.Request) (*http.Response, error) {
    client := new(http.Client)
    // Disable redirect following
    client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
        return http.ErrUseLastResponse
    }

(略)

func testRedirectsResults(res *http.Response, target string, t *testing.T) {
    // ステータスコードが 301 で返却されることを確認
    if res.StatusCode != 301 {
        t.Errorf("got %d, want %d", res.StatusCode, 301)
    }

    // レスポンスヘッダの Location に指定した target が定義されていることを確認 
    if res.Header.Get("Location") != target {
        t.Errorf("got %s, want %s", res.Header.Get("Location"), target)
    }
}

上記のように リダイレクトに追従しないコードを書いているのがミソです.

話はだいぶん脱線してしまったけど, 検証を CircleCI で回した結果は下図の通り.

f:id:inokara:20200125092007p:plain

いい感じ.

以上

Go の testing パッケージで Nginx 設定を検証してみた. testing パッケージをはじめ, http パッケージについてもかなり奥深いけど, Bash で動作確認コードを書く感覚で書くことが出来たのので満足. ちゃんとテストコードを書くと以後の変更等も安心して大胆な変更にも対応出来るので良い!

参考

golang.org

qiita.com

(完)