From 4335459972daa20e069e8d4d796302e42fffba85 Mon Sep 17 00:00:00 2001 From: George Bolo Date: Fri, 7 Dec 2018 07:27:55 -0500 Subject: [PATCH] closes #18 adding unit tests for backend (#30) --- Makefile | 13 +- README.md | 17 ++ backend/aws_test.go | 191 +++++++++++++++++++ backend/backend.go | 2 +- backend/common_test.go | 27 +++ backend/config.go | 15 -- backend/config_test.go | 21 ++ backend/handlers.go | 3 +- backend/handlers_test.go | 68 +++++++ backend/instancedetails_test.go | 31 +++ backend/logger.go | 2 +- backend/logger_test.go | 28 +++ backend/router_test.go | 29 +++ backend/server_test.go | 120 ++++++++++++ backend/version_test.go | 11 ++ testdata/tls/ca_int.pem | 18 ++ testdata/tls/ca_root.pem | 18 ++ testdata/tls/server_power-toggle-chain.pem | 54 ++++++ testdata/tls/server_power-toggle-key.pem | 6 + testdata/tls/server_power-toggle-key.pk8.pem | 6 + testdata/tls/server_power-toggle.pem | 18 ++ 21 files changed, 677 insertions(+), 21 deletions(-) create mode 100644 backend/aws_test.go create mode 100644 backend/common_test.go create mode 100644 backend/config_test.go create mode 100644 backend/handlers_test.go create mode 100644 backend/instancedetails_test.go create mode 100644 backend/logger_test.go create mode 100644 backend/router_test.go create mode 100644 backend/server_test.go create mode 100644 backend/version_test.go create mode 100644 testdata/tls/ca_int.pem create mode 100644 testdata/tls/ca_root.pem create mode 100644 testdata/tls/server_power-toggle-chain.pem create mode 100644 testdata/tls/server_power-toggle-key.pem create mode 100644 testdata/tls/server_power-toggle-key.pk8.pem create mode 100644 testdata/tls/server_power-toggle.pem diff --git a/Makefile b/Makefile index a8398ae..cbbc03d 100644 --- a/Makefile +++ b/Makefile @@ -15,13 +15,13 @@ Q = $(if $(filter 1,$V),,@) M = $(shell printf "\033[34;1m▶\033[0m") .PHONY: all -all: fmt dep $(BIN) frontend ; $(info $(M) building executable...) @ ## Build program binary +all: fmt dep $(BIN) frontend ; $(info $(M) building executable...) @ ## Build main binary $Q $(GO) build \ -ldflags '-X main.Version=$(VERSION) -X main.BuildDate=$(DATE) -X main.CommitSHA=$(COMMIT_SHA)' \ -o $(BIN)/$(PACKAGE) .PHONY: docker -docker: clean ; $(info $(M) building docker image...) @ ## Build docker imaage +docker: clean ; $(info $(M) building docker image...) @ ## Build docker image $Q docker build -t gbolo/$(PACKAGE):$(VERSION) . .PHONY: frontend @@ -41,6 +41,9 @@ $(BIN)/%: | $(BIN) ; $(info $(M) building $(REPOSITORY)...) DEP = $(BIN)/dep $(BIN)/dep: REPOSITORY=github.com/golang/dep/cmd/dep +GOIMPORTS = $(BIN)/goimports +$(BIN)/goimports: REPOSITORY=golang.org/x/tools/cmd/goimports + .PHONY: dep dep: | $(DEP) ; $(info $(M) running dep...) @ ## Run dep ensure to fetch dependencies $Q $(DEP) ensure -v @@ -49,8 +52,12 @@ dep: | $(DEP) ; $(info $(M) running dep...) @ ## Run dep ensure to fetch depende fmt: ; $(info $(M) running gofmt...) @ ## Run gofmt on all source files $Q $(GO) fmt ./... +.PHONY: goimports +goimports: | $(GOIMPORTS) ; $(info $(M) running goimports...) @ ## Run goimports on backend source files + $Q $(GOIMPORTS) -w backend/ + .PHONY: test -test: ; $(info $(M) running go test...) @ ## Run go test +test: ; $(info $(M) running go test...) @ ## Run go unit tests $Q $(GO) test -v -cover $(TESTPKGS) # Misc diff --git a/README.md b/README.md index f2e6b4a..ae12c95 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,23 @@ If you prefer to use `docker` for building (which I recommend), you can build th make docker ``` + +### Make Targets + +``` +$ make help + +all Build main binary +docker Build docker image +frontend Build frontend +dep Run dep ensure to fetch dependencies +fmt Run gofmt on all source files +goimports Run goimports on backend source files +test Run go unit tests +clean Cleanup everything +``` + + ### API Documentation For further details on an API endpoint (including example responses), click on the endpoint's name. diff --git a/backend/aws_test.go b/backend/aws_test.go new file mode 100644 index 0000000..2378f80 --- /dev/null +++ b/backend/aws_test.go @@ -0,0 +1,191 @@ +package backend + +import ( + "os" + "testing" +) + +func TestCheckInstanceType(t *testing.T) { + // init the test config + os.Setenv("POWER_TOGGLE_AWS_IGNORE_INSTANCE_TYPES", "c5d.18xlarge c5d.9xlarge") + ConfigInit("../testdata/sampleconfig/power-toggle-config.yaml", false) + + testCases := map[string]bool{ + "c5d.18xlarge": false, + "c5d.9xlarge": false, + "c5.18xlarge": true, + "t2.medium": true, + } + + for input, expectedResult := range testCases { + if checkInstanceType(input) != expectedResult { + t.Errorf("input(%s) != expectedResult(%v)", input, expectedResult) + } + } +} + +func TestValidateEnvName(t *testing.T) { + // init the test config + os.Setenv("POWER_TOGGLE_AWS_IGNORE_ENVIRONMENTS", "ignoredEnv1 ignoredEnv2") + ConfigInit("../testdata/sampleconfig/power-toggle-config.yaml", false) + + testCases := map[string]bool{ + "ignoredEnv1": false, + "ignoredEnv2": false, + "env3": true, + "env4": true, + } + + for input, expectedResult := range testCases { + if validateEnvName(input) != expectedResult { + t.Errorf("input(%s) != expectedResult(%v)", input, expectedResult) + } + } +} + +func TestGetEnvironmentById(t *testing.T) { + if err := resetMockData(); err != nil { + t.Fatalf("mockRefreshTable failed: %v", err) + } + envId := "356f6265efcc" + + if len(cachedTable) == 0 { + t.Fatalf("cachedTable is of 0 size!") + } + + env, found := getEnvironmentById(envId) + if !found { + t.Errorf("unable to retrieve test env %s", envId) + } + if env.Name != "mockenv1" && len(env.Instances) < 1 { + t.Errorf("unexpected env retrieved") + } + if _, found := getEnvironmentById("incorrectEnvId"); found { + t.Errorf("getEnvironmentById reported found for an invalid env id") + } +} + +func TestUpdateEnvDetails(t *testing.T) { + if err := resetMockData(); err != nil { + t.Fatalf("mockRefreshTable failed: %v", err) + } + + // ensure our mocked json initial state is correct + startingInstanceState := cachedTable[1].Instances[1].State + if startingInstanceState != "stopped" { + t.Error("our moc json has unexpected init values. Has it changed?") + } + startingEnvState := cachedTable[1].State + if startingEnvState != "stopped" { + t.Error("our moc json has unexpected init values. Has it changed?") + } + + // set an instance in this env to running, we should see env state change + cachedTable[1].Instances[1].State = "running" + updateEnvDetails() + if cachedTable[1].State != ENV_MIXED { + t.Errorf("unexpected env state: got %s expected %s", cachedTable[1].State, ENV_MIXED) + } + + // set an instance in this env to pending, we should see env state change + cachedTable[1].Instances[1].State = "pending" + updateEnvDetails() + if cachedTable[1].State != ENV_CHANGING { + t.Errorf("unexpected env state: got %s expected %s", cachedTable[1].State, ENV_CHANGING) + } + + // set all instances to running, we should see env state change + for i, _ := range cachedTable[1].Instances { + cachedTable[1].Instances[i].State = "running" + } + updateEnvDetails() + if cachedTable[1].State != ENV_RUNNING { + t.Errorf("unexpected env state: got %s expected %s", cachedTable[1].State, ENV_RUNNING) + } + + // set all instances to stopped, we should see env state change + for i, _ := range cachedTable[1].Instances { + cachedTable[1].Instances[i].State = "stopped" + } + updateEnvDetails() + if cachedTable[1].State != ENV_DOWN { + t.Errorf("unexpected env state: got %s expected %s", cachedTable[1].State, ENV_DOWN) + } + + // ensure that our counts are functioning correctly + currentTotalCpuCount := cachedTable[1].TotalVCPU + cachedTable[1].Instances[1].VCPU++ + updateEnvDetails() + if (currentTotalCpuCount + 1) != cachedTable[1].TotalVCPU { + t.Errorf("Total vCPU count has an unexpected value: %d", cachedTable[1].TotalVCPU) + } +} + +func TestToggleInstance(t *testing.T) { + if err := resetMockData(); err != nil { + t.Fatalf("mockRefreshTable failed: %v", err) + } + + // test toggleInstance + for desiredState, actualState := range map[string]string{ + "stop": "stopped", + "start": "running", + } { + _, err := toggleInstance(cachedTable[1].Instances[1].Id, desiredState) + if err != nil || cachedTable[1].Instances[1].State != actualState { + t.Errorf("go %s but wanted %s. Err: %v", cachedTable[1].Instances[1].State, actualState, err) + } + } +} + +func TestGetAWSInstanceId(t *testing.T) { + if err := resetMockData(); err != nil { + t.Fatalf("mockRefreshTable failed: %v", err) + } + + if getAWSInstanceId(cachedTable[1].Instances[1].Id) != cachedTable[1].Instances[1].InstanceId { + t.Errorf("getAWSInstanceId is not returning correct id") + } +} + +func TestEnvStartStop(t *testing.T) { + if err := resetMockData(); err != nil { + t.Fatalf("mockRefreshTable failed: %v", err) + } + envId := "4f9f1afb29f1" + + _, err := startupEnv(envId) + if err != nil { + t.Errorf("startupEnv return and error: %v", err) + } + updateEnvDetails() + state, _ := getEnvState(envId) + if state != "running" { + t.Errorf("test env is not in running state: %s", state) + } + + _, err = shutdownEnv(envId) + if err != nil { + t.Errorf("startupEnv return and error: %v", err) + } + updateEnvDetails() + state, _ = getEnvState(envId) + if state != "stopped" { + t.Errorf("test env is not in stopped state: %s", state) + } +} + +func resetMockData() error { + MOCK_ENABLED = true + cachedTable = cachedTable[:0] + return mockRefreshTable() +} + +func getEnvState(envId string) (string, bool) { + env, found := getEnvironmentById(envId) + if !found { + return "", found + } else { + return env.State, found + } +} diff --git a/backend/backend.go b/backend/backend.go index 93b2dc0..b53f7d9 100644 --- a/backend/backend.go +++ b/backend/backend.go @@ -45,4 +45,4 @@ func StartBackendDeamon(cfgFile string) { // }, nil //} // -//cfg.EndpointResolver = aws.EndpointResolverFunc(mockAwsResolver) \ No newline at end of file +//cfg.EndpointResolver = aws.EndpointResolverFunc(mockAwsResolver) diff --git a/backend/common_test.go b/backend/common_test.go new file mode 100644 index 0000000..a0d0d6d --- /dev/null +++ b/backend/common_test.go @@ -0,0 +1,27 @@ +package backend + +import "testing" + +func TestComputeId(t *testing.T) { + + // test cases for case sensitivity + testStringCase := map[string]string{ + "testString": "956265657d0b", + "teststring": "b8473b86d4c2", + } + + // test case for multiple strings + testMultipleInputs1 := "teststring1" + testMultipleInputs2 := "teststring2" + testMultipleInputsExpectedId := "ab8675367360" + + for input, expectedResult := range testStringCase { + if ComputeId(input) != expectedResult { + t.Errorf("%s != %s - got: %s", input, expectedResult, ComputeId(input)) + } + } + + if ComputeId(testMultipleInputs1, testMultipleInputs2) != testMultipleInputsExpectedId { + t.Error("testMultipleInputsExpectedId did not match") + } +} diff --git a/backend/config.go b/backend/config.go index 5ebf0e7..476be17 100644 --- a/backend/config.go +++ b/backend/config.go @@ -1,8 +1,6 @@ package backend import ( - "fmt" - "os" "strings" "github.com/spf13/viper" @@ -54,19 +52,6 @@ func initViper(cfgFile string) { viper.SetConfigName("power-toggle-config") viper.AddConfigPath("./") - // if env _TESTING=true then set a path to sampleconfig - if viper.GetBool("testing") { - testConfig := "./testdata/sampleconfig" - - goPath := os.Getenv("GOPATH") - if goPath != "" { - testConfig = fmt.Sprintf("%s/src/github.com/gbolo/aws-power-toggle/testdata/sampleconfig", goPath) - } - - log.Debugf("dev mode enabled: %s", testConfig) - viper.AddConfigPath(testConfig) - } - // if the user provides a config file in a flag, lets use it if cfgFile != "" { viper.SetConfigFile(cfgFile) diff --git a/backend/config_test.go b/backend/config_test.go new file mode 100644 index 0000000..2488741 --- /dev/null +++ b/backend/config_test.go @@ -0,0 +1,21 @@ +package backend + +import ( + "fmt" + "os" + "testing" +) + +func TestConfigInit(t *testing.T) { + maxInstancesToShutdown = -1 + + testConfig := "../testdata/sampleconfig" + goPath := os.Getenv("GOPATH") + if goPath != "" { + testConfig = fmt.Sprintf("%s/src/github.com/gbolo/aws-power-toggle/testdata/sampleconfig", goPath) + } + ConfigInit(testConfig, true) + if maxInstancesToShutdown == -1 { + t.Error("ConfigInit did not change maxInstancesToShutdown") + } +} diff --git a/backend/handlers.go b/backend/handlers.go index b91a897..4d27222 100644 --- a/backend/handlers.go +++ b/backend/handlers.go @@ -2,8 +2,9 @@ package backend import ( "fmt" - "github.com/gorilla/mux" "net/http" + + "github.com/gorilla/mux" ) // returns version information diff --git a/backend/handlers_test.go b/backend/handlers_test.go new file mode 100644 index 0000000..c026e90 --- /dev/null +++ b/backend/handlers_test.go @@ -0,0 +1,68 @@ +// handlers_test.go +package backend + +import ( + "net/http" + "net/http/httptest" + "testing" +) + +func TestHttpHandlers(t *testing.T) { + + // discard logs + loggingInit("INFO") + + // prepare data + if err := resetMockData(); err != nil { + t.Fatalf("mockRefreshTable failed: %v", err) + } + + type req struct { + method string + endpoint string + status int + } + + // ONLY check status code for now... + // TODO: add checks for response body + for _, testReq := range []req{ + {"GET", "/", http.StatusNotFound}, + {"GET", getEndpoint("version"), http.StatusOK}, + {"POST", getEndpoint("refresh"), http.StatusOK}, + {"GET", getEndpoint("env/summary"), http.StatusOK}, + {"GET", getEndpoint("env/details"), http.StatusOK}, + {"GET", getEndpoint("env/4f9f1afb29f1/summary"), http.StatusOK}, + {"GET", getEndpoint("env/4f9f1afb29f1/details"), http.StatusOK}, + {"GET", getEndpoint("env/invalid/summary"), http.StatusNotFound}, + {"GET", getEndpoint("env/invalid/details"), http.StatusNotFound}, + {"POST", getEndpoint("env/4f9f1afb29f1/start"), http.StatusOK}, + {"POST", getEndpoint("env/4f9f1afb29f1/stop"), http.StatusOK}, + {"POST", getEndpoint("env/invalid/start"), http.StatusInternalServerError}, + {"POST", getEndpoint("env/invalid/stop"), http.StatusInternalServerError}, + {"POST", getEndpoint("instance/906d663b6ecd/start"), http.StatusOK}, + {"POST", getEndpoint("instance/906d663b6ecd/stop"), http.StatusOK}, + {"POST", getEndpoint("instance/invalid/start"), http.StatusInternalServerError}, + {"POST", getEndpoint("instance/invalid/stop"), http.StatusInternalServerError}, + } { + + // Create a request to pass to our handler. We don't have any query parameters for now, so we'll + // pass 'nil' as the third parameter. + req, err := http.NewRequest(testReq.method, testReq.endpoint, nil) + if err != nil { + t.Fatal(err) + } + + // We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response. + rr := httptest.NewRecorder() + + // since we use gorilla mux for our handers, we need to pass the request over to that + mux := newRouter() + mux.ServeHTTP(rr, req) + + // Check the status code is what we expect. + if status := rr.Code; status != testReq.status { + t.Errorf("handler returned wrong status code for endpoint: %s: got %v want %v", + testReq.endpoint, status, testReq.status) + } + } +} diff --git a/backend/instancedetails_test.go b/backend/instancedetails_test.go new file mode 100644 index 0000000..f36d0ab --- /dev/null +++ b/backend/instancedetails_test.go @@ -0,0 +1,31 @@ +package backend + +import ( + "testing" +) + +func TestAwsInstanceDetails(t *testing.T) { + + // this should NEVER return an error + // if it does then the json data may be incorrect + if err := loadAwsInstanceDetailsJson(); err != nil { + t.Error("loadAwsInstanceDetailsJson returned an error") + } + + // check if instanceTypeDetailsCache was updated properly + if len(instanceTypeDetailsCache) < 1 { + t.Error("instanceTypeDetailsCache has not been updated") + } + + // test that we can get instance type details + for iType, expected := range map[string]bool{ + "t2.medium": true, + "c5d.4xlarge": true, + "p99.invalid": false, + } { + _, got := getInstanceTypeDetails(iType) + if expected != got { + t.Errorf("for type: %s got %v, expected %v", iType, got, expected) + } + } +} diff --git a/backend/logger.go b/backend/logger.go index 34a363a..ce326ac 100644 --- a/backend/logger.go +++ b/backend/logger.go @@ -3,7 +3,7 @@ package backend import ( "os" - "github.com/op/go-logging" + logging "github.com/op/go-logging" ) // logFormat is an RFC 5424 style log format diff --git a/backend/logger_test.go b/backend/logger_test.go new file mode 100644 index 0000000..3d155ad --- /dev/null +++ b/backend/logger_test.go @@ -0,0 +1,28 @@ +package backend + +import ( + "strings" + "testing" + + logging "github.com/op/go-logging" +) + +func TestLoggingInit(t *testing.T) { + + // test log level + for _, setLevel := range []string{"ERROR", "INFO", "warning", "WARNING"} { + loggingInit(setLevel) + appliedLevel := logging.GetLevel("log_backend_f").String() + if appliedLevel != strings.ToUpper(setLevel) { + t.Errorf("loging level was not applied properly: %s != %s", appliedLevel, setLevel) + } + } + // test invalid log level. Should get set to ERROR + loggingInit("INVALID") + if logging.GetLevel("log_backend_f").String() != "ERROR" { + t.Errorf( + "expected an invalid log level to result in ERROR but got: %s", + logging.GetLevel("log_backend_f").String(), + ) + } +} diff --git a/backend/router_test.go b/backend/router_test.go new file mode 100644 index 0000000..e74964b --- /dev/null +++ b/backend/router_test.go @@ -0,0 +1,29 @@ +package backend + +import ( + "testing" +) + +// TestNewRouter checks that all defined routes are loaded properly +func TestNewRouter(t *testing.T) { + // check that routes has entries + if len(routes) == 0 { + t.Error("routes are missing!") + } + + // validate that we load all routes into the router + router := newRouter() + for _, route := range routes { + if r := router.GetRoute(route.Name); r == nil { + log.Errorf("route with name %s was not loaded correctly", route.Name) + } + } +} + +// ensure that the correct route endpoints are being returned +func TestGetEndpoint(t *testing.T) { + expectedResult := "/api/v1/testroute" + if getEndpoint("testroute") != expectedResult { + t.Errorf("api endpoint naming logic has changed: %s != %s", getEndpoint("testroute"), expectedResult) + } +} diff --git a/backend/server_test.go b/backend/server_test.go new file mode 100644 index 0000000..4bac0cc --- /dev/null +++ b/backend/server_test.go @@ -0,0 +1,120 @@ +package backend + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "os" + "testing" + + "github.com/gorilla/mux" +) + +const ( + // these constants may need to change when testdata content changes + caRootCertSubjectCN = "linuxctl ECC Root Certification Authority (Test)" + caIntCertSubjectCN = "linuxctl ECC Intermediate Certification Authority (Test)" + serverCertSubjectCN = "power-toggle" + serverCertFileLocation = "../testdata/tls/server_power-toggle-chain.pem" + serverKeyFileLocation = "../testdata/tls/server_power-toggle-key.pem" +) + +// helper function to create TLS config while handling error +func createTestTLSConfig(t *testing.T) *tls.Config { + testTLSConfig, err := configureTLS() + if err != nil { + t.Fatalf("we got an unexpected error while calling createTLSConfig: %s", err) + } + + return &testTLSConfig +} + +// TestTLSConfig should test the behaviour of configureTLS +func TestTLSConfig(t *testing.T) { + + // configure TLS options + os.Setenv("POWER_TOGGLE_SERVER_TLS_ENABLED", "true") + os.Setenv("POWER_TOGGLE_SERVER_TLS_CERT_CHAIN", serverCertFileLocation) + os.Setenv("POWER_TOGGLE_SERVER_TLS_PRIVATE_KEY", serverKeyFileLocation) + testTLSConfig := createTestTLSConfig(t) + + if testTLSConfig.MinVersion != tlsMinVersion { + t.Error("MinVersion is not set to expected value") + } + if testTLSConfig.InsecureSkipVerify { + t.Error("InsecureSkipVerify is not set to false") + } + if !testTLSConfig.PreferServerCipherSuites { + t.Errorf("PreferServerCipherSuites is not set to true") + } + if len(testTLSConfig.CipherSuites) == 0 { + t.Error("CipherSuites is not set") + } + if len(testTLSConfig.CurvePreferences) == 0 { + t.Error("CurvePreferences is not set") + } + for i := range testTLSConfig.CipherSuites { + if testTLSConfig.CipherSuites[i] != tlsCiphers[i] { + t.Error("discrepancy found in CipherSuites") + } + } + for i := range testTLSConfig.CurvePreferences { + if testTLSConfig.CurvePreferences[i] != tlsCurvePreferences[i] { + t.Error("discrepancy found in CurvePreferences") + } + } + + // test that the expected certs are loaded + if len(testTLSConfig.Certificates) == 0 { + t.Fatal("certificate file was not loaded") + } else if len(testTLSConfig.Certificates) > 1 { + t.Fatalf("more than 1 certficate file was loaded: %v", len(testTLSConfig.Certificates)) + } + + // our test chain cert file should have 3 certs (server > intermediate ca > root ca) + if len(testTLSConfig.Certificates[0].Certificate) != 3 { + t.Fatalf("expected to have 3 x509 certificates loaded, but found: %v", len(testTLSConfig.Certificates[0].Certificate)) + } + + // confirm the correct 3 certificates are loaded (we use subjects here, instead of SKI) + for _, cert := range testTLSConfig.Certificates[0].Certificate { + cert, err := x509.ParseCertificate(cert) + if err != nil { + t.Fatalf("failed to parse certficate: %v", err) + } + + switch { + case bytes.Contains(cert.RawSubject, []byte(caRootCertSubjectCN)): + t.Log("found root ca cert cn") + case bytes.Contains(cert.RawSubject, []byte(caIntCertSubjectCN)): + t.Log("found intermediate ca cert cn") + case bytes.Contains(cert.RawSubject, []byte(serverCertSubjectCN)): + t.Log("found server cert cn") + default: + t.Fatal("expected CN not found in certificate subject") + } + } + + // confirm that we can disable TLS + os.Unsetenv("POWER_TOGGLE_SERVER_TLS_ENABLED") + testTLSConfig = createTestTLSConfig(t) + if len(testTLSConfig.Certificates) != 0 { + t.Fatal("failed to disable TLS") + } +} + +func TestHTTPConfig(t *testing.T) { + httpServerConfig := configureHttpServer(&mux.Router{}) + + if httpServerConfig.WriteTimeout != httpWriteTimeout { + t.Error("WriteTimeout is not set to correct value") + } + if httpServerConfig.ReadTimeout != httpReadTimeout { + t.Error("ReadTimeout is not set to correct value") + } + if httpServerConfig.IdleTimeout != httpIdleTimeout { + t.Error("IdleTimeout is not set to correct value") + } +} + +// TODO: test StartServer() somehow diff --git a/backend/version_test.go b/backend/version_test.go new file mode 100644 index 0000000..b4ab1f3 --- /dev/null +++ b/backend/version_test.go @@ -0,0 +1,11 @@ +package backend + +import "testing" + +func TestGetVersion(t *testing.T) { + + expectedResult := `{"version":"devel","git_hash":"unknown","build_date":"unknown"}` + if getVersionResponse() != expectedResult { + t.Error("version output has changed") + } +} diff --git a/testdata/tls/ca_int.pem b/testdata/tls/ca_int.pem new file mode 100644 index 0000000..5bd6ad0 --- /dev/null +++ b/testdata/tls/ca_int.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC6zCCAkygAwIBAgIUF9S5KEOeJ3Ne3OrWPwMw7VwYPP4wCgYIKoZIzj0EAwQw +gY0xCzAJBgNVBAYTAkNBMRAwDgYDVQQIEwdPbnRhcmlvMRAwDgYDVQQHEwdUb3Jv +bnRvMREwDwYDVQQKEwhsaW51eGN0bDEMMAoGA1UECxMDTGFiMTkwNwYDVQQDEzBs +aW51eGN0bCBFQ0MgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAoVGVzdCkw +HhcNMTgxMjAyMjMwMjAwWhcNMjgxMTI5MjMwMjAwWjCBlTELMAkGA1UEBhMCQ0Ex +EDAOBgNVBAgTB09udGFyaW8xEDAOBgNVBAcTB1Rvcm9udG8xETAPBgNVBAoTCGxp +bnV4Y3RsMQwwCgYDVQQLEwNMYWIxQTA/BgNVBAMTOGxpbnV4Y3RsIEVDQyBJbnRl +cm1lZGlhdGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKFRlc3QpMHYwEAYHKoZI +zj0CAQYFK4EEACIDYgAEaK7on/Zez0ZXDubWkqUGL7RzZ7PC4IZdKDU+CgScOlRN +PBPD9TYa/e1yINX4ShE8kB+dB5X7sIxu8v8P/IGsVZEwIetyoArQ3VW/0GHbvek1 +DLXQSZU4St8fKNR8TJhPo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQU0ybw3IWv7o+akt5FVohl+0SReJkwHwYDVR0jBBgwFoAU +Mpq0e/GGi3t3e2t18TxotnjOlXcwCgYIKoZIzj0EAwQDgYwAMIGIAkIAhT+SrjEF +NTOu9N4Pog/FydumunigFyG+0haD+4Caa8B7CcKYV+yrf5WB6g0AF18upQO9RmpX +otdwfSo6XkSMFycCQgHUbwBu6XG2k91+xIERhse7fTWZ88fQS0zoMASa06NNHP3q +FES85yjxvLwEfkrKVhHz/E35lDyIW2gR54MkRsSy2w== +-----END CERTIFICATE----- diff --git a/testdata/tls/ca_root.pem b/testdata/tls/ca_root.pem new file mode 100644 index 0000000..171c998 --- /dev/null +++ b/testdata/tls/ca_root.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC6DCCAkmgAwIBAgIUFlHlJEZTisy1ZBaujmKeUQSX/X4wCgYIKoZIzj0EAwQw +gY0xCzAJBgNVBAYTAkNBMRAwDgYDVQQIEwdPbnRhcmlvMRAwDgYDVQQHEwdUb3Jv +bnRvMREwDwYDVQQKEwhsaW51eGN0bDEMMAoGA1UECxMDTGFiMTkwNwYDVQQDEzBs +aW51eGN0bCBFQ0MgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAoVGVzdCkw +HhcNMTgxMjAyMjMwMjAwWhcNNDgxMTI0MjMwMjAwWjCBjTELMAkGA1UEBhMCQ0Ex +EDAOBgNVBAgTB09udGFyaW8xEDAOBgNVBAcTB1Rvcm9udG8xETAPBgNVBAoTCGxp +bnV4Y3RsMQwwCgYDVQQLEwNMYWIxOTA3BgNVBAMTMGxpbnV4Y3RsIEVDQyBSb290 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IChUZXN0KTCBmzAQBgcqhkjOPQIBBgUr +gQQAIwOBhgAEAfvNYQ2joZJZJ9z7UHygsPh/cCYv8UbtjsIKwGg9vFS05mIGsWD2 +ydbMM7QqBRllboOKZega6YypNaXvBQJeWmiPAPoyeq2nw+OkNO7pv2kvYedHeIJF +us/WQb3crj6FVcKAM9N7epM8xJX4uxljTy2nA1kCEI+EZFydlRdEi/DBwDiao0Iw +QDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUMpq0 +e/GGi3t3e2t18TxotnjOlXcwCgYIKoZIzj0EAwQDgYwAMIGIAkIB/z2RfqjhdlwI +cKaQmQRoEkxM/rrzIGed5I3Z4YvBB2qpIsF1QlO3JnCNvJIEKse9bkxoTh5WclRM +v3LbBQcDpP8CQgC+n32LJBukiWZVvDWZhQKg+h2UKPZUww7WKTe9DI2gt0UHe313 +G5p5f9lrGPctjlVuHCOUjvhfB1aI6TsE0/jzJQ== +-----END CERTIFICATE----- diff --git a/testdata/tls/server_power-toggle-chain.pem b/testdata/tls/server_power-toggle-chain.pem new file mode 100644 index 0000000..e2f36d0 --- /dev/null +++ b/testdata/tls/server_power-toggle-chain.pem @@ -0,0 +1,54 @@ +-----BEGIN CERTIFICATE----- +MIIC4DCCAmagAwIBAgIUJrb/FzMq92+7HQZLOXhxT15cnJ4wCgYIKoZIzj0EAwMw +gZUxCzAJBgNVBAYTAkNBMRAwDgYDVQQIEwdPbnRhcmlvMRAwDgYDVQQHEwdUb3Jv +bnRvMREwDwYDVQQKEwhsaW51eGN0bDEMMAoGA1UECxMDTGFiMUEwPwYDVQQDEzhs +aW51eGN0bCBFQ0MgSW50ZXJtZWRpYXRlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IChUZXN0KTAeFw0xODEyMDIyMzAzMDBaFw0yMzEyMDEyMzAzMDBaMGkxCzAJBgNV +BAYTAkNBMRAwDgYDVQQIEwdPbnRhcmlvMRAwDgYDVQQHEwdUb3JvbnRvMREwDwYD +VQQKEwhsaW51eGN0bDEMMAoGA1UECxMDTGFiMRUwEwYDVQQDEwxwb3dlci10b2dn +bGUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAROSOR7Z7i0edPvj05344JCVFN8BBvV +Qtn/Hw6MQBXvHvIDxhtq9AJ+TwbktmBau18ftpqTgHxw04fhE7WESYfliUlNk4gg +7+D6exsxdoXD7J3x+aZ0aC3vtbOgaTV2AbKjgaEwgZ4wDgYDVR0PAQH/BAQDAgWg +MBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFOrF +Vf+8rAvHXaFEf4ss5LhHL1fkMB8GA1UdIwQYMBaAFNMm8NyFr+6PmpLeRVaIZftE +kXiZMCkGA1UdEQQiMCCCHnBvd2VyLXRvZ2dsZS5kZW1vLmxpbnV4Y3RsLmNvbTAK +BggqhkjOPQQDAwNoADBlAjB7PrrJVpuqOrKghL7tq2pHZJ7W8i3/PX+nQDHR2KiR +vcIm7pq2qE8PbAp7Pxpm+SECMQDc6WFrxnZEqrcyCKq7cPuIMbxyYtE4aTSGKgPs +fGTfTe2UPGx5hyr2MUcjt+8396o= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIC6zCCAkygAwIBAgIUF9S5KEOeJ3Ne3OrWPwMw7VwYPP4wCgYIKoZIzj0EAwQw +gY0xCzAJBgNVBAYTAkNBMRAwDgYDVQQIEwdPbnRhcmlvMRAwDgYDVQQHEwdUb3Jv +bnRvMREwDwYDVQQKEwhsaW51eGN0bDEMMAoGA1UECxMDTGFiMTkwNwYDVQQDEzBs +aW51eGN0bCBFQ0MgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAoVGVzdCkw +HhcNMTgxMjAyMjMwMjAwWhcNMjgxMTI5MjMwMjAwWjCBlTELMAkGA1UEBhMCQ0Ex +EDAOBgNVBAgTB09udGFyaW8xEDAOBgNVBAcTB1Rvcm9udG8xETAPBgNVBAoTCGxp +bnV4Y3RsMQwwCgYDVQQLEwNMYWIxQTA/BgNVBAMTOGxpbnV4Y3RsIEVDQyBJbnRl +cm1lZGlhdGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKFRlc3QpMHYwEAYHKoZI +zj0CAQYFK4EEACIDYgAEaK7on/Zez0ZXDubWkqUGL7RzZ7PC4IZdKDU+CgScOlRN +PBPD9TYa/e1yINX4ShE8kB+dB5X7sIxu8v8P/IGsVZEwIetyoArQ3VW/0GHbvek1 +DLXQSZU4St8fKNR8TJhPo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQU0ybw3IWv7o+akt5FVohl+0SReJkwHwYDVR0jBBgwFoAU +Mpq0e/GGi3t3e2t18TxotnjOlXcwCgYIKoZIzj0EAwQDgYwAMIGIAkIAhT+SrjEF +NTOu9N4Pog/FydumunigFyG+0haD+4Caa8B7CcKYV+yrf5WB6g0AF18upQO9RmpX +otdwfSo6XkSMFycCQgHUbwBu6XG2k91+xIERhse7fTWZ88fQS0zoMASa06NNHP3q +FES85yjxvLwEfkrKVhHz/E35lDyIW2gR54MkRsSy2w== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIC6DCCAkmgAwIBAgIUFlHlJEZTisy1ZBaujmKeUQSX/X4wCgYIKoZIzj0EAwQw +gY0xCzAJBgNVBAYTAkNBMRAwDgYDVQQIEwdPbnRhcmlvMRAwDgYDVQQHEwdUb3Jv +bnRvMREwDwYDVQQKEwhsaW51eGN0bDEMMAoGA1UECxMDTGFiMTkwNwYDVQQDEzBs +aW51eGN0bCBFQ0MgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAoVGVzdCkw +HhcNMTgxMjAyMjMwMjAwWhcNNDgxMTI0MjMwMjAwWjCBjTELMAkGA1UEBhMCQ0Ex +EDAOBgNVBAgTB09udGFyaW8xEDAOBgNVBAcTB1Rvcm9udG8xETAPBgNVBAoTCGxp +bnV4Y3RsMQwwCgYDVQQLEwNMYWIxOTA3BgNVBAMTMGxpbnV4Y3RsIEVDQyBSb290 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IChUZXN0KTCBmzAQBgcqhkjOPQIBBgUr +gQQAIwOBhgAEAfvNYQ2joZJZJ9z7UHygsPh/cCYv8UbtjsIKwGg9vFS05mIGsWD2 +ydbMM7QqBRllboOKZega6YypNaXvBQJeWmiPAPoyeq2nw+OkNO7pv2kvYedHeIJF +us/WQb3crj6FVcKAM9N7epM8xJX4uxljTy2nA1kCEI+EZFydlRdEi/DBwDiao0Iw +QDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUMpq0 +e/GGi3t3e2t18TxotnjOlXcwCgYIKoZIzj0EAwQDgYwAMIGIAkIB/z2RfqjhdlwI +cKaQmQRoEkxM/rrzIGed5I3Z4YvBB2qpIsF1QlO3JnCNvJIEKse9bkxoTh5WclRM +v3LbBQcDpP8CQgC+n32LJBukiWZVvDWZhQKg+h2UKPZUww7WKTe9DI2gt0UHe313 +G5p5f9lrGPctjlVuHCOUjvhfB1aI6TsE0/jzJQ== +-----END CERTIFICATE----- diff --git a/testdata/tls/server_power-toggle-key.pem b/testdata/tls/server_power-toggle-key.pem new file mode 100644 index 0000000..5893ffb --- /dev/null +++ b/testdata/tls/server_power-toggle-key.pem @@ -0,0 +1,6 @@ +-----BEGIN EC PRIVATE KEY----- +MIGkAgEBBDB5E7iVTEUbDBhHdluZAWOApuAvLcKLBf2CyqXQVQW+XJeOZflCJ0jT +sTZhyHDqK+OgBwYFK4EEACKhZANiAAROSOR7Z7i0edPvj05344JCVFN8BBvVQtn/ +Hw6MQBXvHvIDxhtq9AJ+TwbktmBau18ftpqTgHxw04fhE7WESYfliUlNk4gg7+D6 +exsxdoXD7J3x+aZ0aC3vtbOgaTV2AbI= +-----END EC PRIVATE KEY----- diff --git a/testdata/tls/server_power-toggle-key.pk8.pem b/testdata/tls/server_power-toggle-key.pk8.pem new file mode 100644 index 0000000..34414cf --- /dev/null +++ b/testdata/tls/server_power-toggle-key.pk8.pem @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDB5E7iVTEUbDBhHdluZ +AWOApuAvLcKLBf2CyqXQVQW+XJeOZflCJ0jTsTZhyHDqK+OhZANiAAROSOR7Z7i0 +edPvj05344JCVFN8BBvVQtn/Hw6MQBXvHvIDxhtq9AJ+TwbktmBau18ftpqTgHxw +04fhE7WESYfliUlNk4gg7+D6exsxdoXD7J3x+aZ0aC3vtbOgaTV2AbI= +-----END PRIVATE KEY----- diff --git a/testdata/tls/server_power-toggle.pem b/testdata/tls/server_power-toggle.pem new file mode 100644 index 0000000..1a73b8f --- /dev/null +++ b/testdata/tls/server_power-toggle.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC4DCCAmagAwIBAgIUJrb/FzMq92+7HQZLOXhxT15cnJ4wCgYIKoZIzj0EAwMw +gZUxCzAJBgNVBAYTAkNBMRAwDgYDVQQIEwdPbnRhcmlvMRAwDgYDVQQHEwdUb3Jv +bnRvMREwDwYDVQQKEwhsaW51eGN0bDEMMAoGA1UECxMDTGFiMUEwPwYDVQQDEzhs +aW51eGN0bCBFQ0MgSW50ZXJtZWRpYXRlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IChUZXN0KTAeFw0xODEyMDIyMzAzMDBaFw0yMzEyMDEyMzAzMDBaMGkxCzAJBgNV +BAYTAkNBMRAwDgYDVQQIEwdPbnRhcmlvMRAwDgYDVQQHEwdUb3JvbnRvMREwDwYD +VQQKEwhsaW51eGN0bDEMMAoGA1UECxMDTGFiMRUwEwYDVQQDEwxwb3dlci10b2dn +bGUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAROSOR7Z7i0edPvj05344JCVFN8BBvV +Qtn/Hw6MQBXvHvIDxhtq9AJ+TwbktmBau18ftpqTgHxw04fhE7WESYfliUlNk4gg +7+D6exsxdoXD7J3x+aZ0aC3vtbOgaTV2AbKjgaEwgZ4wDgYDVR0PAQH/BAQDAgWg +MBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFOrF +Vf+8rAvHXaFEf4ss5LhHL1fkMB8GA1UdIwQYMBaAFNMm8NyFr+6PmpLeRVaIZftE +kXiZMCkGA1UdEQQiMCCCHnBvd2VyLXRvZ2dsZS5kZW1vLmxpbnV4Y3RsLmNvbTAK +BggqhkjOPQQDAwNoADBlAjB7PrrJVpuqOrKghL7tq2pHZJ7W8i3/PX+nQDHR2KiR +vcIm7pq2qE8PbAp7Pxpm+SECMQDc6WFrxnZEqrcyCKq7cPuIMbxyYtE4aTSGKgPs +fGTfTe2UPGx5hyr2MUcjt+8396o= +-----END CERTIFICATE-----