| package http |
| |
| import ( |
| "bytes" |
| "fmt" |
| "io" |
| "net/http" |
| "net/http/httptest" |
| "net/url" |
| "reflect" |
| "testing" |
| |
| "github.com/hashicorp/go-retryablehttp" |
| "github.com/hashicorp/terraform/internal/states/remote" |
| ) |
| |
| func TestHTTPClient_impl(t *testing.T) { |
| var _ remote.Client = new(httpClient) |
| var _ remote.ClientLocker = new(httpClient) |
| } |
| |
| func TestHTTPClient(t *testing.T) { |
| handler := new(testHTTPHandler) |
| ts := httptest.NewServer(http.HandlerFunc(handler.Handle)) |
| defer ts.Close() |
| |
| url, err := url.Parse(ts.URL) |
| if err != nil { |
| t.Fatalf("Parse: %s", err) |
| } |
| |
| // Test basic get/update |
| client := &httpClient{URL: url, Client: retryablehttp.NewClient()} |
| remote.TestClient(t, client) |
| |
| // test just a single PUT |
| p := &httpClient{ |
| URL: url, |
| UpdateMethod: "PUT", |
| Client: retryablehttp.NewClient(), |
| } |
| remote.TestClient(t, p) |
| |
| // Test locking and alternative UpdateMethod |
| a := &httpClient{ |
| URL: url, |
| UpdateMethod: "PUT", |
| LockURL: url, |
| LockMethod: "LOCK", |
| UnlockURL: url, |
| UnlockMethod: "UNLOCK", |
| Client: retryablehttp.NewClient(), |
| } |
| b := &httpClient{ |
| URL: url, |
| UpdateMethod: "PUT", |
| LockURL: url, |
| LockMethod: "LOCK", |
| UnlockURL: url, |
| UnlockMethod: "UNLOCK", |
| Client: retryablehttp.NewClient(), |
| } |
| remote.TestRemoteLocks(t, a, b) |
| |
| // test a WebDAV-ish backend |
| davhandler := new(testHTTPHandler) |
| ts = httptest.NewServer(http.HandlerFunc(davhandler.HandleWebDAV)) |
| defer ts.Close() |
| |
| url, err = url.Parse(ts.URL) |
| client = &httpClient{ |
| URL: url, |
| UpdateMethod: "PUT", |
| Client: retryablehttp.NewClient(), |
| } |
| if err != nil { |
| t.Fatalf("Parse: %s", err) |
| } |
| |
| remote.TestClient(t, client) // first time through: 201 |
| remote.TestClient(t, client) // second time, with identical data: 204 |
| |
| // test a broken backend |
| brokenHandler := new(testBrokenHTTPHandler) |
| brokenHandler.handler = new(testHTTPHandler) |
| ts = httptest.NewServer(http.HandlerFunc(brokenHandler.Handle)) |
| defer ts.Close() |
| |
| url, err = url.Parse(ts.URL) |
| if err != nil { |
| t.Fatalf("Parse: %s", err) |
| } |
| client = &httpClient{URL: url, Client: retryablehttp.NewClient()} |
| remote.TestClient(t, client) |
| } |
| |
| type testHTTPHandler struct { |
| Data []byte |
| Locked bool |
| } |
| |
| func (h *testHTTPHandler) Handle(w http.ResponseWriter, r *http.Request) { |
| switch r.Method { |
| case "GET": |
| w.Write(h.Data) |
| case "PUT": |
| buf := new(bytes.Buffer) |
| if _, err := io.Copy(buf, r.Body); err != nil { |
| w.WriteHeader(500) |
| } |
| w.WriteHeader(201) |
| h.Data = buf.Bytes() |
| case "POST": |
| buf := new(bytes.Buffer) |
| if _, err := io.Copy(buf, r.Body); err != nil { |
| w.WriteHeader(500) |
| } |
| h.Data = buf.Bytes() |
| case "LOCK": |
| if h.Locked { |
| w.WriteHeader(423) |
| } else { |
| h.Locked = true |
| } |
| case "UNLOCK": |
| h.Locked = false |
| case "DELETE": |
| h.Data = nil |
| w.WriteHeader(200) |
| default: |
| w.WriteHeader(500) |
| w.Write([]byte(fmt.Sprintf("Unknown method: %s", r.Method))) |
| } |
| } |
| |
| // mod_dav-ish behavior |
| func (h *testHTTPHandler) HandleWebDAV(w http.ResponseWriter, r *http.Request) { |
| switch r.Method { |
| case "GET": |
| w.Write(h.Data) |
| case "PUT": |
| buf := new(bytes.Buffer) |
| if _, err := io.Copy(buf, r.Body); err != nil { |
| w.WriteHeader(500) |
| } |
| if reflect.DeepEqual(h.Data, buf.Bytes()) { |
| h.Data = buf.Bytes() |
| w.WriteHeader(204) |
| } else { |
| h.Data = buf.Bytes() |
| w.WriteHeader(201) |
| } |
| case "DELETE": |
| h.Data = nil |
| w.WriteHeader(200) |
| default: |
| w.WriteHeader(500) |
| w.Write([]byte(fmt.Sprintf("Unknown method: %s", r.Method))) |
| } |
| } |
| |
| type testBrokenHTTPHandler struct { |
| lastRequestWasBroken bool |
| handler *testHTTPHandler |
| } |
| |
| func (h *testBrokenHTTPHandler) Handle(w http.ResponseWriter, r *http.Request) { |
| if h.lastRequestWasBroken { |
| h.lastRequestWasBroken = false |
| h.handler.Handle(w, r) |
| } else { |
| h.lastRequestWasBroken = true |
| w.WriteHeader(500) |
| } |
| } |