233 lines
7.4 KiB
Go
233 lines
7.4 KiB
Go
package transport
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
func TestFetchBodyIfChangedPrefersETagAndTreats304AsUnchanged(t *testing.T) {
|
|
t.Helper()
|
|
|
|
var call int
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
call++
|
|
switch call {
|
|
case 1:
|
|
if got := r.Header.Get("If-None-Match"); got != "" {
|
|
t.Fatalf("first request If-None-Match = %q, want empty", got)
|
|
}
|
|
if got := r.Header.Get("If-Modified-Since"); got != "" {
|
|
t.Fatalf("first request If-Modified-Since = %q, want empty", got)
|
|
}
|
|
w.Header().Set("ETag", `"v1"`)
|
|
w.Header().Set("Last-Modified", "Mon, 02 Jan 2006 15:04:05 GMT")
|
|
_, _ = w.Write([]byte(`{"ok":true}`))
|
|
case 2:
|
|
if got := r.Header.Get("If-None-Match"); got != `"v1"` {
|
|
t.Fatalf("second request If-None-Match = %q, want %q", got, `"v1"`)
|
|
}
|
|
if got := r.Header.Get("If-Modified-Since"); got != "" {
|
|
t.Fatalf("second request If-Modified-Since = %q, want empty when ETag is cached", got)
|
|
}
|
|
w.WriteHeader(http.StatusNotModified)
|
|
default:
|
|
t.Fatalf("unexpected call count %d", call)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
validators := HTTPValidators{}
|
|
body, changed, next, err := FetchBodyIfChanged(context.Background(), srv.Client(), srv.URL, "test-agent", "application/json", true, validators)
|
|
if err != nil {
|
|
t.Fatalf("first FetchBodyIfChanged() error = %v", err)
|
|
}
|
|
if !changed {
|
|
t.Fatalf("first FetchBodyIfChanged() changed = false, want true")
|
|
}
|
|
if got := string(body); got != `{"ok":true}` {
|
|
t.Fatalf("first FetchBodyIfChanged() body = %q", got)
|
|
}
|
|
if got := next.ETag; got != `"v1"` {
|
|
t.Fatalf("cached ETag = %q, want %q", got, `"v1"`)
|
|
}
|
|
if got := next.LastModified; got != "Mon, 02 Jan 2006 15:04:05 GMT" {
|
|
t.Fatalf("cached Last-Modified = %q", got)
|
|
}
|
|
|
|
body, changed, next, err = FetchBodyIfChanged(context.Background(), srv.Client(), srv.URL, "test-agent", "application/json", true, next)
|
|
if err != nil {
|
|
t.Fatalf("second FetchBodyIfChanged() error = %v", err)
|
|
}
|
|
if changed {
|
|
t.Fatalf("second FetchBodyIfChanged() changed = true, want false")
|
|
}
|
|
if body != nil {
|
|
t.Fatalf("second FetchBodyIfChanged() body = %q, want nil", string(body))
|
|
}
|
|
if got := next.ETag; got != `"v1"` {
|
|
t.Fatalf("cached ETag after 304 = %q, want %q", got, `"v1"`)
|
|
}
|
|
}
|
|
|
|
func TestFetchBodyIfChangedFallsBackToIfModifiedSince(t *testing.T) {
|
|
t.Helper()
|
|
|
|
var call int
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
call++
|
|
switch call {
|
|
case 1:
|
|
w.Header().Set("Last-Modified", "Tue, 03 Jan 2006 15:04:05 GMT")
|
|
_, _ = w.Write([]byte(`first`))
|
|
case 2:
|
|
if got := r.Header.Get("If-None-Match"); got != "" {
|
|
t.Fatalf("second request If-None-Match = %q, want empty", got)
|
|
}
|
|
if got := r.Header.Get("If-Modified-Since"); got != "Tue, 03 Jan 2006 15:04:05 GMT" {
|
|
t.Fatalf("second request If-Modified-Since = %q", got)
|
|
}
|
|
w.WriteHeader(http.StatusNotModified)
|
|
default:
|
|
t.Fatalf("unexpected call count %d", call)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
_, changed, validators, err := FetchBodyIfChanged(context.Background(), srv.Client(), srv.URL, "test-agent", "", true, HTTPValidators{})
|
|
if err != nil {
|
|
t.Fatalf("first FetchBodyIfChanged() error = %v", err)
|
|
}
|
|
if !changed {
|
|
t.Fatalf("first FetchBodyIfChanged() changed = false, want true")
|
|
}
|
|
if got := validators.LastModified; got != "Tue, 03 Jan 2006 15:04:05 GMT" {
|
|
t.Fatalf("cached Last-Modified = %q", got)
|
|
}
|
|
|
|
_, changed, _, err = FetchBodyIfChanged(context.Background(), srv.Client(), srv.URL, "test-agent", "", true, validators)
|
|
if err != nil {
|
|
t.Fatalf("second FetchBodyIfChanged() error = %v", err)
|
|
}
|
|
if changed {
|
|
t.Fatalf("second FetchBodyIfChanged() changed = true, want false")
|
|
}
|
|
}
|
|
|
|
func TestFetchBodyIfChangedClearsValidatorsOn200WithoutValidators(t *testing.T) {
|
|
t.Helper()
|
|
|
|
var call int
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
call++
|
|
switch call {
|
|
case 1:
|
|
w.Header().Set("ETag", `"v1"`)
|
|
_, _ = w.Write([]byte(`first`))
|
|
case 2:
|
|
if got := r.Header.Get("If-None-Match"); got != `"v1"` {
|
|
t.Fatalf("second request If-None-Match = %q", got)
|
|
}
|
|
_, _ = w.Write([]byte(`second`))
|
|
case 3:
|
|
if got := r.Header.Get("If-None-Match"); got != "" {
|
|
t.Fatalf("third request If-None-Match = %q, want empty", got)
|
|
}
|
|
if got := r.Header.Get("If-Modified-Since"); got != "" {
|
|
t.Fatalf("third request If-Modified-Since = %q, want empty", got)
|
|
}
|
|
_, _ = w.Write([]byte(`third`))
|
|
default:
|
|
t.Fatalf("unexpected call count %d", call)
|
|
}
|
|
}))
|
|
defer srv.Close()
|
|
|
|
_, _, validators, err := FetchBodyIfChanged(context.Background(), srv.Client(), srv.URL, "test-agent", "", true, HTTPValidators{})
|
|
if err != nil {
|
|
t.Fatalf("first FetchBodyIfChanged() error = %v", err)
|
|
}
|
|
_, _, validators, err = FetchBodyIfChanged(context.Background(), srv.Client(), srv.URL, "test-agent", "", true, validators)
|
|
if err != nil {
|
|
t.Fatalf("second FetchBodyIfChanged() error = %v", err)
|
|
}
|
|
if validators.ETag != "" || validators.LastModified != "" {
|
|
t.Fatalf("validators after 200 without validators = %+v, want cleared", validators)
|
|
}
|
|
_, _, _, err = FetchBodyIfChanged(context.Background(), srv.Client(), srv.URL, "test-agent", "", true, validators)
|
|
if err != nil {
|
|
t.Fatalf("third FetchBodyIfChanged() error = %v", err)
|
|
}
|
|
}
|
|
|
|
func TestFetchBodyIfChangedConditionalDisabledSkipsConditionalHeaders(t *testing.T) {
|
|
t.Helper()
|
|
|
|
var calls int
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
calls++
|
|
if got := r.Header.Get("If-None-Match"); got != "" {
|
|
t.Fatalf("request If-None-Match = %q, want empty", got)
|
|
}
|
|
if got := r.Header.Get("If-Modified-Since"); got != "" {
|
|
t.Fatalf("request If-Modified-Since = %q, want empty", got)
|
|
}
|
|
_, _ = w.Write([]byte(`body`))
|
|
}))
|
|
defer srv.Close()
|
|
|
|
validators := HTTPValidators{ETag: `"v1"`, LastModified: "Wed, 04 Jan 2006 15:04:05 GMT"}
|
|
_, changed, next, err := FetchBodyIfChanged(context.Background(), srv.Client(), srv.URL, "test-agent", "", false, validators)
|
|
if err != nil {
|
|
t.Fatalf("FetchBodyIfChanged() error = %v", err)
|
|
}
|
|
if !changed {
|
|
t.Fatalf("FetchBodyIfChanged() changed = false, want true")
|
|
}
|
|
if next != validators {
|
|
t.Fatalf("validators changed when conditional disabled: got %+v want %+v", next, validators)
|
|
}
|
|
if calls != 1 {
|
|
t.Fatalf("calls = %d, want 1", calls)
|
|
}
|
|
}
|
|
|
|
func TestFetchBodyIfChangedAllowsEmpty304ButRejectsEmpty200(t *testing.T) {
|
|
t.Helper()
|
|
|
|
notModified := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusNotModified)
|
|
}))
|
|
defer notModified.Close()
|
|
|
|
_, changed, _, err := FetchBodyIfChanged(
|
|
context.Background(),
|
|
notModified.Client(),
|
|
notModified.URL,
|
|
"test-agent",
|
|
"",
|
|
true,
|
|
HTTPValidators{ETag: `"v1"`},
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("304 FetchBodyIfChanged() error = %v", err)
|
|
}
|
|
if changed {
|
|
t.Fatalf("304 FetchBodyIfChanged() changed = true, want false")
|
|
}
|
|
|
|
emptyBody := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer emptyBody.Close()
|
|
|
|
_, _, _, err = FetchBodyIfChanged(context.Background(), emptyBody.Client(), emptyBody.URL, "test-agent", "", true, HTTPValidators{})
|
|
if err == nil {
|
|
t.Fatalf("empty 200 FetchBodyIfChanged() error = nil, want error")
|
|
}
|
|
if err.Error() != "empty response body" {
|
|
t.Fatalf("empty 200 FetchBodyIfChanged() error = %q", err)
|
|
}
|
|
}
|