terraform/state/remote/http_test.go

214 lines
5.4 KiB
Go

package remote
import (
"bytes"
"fmt"
"io"
"net/http"
"net/http/httptest"
"net/url"
"reflect"
"testing"
"github.com/hashicorp/go-cleanhttp"
)
func TestHTTPClient_impl(t *testing.T) {
var _ Client = new(HTTPClient)
var _ 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("err: %s", err)
}
// Test basic get/update
client := &HTTPClient{URL: url, Client: cleanhttp.DefaultClient()}
testClient(t, client)
// test just a single PUT
p := &HTTPClient{
URL: url,
UpdateMethod: "PUT",
Client: cleanhttp.DefaultClient(),
}
testClient(t, p)
// Test locking and alternative UpdateMethod
a := &HTTPClient{
URL: url,
UpdateMethod: "PUT",
LockURL: url,
LockMethod: "LOCK",
UnlockURL: url,
UnlockMethod: "UNLOCK",
Client: cleanhttp.DefaultClient(),
}
b := &HTTPClient{
URL: url,
UpdateMethod: "PUT",
LockURL: url,
LockMethod: "LOCK",
UnlockURL: url,
UnlockMethod: "UNLOCK",
Client: cleanhttp.DefaultClient(),
}
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)
c := &HTTPClient{
URL: url,
UpdateMethod: "PUT",
Client: cleanhttp.DefaultClient(),
}
testClient(t, c) // first time through: 201
testClient(t, c) // second time, with identical data: 204
}
func assertError(t *testing.T, err error, expected string) {
if err == nil {
t.Fatalf("Expected empty config to err")
} else if err.Error() != expected {
t.Fatalf("Expected err.Error() to be \"%s\", got \"%s\"", expected, err.Error())
}
}
func TestHTTPClientFactory(t *testing.T) {
// missing address
_, err := httpFactory(map[string]string{})
assertError(t, err, "missing 'address' configuration")
// defaults
conf := map[string]string{
"address": "http://127.0.0.1:8888/foo",
}
c, err := httpFactory(conf)
client, _ := c.(*HTTPClient)
if client == nil || err != nil {
t.Fatal("Unexpected failure, address")
}
if client.URL.String() != conf["address"] {
t.Fatalf("Expected address \"%s\", got \"%s\"", conf["address"], client.URL.String())
}
if client.UpdateMethod != "POST" {
t.Fatalf("Expected update_method \"%s\", got \"%s\"", "POST", client.UpdateMethod)
}
if client.LockURL != nil || client.LockMethod != "LOCK" {
t.Fatal("Unexpected lock_address or lock_method")
}
if client.UnlockURL != nil || client.UnlockMethod != "UNLOCK" {
t.Fatal("Unexpected unlock_address or unlock_method")
}
if client.Username != "" || client.Password != "" {
t.Fatal("Unexpected username or password")
}
// custom
conf = map[string]string{
"address": "http://127.0.0.1:8888/foo",
"update_method": "BLAH",
"lock_address": "http://127.0.0.1:8888/bar",
"lock_method": "BLIP",
"unlock_address": "http://127.0.0.1:8888/baz",
"unlock_method": "BLOOP",
"username": "user",
"password": "pass",
}
c, err = httpFactory(conf)
client, _ = c.(*HTTPClient)
if client == nil || err != nil {
t.Fatal("Unexpected failure, update_method")
}
if client.UpdateMethod != "BLAH" {
t.Fatalf("Expected update_method \"%s\", got \"%s\"", "BLAH", client.UpdateMethod)
}
if client.LockURL.String() != conf["lock_address"] || client.LockMethod != "BLIP" {
t.Fatalf("Unexpected lock_address \"%s\" vs \"%s\" or lock_method \"%s\" vs \"%s\"", client.LockURL.String(),
conf["lock_address"], client.LockMethod, conf["lock_method"])
}
if client.UnlockURL.String() != conf["unlock_address"] || client.UnlockMethod != "BLOOP" {
t.Fatalf("Unexpected unlock_address \"%s\" vs \"%s\" or unlock_method \"%s\" vs \"%s\"", client.UnlockURL.String(),
conf["unlock_address"], client.UnlockMethod, conf["unlock_method"])
}
if client.Username != "user" || client.Password != "pass" {
t.Fatalf("Unexpected username \"%s\" vs \"%s\" or password \"%s\" vs \"%s\"", client.Username, conf["username"],
client.Password, conf["password"])
}
}
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)))
}
}