boulder/test/load-generator/acme/directory_test.go

187 lines
5.3 KiB
Go

package acme
import (
"fmt"
"net"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"github.com/letsencrypt/boulder/test"
)
// Path constants for test cases and mockDirectoryServer handlers.
const (
wrongStatusCodePath = "/dir-wrong-status"
invalidJSONPath = "/dir-bad-json"
missingEndpointPath = "/dir-missing-endpoint"
invalidEndpointURLPath = "/dir-invalid-endpoint"
validDirectoryPath = "/dir-valid"
invalidMetaDirectoryPath = "/dir-valid-meta-invalid"
invalidMetaDirectoryToSPath = "/dir-valid-meta-valid-tos-invalid"
)
// mockDirectoryServer is an httptest.Server that returns mock data for ACME
// directory GET requests based on the requested path.
type mockDirectoryServer struct {
*httptest.Server
}
// newMockDirectoryServer creates a mockDirectoryServer that returns mock data
// based on the requested path. The returned server will not be started
// automatically.
func newMockDirectoryServer() *mockDirectoryServer {
m := http.NewServeMux()
m.HandleFunc(wrongStatusCodePath, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusUnavailableForLegalReasons)
})
m.HandleFunc(invalidJSONPath, func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, `{`)
})
m.HandleFunc(missingEndpointPath, func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, `{}`)
})
m.HandleFunc(invalidEndpointURLPath, func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, `{
"newAccount": "",
"newNonce": "ht\ntp://bad-scheme",
"newOrder": "",
"revokeCert": ""
}`)
})
m.HandleFunc(invalidMetaDirectoryPath, func(w http.ResponseWriter, r *http.Request) {
noMetaDir := `{
"keyChange": "https://localhost:14000/rollover-account-key",
"newAccount": "https://localhost:14000/sign-me-up",
"newNonce": "https://localhost:14000/nonce-plz",
"newOrder": "https://localhost:14000/order-plz",
"revokeCert": "https://localhost:14000/revoke-cert"
}`
fmt.Fprint(w, noMetaDir)
})
m.HandleFunc(invalidMetaDirectoryToSPath, func(w http.ResponseWriter, r *http.Request) {
noToSDir := `{
"keyChange": "https://localhost:14000/rollover-account-key",
"meta": {
"chaos": "reigns"
},
"newAccount": "https://localhost:14000/sign-me-up",
"newNonce": "https://localhost:14000/nonce-plz",
"newOrder": "https://localhost:14000/order-plz",
"revokeCert": "https://localhost:14000/revoke-cert"
}`
fmt.Fprint(w, noToSDir)
})
m.HandleFunc(validDirectoryPath, func(w http.ResponseWriter, r *http.Request) {
validDir := `{
"keyChange": "https://localhost:14000/rollover-account-key",
"meta": {
"termsOfService": "data:text/plain,Do%20what%20thou%20wilt"
},
"newAccount": "https://localhost:14000/sign-me-up",
"newNonce": "https://localhost:14000/nonce-plz",
"newOrder": "https://localhost:14000/order-plz",
"revokeCert": "https://localhost:14000/revoke-cert"
}`
fmt.Fprint(w, validDir)
})
srv := &mockDirectoryServer{
Server: httptest.NewUnstartedServer(m),
}
return srv
}
// TestNew tests that creating a new Client and populating the endpoint map
// works correctly.
func TestNew(t *testing.T) {
srv := newMockDirectoryServer()
srv.Start()
defer srv.Close()
srvUrl, _ := url.Parse(srv.URL)
_, port, _ := net.SplitHostPort(srvUrl.Host)
testURL := func(path string) string {
return fmt.Sprintf("http://localhost:%s%s", port, path)
}
testCases := []struct {
Name string
DirectoryURL string
ExpectedError string
}{
{
Name: "empty directory URL",
ExpectedError: ErrEmptyDirectory.Error(),
},
{
Name: "invalid directory URL",
DirectoryURL: "http://" + string([]byte{0x1, 0x7F}),
ExpectedError: ErrInvalidDirectoryURL.Error(),
},
{
Name: "unreachable directory URL",
DirectoryURL: "http://localhost:1987",
ExpectedError: "connect: connection refused",
},
{
Name: "wrong directory HTTP status code",
DirectoryURL: testURL(wrongStatusCodePath),
ExpectedError: ErrInvalidDirectoryHTTPCode.Error(),
},
{
Name: "invalid directory JSON",
DirectoryURL: testURL(invalidJSONPath),
ExpectedError: ErrInvalidDirectoryJSON.Error(),
},
{
Name: "directory JSON missing required endpoint",
DirectoryURL: testURL(missingEndpointPath),
ExpectedError: ErrMissingEndpoint{endpoint: NewNonceEndpoint}.Error(),
},
{
Name: "directory JSON with invalid endpoint URL",
DirectoryURL: testURL(invalidEndpointURLPath),
ExpectedError: ErrInvalidEndpointURL{
endpoint: NewNonceEndpoint,
value: "ht\ntp://bad-scheme",
}.Error(),
},
{
Name: "directory JSON missing meta key",
DirectoryURL: testURL(invalidMetaDirectoryPath),
ExpectedError: ErrInvalidDirectoryMeta.Error(),
},
{
Name: "directory JSON missing meta TermsOfService key",
DirectoryURL: testURL(invalidMetaDirectoryToSPath),
ExpectedError: ErrInvalidTermsOfService.Error(),
},
{
Name: "valid directory",
DirectoryURL: testURL(validDirectoryPath),
},
}
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
_, err := NewDirectory(tc.DirectoryURL)
if err == nil && tc.ExpectedError != "" {
t.Errorf("expected error %q got nil", tc.ExpectedError)
} else if err != nil {
test.AssertContains(t, err.Error(), tc.ExpectedError)
}
})
}
}