From 29bfcc8ffd7b1bd6bd03e976257e9480feeb4143 Mon Sep 17 00:00:00 2001 From: qibobo Date: Thu, 22 Aug 2019 16:38:30 +0800 Subject: [PATCH 01/16] add integration tests for golang apiserver --- src/integration/components.go | 111 ++++- src/integration/helpers.go | 185 ++++++++ ...ation_api_broker_graceful_shutdown_test.go | 22 +- .../integration_api_eventgenerator_test.go | 60 +-- .../integration_api_metricscollector_test.go | 81 +--- .../integration_api_scalingengine_test.go | 60 +-- .../integration_api_scheduler_test.go | 226 ++++----- .../integration_broker_api_test.go | 62 +-- ...tegration_golangapi_eventgenerator_test.go | 265 +++++++++++ ...gration_golangapi_metricscollector_test.go | 362 +++++++++++++++ ...ntegration_golangapi_scalingengine_test.go | 293 ++++++++++++ .../integration_golangapi_scheduler_test.go | 431 ++++++++++++++++++ .../integration_operator_others_test.go | 8 +- src/integration/integration_suite_test.go | 126 +++-- 14 files changed, 1867 insertions(+), 425 deletions(-) create mode 100644 src/integration/helpers.go create mode 100644 src/integration/integration_golangapi_eventgenerator_test.go create mode 100644 src/integration/integration_golangapi_metricscollector_test.go create mode 100644 src/integration/integration_golangapi_scalingengine_test.go create mode 100644 src/integration/integration_golangapi_scheduler_test.go diff --git a/src/integration/components.go b/src/integration/components.go index c31200099..9f9add065 100644 --- a/src/integration/components.go +++ b/src/integration/components.go @@ -3,14 +3,17 @@ package integration import ( "autoscaler/cf" "autoscaler/db" - egConfig "autoscaler/eventgenerator/config" "autoscaler/helpers" + "autoscaler/models" + + apiConfig "autoscaler/api/config" + egConfig "autoscaler/eventgenerator/config" mcConfig "autoscaler/metricscollector/config" mgConfig "autoscaler/metricsgateway/config" msConfig "autoscaler/metricsserver/config" - "autoscaler/models" opConfig "autoscaler/operator/config" seConfig "autoscaler/scalingengine/config" + "encoding/json" "fmt" "io/ioutil" @@ -28,7 +31,9 @@ import ( const ( APIServer = "apiServer" APIPublicServer = "APIPublicServer" + GolangAPIServer = "golangApiServer" ServiceBroker = "serviceBroker" + GolangServiceBroker = "golangServiceBroker" ServiceBrokerInternal = "serviceBrokerInternal" Scheduler = "scheduler" MetricsCollector = "metricsCollector" @@ -45,6 +50,11 @@ var serviceCatalogPath string = "../../servicebroker/config/catalog.json" var schemaValidationPath string = "../../servicebroker/config/catalog.schema.json" var apiServerInfoFilePath string = "../../api/config/info.json" +var golangAPIInfoFilePath string = "../autoscaler/api/exampleconfig/catalog-example.json" +var golangSchemaValidationPath string = "../autoscaler/api/schemas/catalog.schema.json" +var golangApiServerPolicySchemaPath string = "../autoscaler/api/policyvalidator/policy_json.schema.json" +var golangServiceCatalogPath string = "../../servicebroker/config/catalog.json" + type Executables map[string]string type Ports map[string]int @@ -157,7 +167,21 @@ func (components *Components) ApiServer(confPath string, argv ...string) *ginkgo }, }) } +func (components *Components) GolangAPIServer(confPath string, argv ...string) *ginkgomon.Runner { + return ginkgomon.New(ginkgomon.Config{ + Name: GolangAPIServer, + AnsiColorCode: "33m", + StartCheck: `"api.started"`, + StartCheckTimeout: 20 * time.Second, + Command: exec.Command( + components.Executables[GolangAPIServer], + append([]string{ + "-c", confPath, + }, argv...)..., + ), + }) +} func (components *Components) Scheduler(confPath string, argv ...string) *ginkgomon.Runner { return ginkgomon.New(ginkgomon.Config{ Name: Scheduler, @@ -400,6 +424,89 @@ func (components *Components) PrepareApiServerConfig(port int, publicPort int, s return cfgFile.Name() } +func (components *Components) PrepareGolangApiServerConfig(dbURI string, publicApiPort int, brokerPort int, cfApi string, skipSSLValidation bool, cacheTTL int, schedulerUri string, scalingEngineUri string, metricsCollectorUri string, eventGeneratorUri string, metricsForwarderUri string, useBuildInMode bool, httpClientTimeout time.Duration, tmpDir string) string { + + cfg := apiConfig.Config{ + Logging: helpers.LoggingConfig{ + Level: LOGLEVEL, + }, + PublicApiServer: apiConfig.ServerConfig{ + Port: publicApiPort, + TLS: models.TLSCerts{ + KeyFile: filepath.Join(testCertDir, "api.key"), + CertFile: filepath.Join(testCertDir, "api.crt"), + CACertFile: filepath.Join(testCertDir, "autoscaler-ca.crt"), + }, + }, + BrokerServer: apiConfig.ServerConfig{ + Port: brokerPort, + TLS: models.TLSCerts{ + KeyFile: filepath.Join(testCertDir, "servicebroker.key"), + CertFile: filepath.Join(testCertDir, "servicebroker.crt"), + CACertFile: filepath.Join(testCertDir, "autoscaler-ca.crt"), + }, + }, + DB: apiConfig.DBConfig{ + PolicyDB: db.DatabaseConfig{ + URL: dbURI, + }, + BindingDB: db.DatabaseConfig{ + URL: dbURI, + }, + }, + BrokerUsername: brokerUserName, + BrokerPassword: brokerPassword, + CatalogPath: golangServiceCatalogPath, + CatalogSchemaPath: golangSchemaValidationPath, + DashboardRedirectURI: "", + PolicySchemaPath: golangApiServerPolicySchemaPath, + Scheduler: apiConfig.SchedulerConfig{ + SchedulerURL: schedulerUri, + TLSClientCerts: models.TLSCerts{ + KeyFile: filepath.Join(testCertDir, "scheduler.key"), + CertFile: filepath.Join(testCertDir, "scheduler.crt"), + CACertFile: filepath.Join(testCertDir, "autoscaler-ca.crt"), + }, + }, + ScalingEngine: apiConfig.ScalingEngineConfig{ + ScalingEngineUrl: scalingEngineUri, + TLSClientCerts: models.TLSCerts{ + KeyFile: filepath.Join(testCertDir, "scalingengine.key"), + CertFile: filepath.Join(testCertDir, "scalingengine.crt"), + CACertFile: filepath.Join(testCertDir, "autoscaler-ca.crt"), + }, + }, + MetricsCollector: apiConfig.MetricsCollectorConfig{ + MetricsCollectorUrl: metricsCollectorUri, + TLSClientCerts: models.TLSCerts{ + KeyFile: filepath.Join(testCertDir, "metricscollector.key"), + CertFile: filepath.Join(testCertDir, "metricscollector.crt"), + CACertFile: filepath.Join(testCertDir, "autoscaler-ca.crt"), + }, + }, + EventGenerator: apiConfig.EventGeneratorConfig{ + EventGeneratorUrl: eventGeneratorUri, + TLSClientCerts: models.TLSCerts{ + KeyFile: filepath.Join(testCertDir, "eventgenerator.key"), + CertFile: filepath.Join(testCertDir, "eventgenerator.crt"), + CACertFile: filepath.Join(testCertDir, "autoscaler-ca.crt"), + }, + }, + CF: cf.CFConfig{ + API: cfApi, + ClientID: "admin", + Secret: "admin", + }, + UseBuildInMode: useBuildInMode, + InfoFilePath: golangAPIInfoFilePath, + MetricsForwarder: apiConfig.MetricsForwarderConfig{ + MetricsForwarderUrl: metricsForwarderUri, + }, + } + + return writeYmlConfig(tmpDir, GolangAPIServer, &cfg) +} + func (components *Components) PrepareSchedulerConfig(dbUri string, scalingEngineUri string, tmpDir string, httpClientTimeout time.Duration) string { dbUrl, _ := url.Parse(dbUri) scheme := dbUrl.Scheme diff --git a/src/integration/helpers.go b/src/integration/helpers.go new file mode 100644 index 000000000..710007f8d --- /dev/null +++ b/src/integration/helpers.go @@ -0,0 +1,185 @@ +package integration + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/url" + + "autoscaler/models" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +type AppInstanceMetricResult struct { + TotalResults int `json:"total_results"` + TotalPages int `json:"total_pages"` + Page int `json:"page"` + PrevUrl string `json:"prev_url"` + NextUrl string `json:"next_url"` + Resources []models.AppInstanceMetric `json:"resources"` +} + +func getAppAggregatedMetricUrl(appId string, metricType string, parameteters map[string]string, pageNo int) string { + return fmt.Sprintf("/v1/apps/%s/aggregated_metric_histories/%s?any=any&start-time=%s&end-time=%s&order-direction=%s&page=%d&results-per-page=%s", appId, metricType, parameteters["start-time"], parameteters["end-time"], parameteters["order-direction"], pageNo, parameteters["results-per-page"]) +} + +func compareAppAggregatedMetricResult(o1, o2 AppAggregatedMetricResult) { + Expect(o1.Page).To(Equal(o2.Page)) + Expect(o1.TotalPages).To(Equal(o2.TotalPages)) + Expect(o1.TotalResults).To(Equal(o2.TotalResults)) + Expect(o1.Resources).To(Equal(o2.Resources)) + + prevUrl1, err1 := url.Parse(o1.PrevUrl) + Expect(err1).NotTo(HaveOccurred()) + prevUrl2, err2 := url.Parse(o2.PrevUrl) + Expect(err2).NotTo(HaveOccurred()) + queries1 := prevUrl1.Query() + queries2 := prevUrl2.Query() + Expect(queries1).To(Equal(queries2)) + + nextUrl1, err1 := url.Parse(o1.NextUrl) + Expect(err1).NotTo(HaveOccurred()) + nextUrl2, err2 := url.Parse(o2.NextUrl) + Expect(err2).NotTo(HaveOccurred()) + queries1 = nextUrl1.Query() + queries2 = nextUrl2.Query() + Expect(queries1).To(Equal(queries2)) + +} +func checkAggregatedMetricResult(apiServerPort int, pathVariables []string, parameters map[string]string, result AppAggregatedMetricResult) { + var actual AppAggregatedMetricResult + resp, err := getAppAggregatedMetrics(apiServerPort, pathVariables, parameters) + defer resp.Body.Close() + Expect(err).NotTo(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusOK)) + err = json.NewDecoder(resp.Body).Decode(&actual) + Expect(err).NotTo(HaveOccurred()) + compareAppAggregatedMetricResult(actual, result) + +} + +func getInstanceMetricsUrl(appId string, metricType string, parameteters map[string]string, pageNo int) string { + return fmt.Sprintf("/v1/apps/%s/metric_histories/%s?any=any&start-time=%s&end-time=%s&order-direction=%s&page=%d&results-per-page=%s", appId, metricType, parameteters["start-time"], parameteters["end-time"], parameteters["order-direction"], pageNo, parameteters["results-per-page"]) +} + +func getInstanceMetricsUrlWithInstanceIndex(appId string, metricType string, parameteters map[string]string, pageNo int) string { + return fmt.Sprintf("/v1/apps/%s/metric_histories/%s?any=any&instance-index=%s&start-time=%s&end-time=%s&order-direction=%s&page=%d&results-per-page=%s", appId, metricType, parameteters["instance-index"], parameteters["start-time"], parameteters["end-time"], parameteters["order-direction"], pageNo, parameteters["results-per-page"]) +} + +func compareAppInstanceMetricResult(o1, o2 AppInstanceMetricResult) { + Expect(o1.Page).To(Equal(o2.Page)) + Expect(o1.TotalPages).To(Equal(o2.TotalPages)) + Expect(o1.TotalResults).To(Equal(o2.TotalResults)) + Expect(o1.Resources).To(Equal(o2.Resources)) + + prevUrl1, err1 := url.Parse(o1.PrevUrl) + Expect(err1).NotTo(HaveOccurred()) + prevUrl2, err2 := url.Parse(o2.PrevUrl) + Expect(err2).NotTo(HaveOccurred()) + queries1 := prevUrl1.Query() + queries2 := prevUrl2.Query() + Expect(queries1).To(Equal(queries2)) + + nextUrl1, err1 := url.Parse(o1.NextUrl) + Expect(err1).NotTo(HaveOccurred()) + nextUrl2, err2 := url.Parse(o2.NextUrl) + Expect(err2).NotTo(HaveOccurred()) + queries1 = nextUrl1.Query() + queries2 = nextUrl2.Query() + Expect(queries1).To(Equal(queries2)) + +} +func checkAppInstanceMetricResult(apiServerPort int, pathVariables []string, parameters map[string]string, result AppInstanceMetricResult) { + var actual AppInstanceMetricResult + resp, err := getAppInstanceMetrics(apiServerPort, pathVariables, parameters) + Expect(err).NotTo(HaveOccurred()) + defer resp.Body.Close() + Expect(err).NotTo(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusOK)) + err = json.NewDecoder(resp.Body).Decode(&actual) + Expect(err).NotTo(HaveOccurred()) + compareAppInstanceMetricResult(actual, result) + +} + +func getScalingHistoriesUrl(appId string, parameteters map[string]string, pageNo int) string { + return fmt.Sprintf("/v1/apps/%s/scaling_histories?any=any&start-time=%s&end-time=%s&order-direction=%s&page=%d&results-per-page=%s", appId, parameteters["start-time"], parameteters["end-time"], parameteters["order-direction"], pageNo, parameteters["results-per-page"]) +} + +func compareScalingHistoryResult(o1, o2 ScalingHistoryResult) { + Expect(o1.Page).To(Equal(o2.Page)) + Expect(o1.TotalPages).To(Equal(o2.TotalPages)) + Expect(o1.TotalResults).To(Equal(o2.TotalResults)) + Expect(o1.Resources).To(Equal(o2.Resources)) + + prevUrl1, err1 := url.Parse(o1.PrevUrl) + Expect(err1).NotTo(HaveOccurred()) + prevUrl2, err2 := url.Parse(o2.PrevUrl) + Expect(err2).NotTo(HaveOccurred()) + queries1 := prevUrl1.Query() + queries2 := prevUrl2.Query() + Expect(queries1).To(Equal(queries2)) + + nextUrl1, err1 := url.Parse(o1.NextUrl) + Expect(err1).NotTo(HaveOccurred()) + nextUrl2, err2 := url.Parse(o2.NextUrl) + Expect(err2).NotTo(HaveOccurred()) + queries1 = nextUrl1.Query() + queries2 = nextUrl2.Query() + Expect(queries1).To(Equal(queries2)) + +} +func checkScalingHistoryResult(apiServerPort int, pathVariables []string, parameters map[string]string, result ScalingHistoryResult) { + var actual ScalingHistoryResult + resp, err := getScalingHistories(apiServerPort, pathVariables, parameters) + defer resp.Body.Close() + Expect(err).NotTo(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusOK)) + err = json.NewDecoder(resp.Body).Decode(&actual) + Expect(err).NotTo(HaveOccurred()) + compareScalingHistoryResult(actual, result) + +} + +func doAttachPolicy(appId string, policyStr []byte, statusCode int, apiServerPort int, httpClient *http.Client) { + resp, err := attachPolicy(appId, policyStr, apiServerPort, httpClient) + Expect(err).NotTo(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(statusCode)) + resp.Body.Close() + +} +func doDetachPolicy(appId string, statusCode int, msg string, apiServerPort int, httpClient *http.Client) { + resp, err := detachPolicy(appId, apiServerPort, httpClient) + Expect(err).NotTo(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(statusCode)) + if msg != "" { + respBody, err := ioutil.ReadAll(resp.Body) + Expect(err).NotTo(HaveOccurred()) + Expect(string(respBody)).To(Equal(msg)) + } + resp.Body.Close() +} +func checkApiServerStatus(appId string, statusCode int, apiServerPort int, httpClient *http.Client) { + By("checking the API Server") + resp, err := getPolicy(appId, apiServerPort, httpClient) + Expect(err).NotTo(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(statusCode)) + resp.Body.Close() +} +func checkApiServerContent(appId string, policyStr []byte, statusCode int, port int, httpClient *http.Client) { + By("checking the API Server") + var expected map[string]interface{} + err := json.Unmarshal(policyStr, &expected) + Expect(err).NotTo(HaveOccurred()) + checkResponseContent(getPolicy, appId, statusCode, expected, port, httpClient) +} +func checkSchedulerStatus(appId string, statusCode int) { + By("checking the Scheduler") + resp, err := getSchedules(appId) + Expect(err).NotTo(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(statusCode)) + resp.Body.Close() +} diff --git a/src/integration/integration_api_broker_graceful_shutdown_test.go b/src/integration/integration_api_broker_graceful_shutdown_test.go index da4cdc20c..7f8989566 100644 --- a/src/integration/integration_api_broker_graceful_shutdown_test.go +++ b/src/integration/integration_api_broker_graceful_shutdown_test.go @@ -55,7 +55,7 @@ var _ = Describe("Integration_Api_Broker_Graceful_Shutdown", func() { fakeScheduler.AppendHandlers(ghttp.RespondWith(http.StatusOK, "successful")) policyStr := readPolicyFromFile("fakePolicyWithSchedule.json") - resp, err := attachPolicy(getRandomId(), policyStr, INTERNAL) + resp, err := attachPolicy(getRandomId(), policyStr, components.Ports[APIServer], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) resp.Body.Close() @@ -63,7 +63,7 @@ var _ = Describe("Integration_Api_Broker_Graceful_Shutdown", func() { sendSigusr2Signal(APIServer) Eventually(buffer, 5*time.Second).Should(gbytes.Say(`Received SIGUSR2 signal`)) - resp, err = attachPolicy(getRandomId(), policyStr, INTERNAL) + resp, err = attachPolicy(getRandomId(), policyStr, components.Ports[APIServer], httpClient) Expect(err).To(HaveOccurred()) Eventually(processMap[APIServer].Wait()).Should(Receive()) @@ -84,7 +84,7 @@ var _ = Describe("Integration_Api_Broker_Graceful_Shutdown", func() { go func() { defer GinkgoRecover() policyStr := readPolicyFromFile("fakePolicyWithSchedule.json") - resp, err := attachPolicy(getRandomId(), policyStr, INTERNAL) + resp, err := attachPolicy(getRandomId(), policyStr, components.Ports[APIServer], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) resp.Body.Close() @@ -119,7 +119,7 @@ var _ = Describe("Integration_Api_Broker_Graceful_Shutdown", func() { go func() { defer GinkgoRecover() policyStr := readPolicyFromFile("fakePolicyWithSchedule.json") - _, err := attachPolicy(getRandomId(), policyStr, INTERNAL) + _, err := attachPolicy(getRandomId(), policyStr, components.Ports[APIServer], httpClient) Expect(err).To(HaveOccurred()) close(done) }() @@ -158,7 +158,7 @@ var _ = Describe("Integration_Api_Broker_Graceful_Shutdown", func() { bindingId = getRandomId() appId = getRandomId() //add a service instance - resp, err := provisionServiceInstance(serviceInstanceId, orgId, spaceId) + resp, err := provisionServiceInstance(serviceInstanceId, orgId, spaceId, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) resp.Body.Close() @@ -174,7 +174,7 @@ var _ = Describe("Integration_Api_Broker_Graceful_Shutdown", func() { It("stops receiving new connections", func() { fakeApiServer.AppendHandlers(ghttp.RespondWith(http.StatusCreated, "created")) - resp, err := bindService(bindingId, appId, serviceInstanceId, schedulePolicyJson) + resp, err := bindService(bindingId, appId, serviceInstanceId, schedulePolicyJson, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) resp.Body.Close() @@ -182,10 +182,10 @@ var _ = Describe("Integration_Api_Broker_Graceful_Shutdown", func() { sendSigusr2Signal(ServiceBroker) Eventually(buffer, 5*time.Second).Should(gbytes.Say(`Received SIGUSR2 signal`)) - _, err = bindService(getRandomId(), appId, serviceInstanceId, schedulePolicyJson) + _, err = bindService(getRandomId(), appId, serviceInstanceId, schedulePolicyJson, components.Ports[ServiceBroker], httpClient) Expect(err).To(HaveOccurred()) - Eventually(processMap[ServiceBroker].Wait()).Should(Receive()) + Eventually(processMap[ServiceBroker].Wait(), 10*time.Second).Should(Receive()) Expect(runner.ExitCode()).Should(BeZero()) }) @@ -202,7 +202,7 @@ var _ = Describe("Integration_Api_Broker_Graceful_Shutdown", func() { done := make(chan struct{}) go func() { defer GinkgoRecover() - resp, err := bindService(bindingId, appId, serviceInstanceId, schedulePolicyJson) + resp, err := bindService(bindingId, appId, serviceInstanceId, schedulePolicyJson, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) resp.Body.Close() @@ -217,7 +217,7 @@ var _ = Describe("Integration_Api_Broker_Graceful_Shutdown", func() { close(ch) Eventually(done).Should(BeClosed()) - Eventually(processMap[ServiceBroker].Wait()).Should(Receive()) + Eventually(processMap[ServiceBroker].Wait(), 10*time.Second).Should(Receive()) Expect(runner.ExitCode()).Should(BeZero()) }) }) @@ -236,7 +236,7 @@ var _ = Describe("Integration_Api_Broker_Graceful_Shutdown", func() { done := make(chan struct{}) go func() { defer GinkgoRecover() - _, err := bindService(bindingId, appId, serviceInstanceId, schedulePolicyJson) + _, err := bindService(bindingId, appId, serviceInstanceId, schedulePolicyJson, components.Ports[ServiceBroker], httpClient) Expect(err).To(HaveOccurred()) close(done) }() diff --git a/src/integration/integration_api_eventgenerator_test.go b/src/integration/integration_api_eventgenerator_test.go index e38d54b47..9b6e8867d 100644 --- a/src/integration/integration_api_eventgenerator_test.go +++ b/src/integration/integration_api_eventgenerator_test.go @@ -3,14 +3,11 @@ package integration import ( "autoscaler/cf" "autoscaler/models" - "encoding/json" "fmt" "net/http" - "net/url" "strings" . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" "github.com/onsi/gomega/ghttp" ) @@ -60,7 +57,7 @@ var _ = Describe("Integration_Api_EventGenerator", func() { }) It("should error with status code 500", func() { By("check public api") - checkPublicAPIResponseContentWithParameters(getAppAggregatedMetrics, pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{}) + checkPublicAPIResponseContentWithParameters(getAppAggregatedMetrics, components.Ports[APIPublicServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{}) }) }) @@ -76,7 +73,7 @@ var _ = Describe("Integration_Api_EventGenerator", func() { }) It("should error with status code 500", func() { By("check public api") - checkPublicAPIResponseContentWithParameters(getAppAggregatedMetrics, pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{}) + checkPublicAPIResponseContentWithParameters(getAppAggregatedMetrics, components.Ports[APIPublicServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{}) }) }) Context("UAA api returns 401", func() { @@ -98,7 +95,7 @@ var _ = Describe("Integration_Api_EventGenerator", func() { }) It("should error with status code 401", func() { By("check public api") - checkPublicAPIResponseContentWithParameters(getAppAggregatedMetrics, pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{}) + checkPublicAPIResponseContentWithParameters(getAppAggregatedMetrics, components.Ports[APIPublicServer], pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{}) }) }) @@ -113,7 +110,7 @@ var _ = Describe("Integration_Api_EventGenerator", func() { }) It("should error with status code 401", func() { By("check public api") - checkPublicAPIResponseContentWithParameters(getAppAggregatedMetrics, pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{}) + checkPublicAPIResponseContentWithParameters(getAppAggregatedMetrics, components.Ports[APIPublicServer], pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{}) }) }) @@ -124,7 +121,7 @@ var _ = Describe("Integration_Api_EventGenerator", func() { It("should error with status code 500", func() { By("check public api") - checkPublicAPIResponseContentWithParameters(getAppAggregatedMetrics, pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{"error": fmt.Sprintf("connect ECONNREFUSED 127.0.0.1:%d", components.Ports[EventGenerator])}) + checkPublicAPIResponseContentWithParameters(getAppAggregatedMetrics, components.Ports[APIPublicServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{"error": fmt.Sprintf("connect ECONNREFUSED 127.0.0.1:%d", components.Ports[EventGenerator])}) }) }) @@ -190,7 +187,7 @@ var _ = Describe("Integration_Api_EventGenerator", func() { }, } By("check public api") - checkAggregatedMetricResult(pathVariables, parameters, result) + checkAggregatedMetricResult(components.Ports[APIPublicServer], pathVariables, parameters, result) By("get the 2nd page") parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "2", "results-per-page": "2"} @@ -218,7 +215,7 @@ var _ = Describe("Integration_Api_EventGenerator", func() { }, } By("check public api") - checkAggregatedMetricResult(pathVariables, parameters, result) + checkAggregatedMetricResult(components.Ports[APIPublicServer], pathVariables, parameters, result) By("get the 3rd page") parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "3", "results-per-page": "2"} @@ -238,7 +235,7 @@ var _ = Describe("Integration_Api_EventGenerator", func() { }, } By("check public api") - checkAggregatedMetricResult(pathVariables, parameters, result) + checkAggregatedMetricResult(components.Ports[APIPublicServer], pathVariables, parameters, result) By("the 4th page should be empty") parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "4", "results-per-page": "2"} @@ -250,48 +247,9 @@ var _ = Describe("Integration_Api_EventGenerator", func() { Resources: []models.AppMetric{}, } By("check public api") - checkAggregatedMetricResult(pathVariables, parameters, result) + checkAggregatedMetricResult(components.Ports[APIPublicServer], pathVariables, parameters, result) }) }) }) }) - -func getAppAggregatedMetricUrl(appId string, metricType string, parameteters map[string]string, pageNo int) string { - return fmt.Sprintf("/v1/apps/%s/aggregated_metric_histories/%s?any=any&start-time=%s&end-time=%s&order-direction=%s&page=%d&results-per-page=%s", appId, metricType, parameteters["start-time"], parameteters["end-time"], parameteters["order-direction"], pageNo, parameteters["results-per-page"]) -} - -func compareAppAggregatedMetricResult(o1, o2 AppAggregatedMetricResult) { - Expect(o1.Page).To(Equal(o2.Page)) - Expect(o1.TotalPages).To(Equal(o2.TotalPages)) - Expect(o1.TotalResults).To(Equal(o2.TotalResults)) - Expect(o1.Resources).To(Equal(o2.Resources)) - - prevUrl1, err1 := url.Parse(o1.PrevUrl) - Expect(err1).NotTo(HaveOccurred()) - prevUrl2, err2 := url.Parse(o2.PrevUrl) - Expect(err2).NotTo(HaveOccurred()) - queries1 := prevUrl1.Query() - queries2 := prevUrl2.Query() - Expect(queries1).To(Equal(queries2)) - - nextUrl1, err1 := url.Parse(o1.NextUrl) - Expect(err1).NotTo(HaveOccurred()) - nextUrl2, err2 := url.Parse(o2.NextUrl) - Expect(err2).NotTo(HaveOccurred()) - queries1 = nextUrl1.Query() - queries2 = nextUrl2.Query() - Expect(queries1).To(Equal(queries2)) - -} -func checkAggregatedMetricResult(pathVariables []string, parameters map[string]string, result AppAggregatedMetricResult) { - var actual AppAggregatedMetricResult - resp, err := getAppAggregatedMetrics(pathVariables, parameters) - defer resp.Body.Close() - Expect(err).NotTo(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(http.StatusOK)) - err = json.NewDecoder(resp.Body).Decode(&actual) - Expect(err).NotTo(HaveOccurred()) - compareAppAggregatedMetricResult(actual, result) - -} diff --git a/src/integration/integration_api_metricscollector_test.go b/src/integration/integration_api_metricscollector_test.go index 5e9415076..9fa46f81b 100644 --- a/src/integration/integration_api_metricscollector_test.go +++ b/src/integration/integration_api_metricscollector_test.go @@ -4,26 +4,14 @@ import ( "autoscaler/cf" "autoscaler/metricscollector/config" "autoscaler/models" - "encoding/json" "fmt" "net/http" - "net/url" "strings" . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" "github.com/onsi/gomega/ghttp" ) -type AppInstanceMetricResult struct { - TotalResults int `json:"total_results"` - TotalPages int `json:"total_pages"` - Page int `json:"page"` - PrevUrl string `json:"prev_url"` - NextUrl string `json:"next_url"` - Resources []models.AppInstanceMetric `json:"resources"` -} - var _ = Describe("Integration_Api_MetricsCollector", func() { var ( appId string @@ -65,7 +53,7 @@ var _ = Describe("Integration_Api_MetricsCollector", func() { }) It("should error with status code 500", func() { By("check public api") - checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{}) + checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[APIPublicServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{}) }) }) @@ -83,7 +71,7 @@ var _ = Describe("Integration_Api_MetricsCollector", func() { }) It("should error with status code 500", func() { By("check public api") - checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{}) + checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[APIPublicServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{}) }) }) Context("UAA api returns 401", func() { @@ -107,7 +95,7 @@ var _ = Describe("Integration_Api_MetricsCollector", func() { }) It("should error with status code 401", func() { By("check public api") - checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{}) + checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[APIPublicServer], pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{}) }) }) @@ -123,7 +111,7 @@ var _ = Describe("Integration_Api_MetricsCollector", func() { }) It("should error with status code 401", func() { By("check public api") - checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{}) + checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[APIPublicServer], pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{}) }) }) @@ -135,9 +123,9 @@ var _ = Describe("Integration_Api_MetricsCollector", func() { It("should error with status code 500", func() { By("check internal api") - checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{"error": fmt.Sprintf("connect ECONNREFUSED 127.0.0.1:%d", components.Ports[MetricsCollector])}) + checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[APIPublicServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{"error": fmt.Sprintf("connect ECONNREFUSED 127.0.0.1:%d", components.Ports[MetricsCollector])}) By("check public api") - checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{"error": fmt.Sprintf("connect ECONNREFUSED 127.0.0.1:%d", components.Ports[MetricsCollector])}) + checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[APIPublicServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{"error": fmt.Sprintf("connect ECONNREFUSED 127.0.0.1:%d", components.Ports[MetricsCollector])}) }) @@ -219,7 +207,7 @@ var _ = Describe("Integration_Api_MetricsCollector", func() { } By("check public api") - checkAppInstanceMetricResult(pathVariables, parameters, result) + checkAppInstanceMetricResult(components.Ports[APIPublicServer], pathVariables, parameters, result) By("get the 2nd page") parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "2", "results-per-page": "2"} @@ -251,7 +239,7 @@ var _ = Describe("Integration_Api_MetricsCollector", func() { }, } By("check public api") - checkAppInstanceMetricResult(pathVariables, parameters, result) + checkAppInstanceMetricResult(components.Ports[APIPublicServer], pathVariables, parameters, result) By("get the 3rd page") parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "3", "results-per-page": "2"} @@ -273,7 +261,7 @@ var _ = Describe("Integration_Api_MetricsCollector", func() { }, } By("check public api") - checkAppInstanceMetricResult(pathVariables, parameters, result) + checkAppInstanceMetricResult(components.Ports[APIPublicServer], pathVariables, parameters, result) By("the 4th page should be empty") parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "4", "results-per-page": "2"} @@ -285,7 +273,7 @@ var _ = Describe("Integration_Api_MetricsCollector", func() { Resources: []models.AppInstanceMetric{}, } By("check public api") - checkAppInstanceMetricResult(pathVariables, parameters, result) + checkAppInstanceMetricResult(components.Ports[APIPublicServer], pathVariables, parameters, result) By("the 5th page should be empty") parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "5", "results-per-page": "2"} @@ -296,7 +284,7 @@ var _ = Describe("Integration_Api_MetricsCollector", func() { Resources: []models.AppInstanceMetric{}, } By("check public api") - checkAppInstanceMetricResult(pathVariables, parameters, result) + checkAppInstanceMetricResult(components.Ports[APIPublicServer], pathVariables, parameters, result) }) }) Context("instance-index is provided", func() { @@ -330,7 +318,7 @@ var _ = Describe("Integration_Api_MetricsCollector", func() { } By("check public api") - checkAppInstanceMetricResult(pathVariables, parameters, result) + checkAppInstanceMetricResult(components.Ports[APIPublicServer], pathVariables, parameters, result) By("get the 2nd page") parameters = map[string]string{"instance-index": "1", "start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "2", "results-per-page": "2"} @@ -342,53 +330,10 @@ var _ = Describe("Integration_Api_MetricsCollector", func() { Resources: []models.AppInstanceMetric{}, } By("check public api") - checkAppInstanceMetricResult(pathVariables, parameters, result) + checkAppInstanceMetricResult(components.Ports[APIPublicServer], pathVariables, parameters, result) }) }) }) }) }) - -func getInstanceMetricsUrl(appId string, metricType string, parameteters map[string]string, pageNo int) string { - return fmt.Sprintf("/v1/apps/%s/metric_histories/%s?any=any&start-time=%s&end-time=%s&order-direction=%s&page=%d&results-per-page=%s", appId, metricType, parameteters["start-time"], parameteters["end-time"], parameteters["order-direction"], pageNo, parameteters["results-per-page"]) -} - -func getInstanceMetricsUrlWithInstanceIndex(appId string, metricType string, parameteters map[string]string, pageNo int) string { - return fmt.Sprintf("/v1/apps/%s/metric_histories/%s?any=any&instance-index=%s&start-time=%s&end-time=%s&order-direction=%s&page=%d&results-per-page=%s", appId, metricType, parameteters["instance-index"], parameteters["start-time"], parameteters["end-time"], parameteters["order-direction"], pageNo, parameteters["results-per-page"]) -} - -func compareAppInstanceMetricResult(o1, o2 AppInstanceMetricResult) { - Expect(o1.Page).To(Equal(o2.Page)) - Expect(o1.TotalPages).To(Equal(o2.TotalPages)) - Expect(o1.TotalResults).To(Equal(o2.TotalResults)) - Expect(o1.Resources).To(Equal(o2.Resources)) - - prevUrl1, err1 := url.Parse(o1.PrevUrl) - Expect(err1).NotTo(HaveOccurred()) - prevUrl2, err2 := url.Parse(o2.PrevUrl) - Expect(err2).NotTo(HaveOccurred()) - queries1 := prevUrl1.Query() - queries2 := prevUrl2.Query() - Expect(queries1).To(Equal(queries2)) - - nextUrl1, err1 := url.Parse(o1.NextUrl) - Expect(err1).NotTo(HaveOccurred()) - nextUrl2, err2 := url.Parse(o2.NextUrl) - Expect(err2).NotTo(HaveOccurred()) - queries1 = nextUrl1.Query() - queries2 = nextUrl2.Query() - Expect(queries1).To(Equal(queries2)) - -} -func checkAppInstanceMetricResult(pathVariables []string, parameters map[string]string, result AppInstanceMetricResult) { - var actual AppInstanceMetricResult - resp, err := getAppInstanceMetrics(pathVariables, parameters) - defer resp.Body.Close() - Expect(err).NotTo(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(http.StatusOK)) - err = json.NewDecoder(resp.Body).Decode(&actual) - Expect(err).NotTo(HaveOccurred()) - compareAppInstanceMetricResult(actual, result) - -} diff --git a/src/integration/integration_api_scalingengine_test.go b/src/integration/integration_api_scalingengine_test.go index 3ef1c3033..a156ff977 100644 --- a/src/integration/integration_api_scalingengine_test.go +++ b/src/integration/integration_api_scalingengine_test.go @@ -3,14 +3,11 @@ package integration import ( "autoscaler/cf" "autoscaler/models" - "encoding/json" "fmt" "net/http" - "net/url" "strings" . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" "github.com/onsi/gomega/ghttp" ) @@ -60,7 +57,7 @@ var _ = Describe("Integration_Api_ScalingEngine", func() { }) It("should error with status code 500", func() { By("check public api") - checkPublicAPIResponseContentWithParameters(getScalingHistories, pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{}) + checkPublicAPIResponseContentWithParameters(getScalingHistories, components.Ports[APIPublicServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{}) }) }) @@ -78,7 +75,7 @@ var _ = Describe("Integration_Api_ScalingEngine", func() { }) It("should error with status code 500", func() { By("check public api") - checkPublicAPIResponseContentWithParameters(getScalingHistories, pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{}) + checkPublicAPIResponseContentWithParameters(getScalingHistories, components.Ports[APIPublicServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{}) }) }) @@ -103,7 +100,7 @@ var _ = Describe("Integration_Api_ScalingEngine", func() { }) It("should error with status code 401", func() { By("check public api") - checkPublicAPIResponseContentWithParameters(getScalingHistories, pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{}) + checkPublicAPIResponseContentWithParameters(getScalingHistories, components.Ports[APIPublicServer], pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{}) }) }) @@ -119,7 +116,7 @@ var _ = Describe("Integration_Api_ScalingEngine", func() { }) It("should error with status code 401", func() { By("check public api") - checkPublicAPIResponseContentWithParameters(getScalingHistories, pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{}) + checkPublicAPIResponseContentWithParameters(getScalingHistories, components.Ports[APIPublicServer], pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{}) }) }) @@ -131,7 +128,7 @@ var _ = Describe("Integration_Api_ScalingEngine", func() { It("should error with status code 500", func() { By("check public api") - checkPublicAPIResponseContentWithParameters(getScalingHistories, pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{"error": fmt.Sprintf("connect ECONNREFUSED 127.0.0.1:%d", components.Ports[ScalingEngine])}) + checkPublicAPIResponseContentWithParameters(getScalingHistories, components.Ports[APIPublicServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{"error": fmt.Sprintf("connect ECONNREFUSED 127.0.0.1:%d", components.Ports[ScalingEngine])}) }) @@ -205,7 +202,7 @@ var _ = Describe("Integration_Api_ScalingEngine", func() { }, } By("check public api") - checkScalingHistoryResult(pathVariables, parameters, result) + checkScalingHistoryResult(components.Ports[APIPublicServer], pathVariables, parameters, result) By("get the 2nd page") parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "desc", "page": "2", "results-per-page": "2"} @@ -241,7 +238,7 @@ var _ = Describe("Integration_Api_ScalingEngine", func() { }, } By("check public api") - checkScalingHistoryResult(pathVariables, parameters, result) + checkScalingHistoryResult(components.Ports[APIPublicServer], pathVariables, parameters, result) By("get the 3rd page") parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "desc", "page": "3", "results-per-page": "2"} @@ -265,7 +262,7 @@ var _ = Describe("Integration_Api_ScalingEngine", func() { }, } By("check public api") - checkScalingHistoryResult(pathVariables, parameters, result) + checkScalingHistoryResult(components.Ports[APIPublicServer], pathVariables, parameters, result) By("the 4th page should be empty") parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "desc", "page": "4", "results-per-page": "2"} @@ -277,48 +274,9 @@ var _ = Describe("Integration_Api_ScalingEngine", func() { Resources: []models.AppScalingHistory{}, } By("check public api") - checkScalingHistoryResult(pathVariables, parameters, result) + checkScalingHistoryResult(components.Ports[APIPublicServer], pathVariables, parameters, result) }) }) }) }) - -func getScalingHistoriesUrl(appId string, parameteters map[string]string, pageNo int) string { - return fmt.Sprintf("/v1/apps/%s/scaling_histories?any=any&start-time=%s&end-time=%s&order-direction=%s&page=%d&results-per-page=%s", appId, parameteters["start-time"], parameteters["end-time"], parameteters["order-direction"], pageNo, parameteters["results-per-page"]) -} - -func compareScalingHistoryResult(o1, o2 ScalingHistoryResult) { - Expect(o1.Page).To(Equal(o2.Page)) - Expect(o1.TotalPages).To(Equal(o2.TotalPages)) - Expect(o1.TotalResults).To(Equal(o2.TotalResults)) - Expect(o1.Resources).To(Equal(o2.Resources)) - - prevUrl1, err1 := url.Parse(o1.PrevUrl) - Expect(err1).NotTo(HaveOccurred()) - prevUrl2, err2 := url.Parse(o2.PrevUrl) - Expect(err2).NotTo(HaveOccurred()) - queries1 := prevUrl1.Query() - queries2 := prevUrl2.Query() - Expect(queries1).To(Equal(queries2)) - - nextUrl1, err1 := url.Parse(o1.NextUrl) - Expect(err1).NotTo(HaveOccurred()) - nextUrl2, err2 := url.Parse(o2.NextUrl) - Expect(err2).NotTo(HaveOccurred()) - queries1 = nextUrl1.Query() - queries2 = nextUrl2.Query() - Expect(queries1).To(Equal(queries2)) - -} -func checkScalingHistoryResult(pathVariables []string, parameters map[string]string, result ScalingHistoryResult) { - var actual ScalingHistoryResult - resp, err := getScalingHistories(pathVariables, parameters) - defer resp.Body.Close() - Expect(err).NotTo(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(http.StatusOK)) - err = json.NewDecoder(resp.Body).Decode(&actual) - Expect(err).NotTo(HaveOccurred()) - compareScalingHistoryResult(actual, result) - -} diff --git a/src/integration/integration_api_scheduler_test.go b/src/integration/integration_api_scheduler_test.go index 1a3383c54..790271dfc 100644 --- a/src/integration/integration_api_scheduler_test.go +++ b/src/integration/integration_api_scheduler_test.go @@ -3,9 +3,7 @@ package integration import ( "autoscaler/cf" "encoding/base64" - "encoding/json" "fmt" - "io/ioutil" "net/http" "strings" @@ -55,7 +53,7 @@ var _ = Describe("Integration_Api_Scheduler", func() { apiServerConfPath = components.PrepareApiServerConfig(components.Ports[APIServer], components.Ports[APIPublicServer], false, 200, fakeCCNOAAUAA.URL(), dbUrl, fmt.Sprintf("https://127.0.0.1:%d", components.Ports[Scheduler]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[ScalingEngine]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[MetricsCollector]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[EventGenerator]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[ServiceBrokerInternal]), true, defaultHttpClientTimeout, 30, 30, tmpDir) startApiServer() - resp, err := detachPolicy(appId, INTERNAL) + resp, err := detachPolicy(appId, components.Ports[APIPublicServer], httpClientForPublicApi) Expect(err).NotTo(HaveOccurred()) resp.Body.Close() }) @@ -72,19 +70,19 @@ var _ = Describe("Integration_Api_Scheduler", func() { It("should error with status code 500", func() { By("check public api") policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusInternalServerError, PUBLIC) - checkApiServerStatus(appId, http.StatusInternalServerError, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusInternalServerError, components.Ports[APIPublicServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusInternalServerError, components.Ports[APIPublicServer], httpClientForPublicApi) }) }) Context("Delete policy", func() { BeforeEach(func() { policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusInternalServerError, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusInternalServerError, components.Ports[APIPublicServer], httpClientForPublicApi) }) It("should error with status code 500", func() { - doDetachPolicy(appId, http.StatusInternalServerError, "", PUBLIC) - checkApiServerStatus(appId, http.StatusInternalServerError, PUBLIC) + doDetachPolicy(appId, http.StatusInternalServerError, "", components.Ports[APIPublicServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusInternalServerError, components.Ports[APIPublicServer], httpClientForPublicApi) }) }) @@ -104,19 +102,19 @@ var _ = Describe("Integration_Api_Scheduler", func() { It("should error with status code 500", func() { By("check public api") policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusInternalServerError, PUBLIC) - checkApiServerStatus(appId, http.StatusInternalServerError, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusInternalServerError, components.Ports[APIPublicServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusInternalServerError, components.Ports[APIPublicServer], httpClientForPublicApi) }) }) Context("Delete policy", func() { BeforeEach(func() { policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusInternalServerError, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusInternalServerError, components.Ports[APIPublicServer], httpClientForPublicApi) }) It("should error with status code 500", func() { - doDetachPolicy(appId, http.StatusInternalServerError, "", PUBLIC) - checkApiServerStatus(appId, http.StatusInternalServerError, PUBLIC) + doDetachPolicy(appId, http.StatusInternalServerError, "", components.Ports[APIPublicServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusInternalServerError, components.Ports[APIPublicServer], httpClientForPublicApi) }) }) @@ -143,19 +141,19 @@ var _ = Describe("Integration_Api_Scheduler", func() { It("should error with status code 401", func() { By("check public api") policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusUnauthorized, PUBLIC) - checkApiServerStatus(appId, http.StatusUnauthorized, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusUnauthorized, components.Ports[APIPublicServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusUnauthorized, components.Ports[APIPublicServer], httpClientForPublicApi) }) }) Context("Delete policy", func() { BeforeEach(func() { policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusUnauthorized, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusUnauthorized, components.Ports[APIPublicServer], httpClientForPublicApi) }) It("should error with status code 401", func() { - doDetachPolicy(appId, http.StatusUnauthorized, "", PUBLIC) - checkApiServerStatus(appId, http.StatusUnauthorized, PUBLIC) + doDetachPolicy(appId, http.StatusUnauthorized, "", components.Ports[APIPublicServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusUnauthorized, components.Ports[APIPublicServer], httpClientForPublicApi) }) }) @@ -174,19 +172,19 @@ var _ = Describe("Integration_Api_Scheduler", func() { It("should error with status code 401", func() { By("check public api") policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusUnauthorized, PUBLIC) - checkApiServerStatus(appId, http.StatusUnauthorized, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusUnauthorized, components.Ports[APIPublicServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusUnauthorized, components.Ports[APIPublicServer], httpClientForPublicApi) }) }) Context("Delete policy", func() { BeforeEach(func() { policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusUnauthorized, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusUnauthorized, components.Ports[APIPublicServer], httpClientForPublicApi) }) It("should error with status code 401", func() { - doDetachPolicy(appId, http.StatusUnauthorized, "", PUBLIC) - checkApiServerStatus(appId, http.StatusUnauthorized, PUBLIC) + doDetachPolicy(appId, http.StatusUnauthorized, "", components.Ports[APIPublicServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusUnauthorized, components.Ports[APIPublicServer], httpClientForPublicApi) }) }) @@ -198,10 +196,10 @@ var _ = Describe("Integration_Api_Scheduler", func() { stopScheduler() }) BeforeEach(func() { - provisionAndBind(serviceInstanceId, orgId, spaceId, bindingId, appId, nil) + provisionAndBind(serviceInstanceId, orgId, spaceId, bindingId, appId, nil, components.Ports[ServiceBroker], httpClientForPublicApi) }) AfterEach(func() { - unbindAndDeprovision(bindingId, appId, serviceInstanceId) + unbindAndDeprovision(bindingId, appId, serviceInstanceId, components.Ports[ServiceBroker], httpClientForPublicApi) startScheduler() }) @@ -209,16 +207,16 @@ var _ = Describe("Integration_Api_Scheduler", func() { Context("internal api", func() { It("should not create policy", func() { policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusInternalServerError, INTERNAL) - checkApiServerStatus(appId, http.StatusNotFound, INTERNAL) + doAttachPolicy(appId, policyStr, http.StatusInternalServerError, components.Ports[APIServer], httpClient) + checkApiServerStatus(appId, http.StatusNotFound, components.Ports[APIServer], httpClient) }) }) Context("public api", func() { It("should not create policy", func() { policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusInternalServerError, PUBLIC) - checkApiServerStatus(appId, http.StatusNotFound, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusInternalServerError, components.Ports[APIPublicServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusNotFound, components.Ports[APIPublicServer], httpClientForPublicApi) }) }) @@ -229,12 +227,12 @@ var _ = Describe("Integration_Api_Scheduler", func() { BeforeEach(func() { //attach a policy first with 4 recurring and 2 specific_date schedules policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusCreated, INTERNAL) + doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIServer], httpClient) }) It("should delete policy in API server", func() { - doDetachPolicy(appId, http.StatusInternalServerError, "", INTERNAL) - checkApiServerStatus(appId, http.StatusNotFound, INTERNAL) + doDetachPolicy(appId, http.StatusInternalServerError, "", components.Ports[APIServer], httpClient) + checkApiServerStatus(appId, http.StatusNotFound, components.Ports[APIServer], httpClient) }) }) @@ -242,12 +240,12 @@ var _ = Describe("Integration_Api_Scheduler", func() { BeforeEach(func() { //attach a policy first with 4 recurring and 2 specific_date schedules policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusCreated, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIPublicServer], httpClientForPublicApi) }) It("should delete policy in API server", func() { - doDetachPolicy(appId, http.StatusInternalServerError, "", PUBLIC) - checkApiServerStatus(appId, http.StatusNotFound, PUBLIC) + doDetachPolicy(appId, http.StatusInternalServerError, "", components.Ports[APIPublicServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusNotFound, components.Ports[APIPublicServer], httpClientForPublicApi) }) }) @@ -257,26 +255,26 @@ var _ = Describe("Integration_Api_Scheduler", func() { Describe("Create policy", func() { BeforeEach(func() { - provisionAndBind(serviceInstanceId, orgId, spaceId, bindingId, appId, nil) + provisionAndBind(serviceInstanceId, orgId, spaceId, bindingId, appId, nil, components.Ports[ServiceBroker], httpClientForPublicApi) }) AfterEach(func() { - unbindAndDeprovision(bindingId, appId, serviceInstanceId) + unbindAndDeprovision(bindingId, appId, serviceInstanceId, components.Ports[ServiceBroker], httpClientForPublicApi) }) Context("internal api", func() { Context("Policies with schedules", func() { It("creates a policy and associated schedules", func() { policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusCreated, INTERNAL) - checkApiServerContent(appId, policyStr, http.StatusOK, INTERNAL) + doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIServer], httpClient) + checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[APIServer], httpClient) Expect(checkSchedule(appId, http.StatusOK, map[string]int{"recurring_schedule": 4, "specific_date": 2})).To(BeTrue()) }) It("fails with an invalid policy", func() { policyStr = readPolicyFromFile("fakeInvalidPolicy.json") - doAttachPolicy(appId, policyStr, http.StatusBadRequest, INTERNAL) - checkApiServerStatus(appId, http.StatusNotFound, INTERNAL) + doAttachPolicy(appId, policyStr, http.StatusBadRequest, components.Ports[APIServer], httpClient) + checkApiServerStatus(appId, http.StatusNotFound, components.Ports[APIServer], httpClient) checkSchedulerStatus(appId, http.StatusNotFound) }) }) @@ -285,8 +283,8 @@ var _ = Describe("Integration_Api_Scheduler", func() { It("creates only the policy", func() { policyStr = readPolicyFromFile("fakePolicyWithoutSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusCreated, INTERNAL) - checkApiServerContent(appId, policyStr, http.StatusOK, INTERNAL) + doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIServer], httpClient) + checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[APIServer], httpClient) checkSchedulerStatus(appId, http.StatusNotFound) }) @@ -298,16 +296,16 @@ var _ = Describe("Integration_Api_Scheduler", func() { It("creates a policy and associated schedules", func() { policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusCreated, PUBLIC) - checkApiServerContent(appId, policyStr, http.StatusOK, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIPublicServer], httpClientForPublicApi) + checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[APIPublicServer], httpClientForPublicApi) Expect(checkSchedule(appId, http.StatusOK, map[string]int{"recurring_schedule": 4, "specific_date": 2})).To(BeTrue()) }) It("fails with an invalid policy", func() { policyStr = readPolicyFromFile("fakeInvalidPolicy.json") - doAttachPolicy(appId, policyStr, http.StatusBadRequest, PUBLIC) - checkApiServerStatus(appId, http.StatusNotFound, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusBadRequest, components.Ports[APIPublicServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusNotFound, components.Ports[APIPublicServer], httpClientForPublicApi) checkSchedulerStatus(appId, http.StatusNotFound) }) }) @@ -316,8 +314,8 @@ var _ = Describe("Integration_Api_Scheduler", func() { It("creates only the policy", func() { policyStr = readPolicyFromFile("fakePolicyWithoutSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusCreated, PUBLIC) - checkApiServerContent(appId, policyStr, http.StatusOK, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIPublicServer], httpClientForPublicApi) + checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[APIPublicServer], httpClientForPublicApi) checkSchedulerStatus(appId, http.StatusNotFound) }) @@ -328,10 +326,10 @@ var _ = Describe("Integration_Api_Scheduler", func() { Describe("Update policy", func() { BeforeEach(func() { - provisionAndBind(serviceInstanceId, orgId, spaceId, bindingId, appId, nil) + provisionAndBind(serviceInstanceId, orgId, spaceId, bindingId, appId, nil, components.Ports[ServiceBroker], httpClientForPublicApi) }) AfterEach(func() { - unbindAndDeprovision(bindingId, appId, serviceInstanceId) + unbindAndDeprovision(bindingId, appId, serviceInstanceId, components.Ports[ServiceBroker], httpClientForPublicApi) }) Context("internal api", func() { Context("Update policies with schedules", func() { @@ -339,15 +337,15 @@ var _ = Describe("Integration_Api_Scheduler", func() { //attach a policy first with 4 recurring and 2 specific_date schedules policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusCreated, INTERNAL) + doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIServer], httpClient) }) It("updates the policy and schedules", func() { //attach another policy with 3 recurring and 1 specific_date schedules policyStr = readPolicyFromFile("fakePolicyWithScheduleAnother.json") - doAttachPolicy(appId, policyStr, http.StatusOK, INTERNAL) - checkApiServerContent(appId, policyStr, http.StatusOK, INTERNAL) + doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[APIServer], httpClient) + checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[APIServer], httpClient) Expect(checkSchedule(appId, http.StatusOK, map[string]int{"recurring_schedule": 3, "specific_date": 1})).To(BeTrue()) }) }) @@ -359,15 +357,15 @@ var _ = Describe("Integration_Api_Scheduler", func() { //attach a policy first with 4 recurring and 2 specific_date schedules policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusCreated, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIPublicServer], httpClientForPublicApi) }) It("updates the policy and schedules", func() { //attach another policy with 3 recurring and 1 specific_date schedules policyStr = readPolicyFromFile("fakePolicyWithScheduleAnother.json") - doAttachPolicy(appId, policyStr, http.StatusOK, PUBLIC) - checkApiServerContent(appId, policyStr, http.StatusOK, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[APIPublicServer], httpClientForPublicApi) + checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[APIPublicServer], httpClientForPublicApi) Expect(checkSchedule(appId, http.StatusOK, map[string]int{"recurring_schedule": 3, "specific_date": 1})).To(BeTrue()) }) }) @@ -377,15 +375,15 @@ var _ = Describe("Integration_Api_Scheduler", func() { Describe("Delete Policies", func() { BeforeEach(func() { - provisionAndBind(serviceInstanceId, orgId, spaceId, bindingId, appId, nil) + provisionAndBind(serviceInstanceId, orgId, spaceId, bindingId, appId, nil, components.Ports[ServiceBroker], httpClientForPublicApi) }) AfterEach(func() { - unbindAndDeprovision(bindingId, appId, serviceInstanceId) + unbindAndDeprovision(bindingId, appId, serviceInstanceId, components.Ports[ServiceBroker], httpClientForPublicApi) }) Context("internal api", func() { Context("for a non-existing app", func() { It("Should return a NOT FOUND (404)", func() { - doDetachPolicy(appId, http.StatusNotFound, `{"error":"No policy bound with application"}`, INTERNAL) + doDetachPolicy(appId, http.StatusNotFound, `{"error":"No policy bound with application"}`, components.Ports[APIServer], httpClient) }) }) @@ -394,12 +392,12 @@ var _ = Describe("Integration_Api_Scheduler", func() { //attach a policy first with 4 recurring and 2 specific_date schedules policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusCreated, INTERNAL) + doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIServer], httpClient) }) It("deletes the policy and schedules", func() { - doDetachPolicy(appId, http.StatusOK, "", INTERNAL) - checkApiServerStatus(appId, http.StatusNotFound, INTERNAL) + doDetachPolicy(appId, http.StatusOK, "", components.Ports[APIServer], httpClient) + checkApiServerStatus(appId, http.StatusNotFound, components.Ports[APIServer], httpClient) checkSchedulerStatus(appId, http.StatusNotFound) }) }) @@ -408,7 +406,7 @@ var _ = Describe("Integration_Api_Scheduler", func() { Context("public api", func() { Context("for a non-existing app", func() { It("Should return a NOT FOUND (404)", func() { - doDetachPolicy(appId, http.StatusNotFound, `{"error":"No policy bound with application"}`, PUBLIC) + doDetachPolicy(appId, http.StatusNotFound, `{"error":"No policy bound with application"}`, components.Ports[APIPublicServer], httpClientForPublicApi) }) }) @@ -416,12 +414,12 @@ var _ = Describe("Integration_Api_Scheduler", func() { BeforeEach(func() { //attach a policy first with 4 recurring and 2 specific_date schedules policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusCreated, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIPublicServer], httpClientForPublicApi) }) It("deletes the policy and schedules", func() { - doDetachPolicy(appId, http.StatusOK, "", PUBLIC) - checkApiServerStatus(appId, http.StatusNotFound, PUBLIC) + doDetachPolicy(appId, http.StatusOK, "", components.Ports[APIPublicServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusNotFound, components.Ports[APIPublicServer], httpClientForPublicApi) checkSchedulerStatus(appId, http.StatusNotFound) }) }) @@ -435,7 +433,7 @@ var _ = Describe("Integration_Api_Scheduler", func() { apiServerConfPath = components.PrepareApiServerConfig(components.Ports[APIServer], components.Ports[APIPublicServer], false, 200, fakeCCNOAAUAA.URL(), dbUrl, fmt.Sprintf("https://127.0.0.1:%d", components.Ports[Scheduler]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[ScalingEngine]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[MetricsCollector]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[EventGenerator]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[ServiceBrokerInternal]), false, defaultHttpClientTimeout, 30, 30, tmpDir) startApiServer() - resp, err := detachPolicy(appId, INTERNAL) + resp, err := detachPolicy(appId, components.Ports[APIServer], httpClient) Expect(err).NotTo(HaveOccurred()) resp.Body.Close() }) @@ -449,16 +447,16 @@ var _ = Describe("Integration_Api_Scheduler", func() { It("creates a policy and associated schedules", func() { policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusCreated, INTERNAL) - checkApiServerContent(appId, policyStr, http.StatusOK, INTERNAL) + doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIServer], httpClient) + checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[APIServer], httpClient) Expect(checkSchedule(appId, http.StatusOK, map[string]int{"recurring_schedule": 4, "specific_date": 2})).To(BeTrue()) }) It("fails with an invalid policy", func() { policyStr = readPolicyFromFile("fakeInvalidPolicy.json") - doAttachPolicy(appId, policyStr, http.StatusBadRequest, INTERNAL) - checkApiServerStatus(appId, http.StatusNotFound, INTERNAL) + doAttachPolicy(appId, policyStr, http.StatusBadRequest, components.Ports[APIServer], httpClient) + checkApiServerStatus(appId, http.StatusNotFound, components.Ports[APIServer], httpClient) checkSchedulerStatus(appId, http.StatusNotFound) }) @@ -468,8 +466,8 @@ var _ = Describe("Integration_Api_Scheduler", func() { It("creates only the policy", func() { policyStr = readPolicyFromFile("fakePolicyWithoutSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusCreated, INTERNAL) - checkApiServerContent(appId, policyStr, http.StatusOK, INTERNAL) + doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIServer], httpClient) + checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[APIServer], httpClient) checkSchedulerStatus(appId, http.StatusNotFound) }) @@ -481,16 +479,16 @@ var _ = Describe("Integration_Api_Scheduler", func() { It("creates a policy and associated schedules", func() { policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusCreated, PUBLIC) - checkApiServerContent(appId, policyStr, http.StatusOK, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIPublicServer], httpClientForPublicApi) + checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[APIPublicServer], httpClientForPublicApi) Expect(checkSchedule(appId, http.StatusOK, map[string]int{"recurring_schedule": 4, "specific_date": 2})).To(BeTrue()) }) It("fails with an invalid policy", func() { policyStr = readPolicyFromFile("fakeInvalidPolicy.json") - doAttachPolicy(appId, policyStr, http.StatusBadRequest, PUBLIC) - checkApiServerStatus(appId, http.StatusNotFound, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusBadRequest, components.Ports[APIPublicServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusNotFound, components.Ports[APIPublicServer], httpClientForPublicApi) checkSchedulerStatus(appId, http.StatusNotFound) }) @@ -500,8 +498,8 @@ var _ = Describe("Integration_Api_Scheduler", func() { It("creates only the policy", func() { policyStr = readPolicyFromFile("fakePolicyWithoutSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusCreated, PUBLIC) - checkApiServerContent(appId, policyStr, http.StatusOK, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIPublicServer], httpClientForPublicApi) + checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[APIPublicServer], httpClientForPublicApi) checkSchedulerStatus(appId, http.StatusNotFound) }) @@ -516,15 +514,15 @@ var _ = Describe("Integration_Api_Scheduler", func() { BeforeEach(func() { //attach a policy first with 4 recurring and 2 specific_date schedules policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusCreated, INTERNAL) + doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIServer], httpClient) }) It("updates the policy and schedules", func() { //attach another policy with 3 recurring and 1 specific_date schedules policyStr = readPolicyFromFile("fakePolicyWithScheduleAnother.json") - doAttachPolicy(appId, policyStr, http.StatusOK, INTERNAL) - checkApiServerContent(appId, policyStr, http.StatusOK, INTERNAL) + doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[APIServer], httpClient) + checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[APIServer], httpClient) Expect(checkSchedule(appId, http.StatusOK, map[string]int{"recurring_schedule": 3, "specific_date": 1})).To(BeTrue()) }) }) @@ -535,15 +533,15 @@ var _ = Describe("Integration_Api_Scheduler", func() { BeforeEach(func() { //attach a policy first with 4 recurring and 2 specific_date schedules policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusCreated, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIPublicServer], httpClientForPublicApi) }) It("updates the policy and schedules", func() { //attach another policy with 3 recurring and 1 specific_date schedules policyStr = readPolicyFromFile("fakePolicyWithScheduleAnother.json") - doAttachPolicy(appId, policyStr, http.StatusOK, PUBLIC) - checkApiServerContent(appId, policyStr, http.StatusOK, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[APIPublicServer], httpClientForPublicApi) + checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[APIPublicServer], httpClientForPublicApi) Expect(checkSchedule(appId, http.StatusOK, map[string]int{"recurring_schedule": 3, "specific_date": 1})).To(BeTrue()) }) }) @@ -555,7 +553,7 @@ var _ = Describe("Integration_Api_Scheduler", func() { Context("internal api", func() { Context("for a non-existing app", func() { It("Should return a NOT FOUND (404)", func() { - doDetachPolicy(appId, http.StatusNotFound, `{"error":"No policy bound with application"}`, INTERNAL) + doDetachPolicy(appId, http.StatusNotFound, `{"error":"No policy bound with application"}`, components.Ports[APIServer], httpClient) }) }) @@ -564,12 +562,12 @@ var _ = Describe("Integration_Api_Scheduler", func() { //attach a policy first with 4 recurring and 2 specific_date schedules policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusCreated, INTERNAL) + doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIServer], httpClient) }) It("deletes the policy and schedules", func() { - doDetachPolicy(appId, http.StatusOK, "", INTERNAL) - checkApiServerStatus(appId, http.StatusNotFound, INTERNAL) + doDetachPolicy(appId, http.StatusOK, "", components.Ports[APIServer], httpClient) + checkApiServerStatus(appId, http.StatusNotFound, components.Ports[APIServer], httpClient) checkSchedulerStatus(appId, http.StatusNotFound) }) }) @@ -578,7 +576,7 @@ var _ = Describe("Integration_Api_Scheduler", func() { Context("public api", func() { Context("for a non-existing app", func() { It("Should return a NOT FOUND (404)", func() { - doDetachPolicy(appId, http.StatusNotFound, `{"error":"No policy bound with application"}`, PUBLIC) + doDetachPolicy(appId, http.StatusNotFound, `{"error":"No policy bound with application"}`, components.Ports[APIPublicServer], httpClientForPublicApi) }) }) @@ -586,12 +584,12 @@ var _ = Describe("Integration_Api_Scheduler", func() { BeforeEach(func() { //attach a policy first with 4 recurring and 2 specific_date schedules policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") - doAttachPolicy(appId, policyStr, http.StatusCreated, PUBLIC) + doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIPublicServer], httpClientForPublicApi) }) It("deletes the policy and schedules", func() { - doDetachPolicy(appId, http.StatusOK, "", PUBLIC) - checkApiServerStatus(appId, http.StatusNotFound, PUBLIC) + doDetachPolicy(appId, http.StatusOK, "", components.Ports[APIPublicServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusNotFound, components.Ports[APIPublicServer], httpClientForPublicApi) checkSchedulerStatus(appId, http.StatusNotFound) }) }) @@ -601,43 +599,3 @@ var _ = Describe("Integration_Api_Scheduler", func() { }) }) - -func doAttachPolicy(appId string, policyStr []byte, statusCode int, apiType APIType) { - resp, err := attachPolicy(appId, policyStr, apiType) - Expect(err).NotTo(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(statusCode)) - resp.Body.Close() - -} -func doDetachPolicy(appId string, statusCode int, msg string, apiType APIType) { - resp, err := detachPolicy(appId, apiType) - Expect(err).NotTo(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(statusCode)) - if msg != "" { - respBody, err := ioutil.ReadAll(resp.Body) - Expect(err).NotTo(HaveOccurred()) - Expect(string(respBody)).To(Equal(msg)) - } - resp.Body.Close() -} -func checkApiServerStatus(appId string, statusCode int, apiType APIType) { - By("checking the API Server") - resp, err := getPolicy(appId, apiType) - Expect(err).NotTo(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(statusCode)) - resp.Body.Close() -} -func checkApiServerContent(appId string, policyStr []byte, statusCode int, apiType APIType) { - By("checking the API Server") - var expected map[string]interface{} - err := json.Unmarshal(policyStr, &expected) - Expect(err).NotTo(HaveOccurred()) - checkResponseContent(getPolicy, appId, statusCode, expected, apiType) -} -func checkSchedulerStatus(appId string, statusCode int) { - By("checking the Scheduler") - resp, err := getSchedules(appId) - Expect(err).NotTo(HaveOccurred()) - Expect(resp.StatusCode).To(Equal(statusCode)) - resp.Body.Close() -} diff --git a/src/integration/integration_broker_api_test.go b/src/integration/integration_broker_api_test.go index 24dc7af8b..d3001f31e 100644 --- a/src/integration/integration_broker_api_test.go +++ b/src/integration/integration_broker_api_test.go @@ -44,7 +44,7 @@ var _ = Describe("Integration_Broker_Api", func() { bindingId = getRandomId() appId = getRandomId() //add a service instance - resp, err := provisionServiceInstance(serviceInstanceId, orgId, spaceId) + resp, err := provisionServiceInstance(serviceInstanceId, orgId, spaceId, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) resp.Body.Close() @@ -57,7 +57,7 @@ var _ = Describe("Integration_Broker_Api", func() { AfterEach(func() { //clean the service instance added in before each - resp, err := deprovisionServiceInstance(serviceInstanceId) + resp, err := deprovisionServiceInstance(serviceInstanceId, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusOK)) resp.Body.Close() @@ -74,14 +74,14 @@ var _ = Describe("Integration_Broker_Api", func() { AfterEach(func() { //clear the binding - resp, err := unbindService(bindingId, appId, serviceInstanceId) + resp, err := unbindService(bindingId, appId, serviceInstanceId, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusOK)) resp.Body.Close() }) It("creates a binding", func() { - resp, err := bindService(bindingId, appId, serviceInstanceId, schedulePolicyJson) + resp, err := bindService(bindingId, appId, serviceInstanceId, schedulePolicyJson, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) resp.Body.Close() @@ -95,7 +95,7 @@ var _ = Describe("Integration_Broker_Api", func() { By("checking the credential table content") Expect(getCredentialsCount(appId)).To(Equal(0)) - checkResponseContent(getPolicy, appId, http.StatusOK, expected, INTERNAL) + checkResponseContent(getPolicy, appId, http.StatusOK, expected, components.Ports[APIServer], httpClient) }) }) @@ -107,7 +107,7 @@ var _ = Describe("Integration_Broker_Api", func() { AfterEach(func() { //clear the binding - resp, err := unbindService(bindingId, appId, serviceInstanceId) + resp, err := unbindService(bindingId, appId, serviceInstanceId, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusOK)) resp.Body.Close() @@ -115,7 +115,7 @@ var _ = Describe("Integration_Broker_Api", func() { It("creates a binding", func() { schedulerRequestCount := len(fakeScheduler.ReceivedRequests()) - resp, err := bindService(bindingId, appId, serviceInstanceId, minimalScalingRulePolicyJson) + resp, err := bindService(bindingId, appId, serviceInstanceId, minimalScalingRulePolicyJson, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) resp.Body.Close() @@ -130,7 +130,7 @@ var _ = Describe("Integration_Broker_Api", func() { By("checking the credential table content") Expect(getCredentialsCount(appId)).To(Equal(0)) - checkResponseContent(getPolicy, appId, http.StatusOK, expected, INTERNAL) + checkResponseContent(getPolicy, appId, http.StatusOK, expected, components.Ports[APIServer], httpClient) }) }) @@ -141,7 +141,7 @@ var _ = Describe("Integration_Broker_Api", func() { It("does not create a binding", func() { schedulerCount := len(fakeScheduler.ReceivedRequests()) - resp, err := bindService(bindingId, appId, serviceInstanceId, invalidSchemaPolicyJson) + resp, err := bindService(bindingId, appId, serviceInstanceId, invalidSchemaPolicyJson, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusBadRequest)) respBody, err := ioutil.ReadAll(resp.Body) @@ -150,7 +150,7 @@ var _ = Describe("Integration_Broker_Api", func() { Consistently(fakeScheduler.ReceivedRequests).Should(HaveLen(schedulerCount)) By("checking the API Server") - resp, err = getPolicy(appId, INTERNAL) + resp, err = getPolicy(appId, components.Ports[APIServer], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) resp.Body.Close() @@ -164,7 +164,7 @@ var _ = Describe("Integration_Broker_Api", func() { It("does not create a binding", func() { schedulerCount := len(fakeScheduler.ReceivedRequests()) - resp, err := bindService(bindingId, appId, serviceInstanceId, invalidDataPolicyJson) + resp, err := bindService(bindingId, appId, serviceInstanceId, invalidDataPolicyJson, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusBadRequest)) respBody, err := ioutil.ReadAll(resp.Body) @@ -173,7 +173,7 @@ var _ = Describe("Integration_Broker_Api", func() { Consistently(fakeScheduler.ReceivedRequests).Should(HaveLen(schedulerCount)) By("checking the API Server") - resp, err = getPolicy(appId, INTERNAL) + resp, err = getPolicy(appId, components.Ports[APIServer], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) resp.Body.Close() @@ -183,14 +183,14 @@ var _ = Describe("Integration_Broker_Api", func() { Context("ApiServer is down", func() { BeforeEach(func() { stopApiServer() - _, err := getPolicy(appId, INTERNAL) + _, err := getPolicy(appId, components.Ports[APIServer], httpClient) Expect(err).To(HaveOccurred()) fakeScheduler.RouteToHandler("PUT", regPath, ghttp.RespondWith(http.StatusInternalServerError, "error")) }) It("should return 500", func() { schedulerCount := len(fakeScheduler.ReceivedRequests()) - resp, err := bindService(bindingId, appId, serviceInstanceId, schedulePolicyJson) + resp, err := bindService(bindingId, appId, serviceInstanceId, schedulePolicyJson, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusInternalServerError)) resp.Body.Close() @@ -205,14 +205,14 @@ var _ = Describe("Integration_Broker_Api", func() { It("should return 500", func() { schedulerCount := len(fakeScheduler.ReceivedRequests()) - resp, err := bindService(bindingId, appId, serviceInstanceId, schedulePolicyJson) + resp, err := bindService(bindingId, appId, serviceInstanceId, schedulePolicyJson, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusInternalServerError)) resp.Body.Close() Consistently(fakeScheduler.ReceivedRequests).Should(HaveLen(schedulerCount + 1)) By("checking the API Server") - resp, err = getPolicy(appId, INTERNAL) + resp, err = getPolicy(appId, components.Ports[APIServer], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) resp.Body.Close() @@ -227,7 +227,7 @@ var _ = Describe("Integration_Broker_Api", func() { AfterEach(func() { //clear the binding - resp, err := unbindService(bindingId, appId, serviceInstanceId) + resp, err := unbindService(bindingId, appId, serviceInstanceId, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusOK)) resp.Body.Close() @@ -241,7 +241,7 @@ var _ = Describe("Integration_Broker_Api", func() { }) It("creates a binding", func() { - resp, err := bindService(bindingId, appId, serviceInstanceId, schedulePolicyJson) + resp, err := bindService(bindingId, appId, serviceInstanceId, schedulePolicyJson, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) resp.Body.Close() @@ -256,7 +256,7 @@ var _ = Describe("Integration_Broker_Api", func() { By("checking the credential table content") Expect(getCredentialsCount(appId)).To(Equal(1)) - checkResponseContent(getPolicy, appId, http.StatusOK, expected, INTERNAL) + checkResponseContent(getPolicy, appId, http.StatusOK, expected, components.Ports[APIServer], httpClient) }) }) }) @@ -266,7 +266,7 @@ var _ = Describe("Integration_Broker_Api", func() { brokerAuth = base64.StdEncoding.EncodeToString([]byte("username:password")) //do a bind first fakeScheduler.RouteToHandler("PUT", regPath, ghttp.RespondWith(http.StatusOK, "successful")) - resp, err := bindService(bindingId, appId, serviceInstanceId, schedulePolicyJson) + resp, err := bindService(bindingId, appId, serviceInstanceId, schedulePolicyJson, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) resp.Body.Close() @@ -277,13 +277,13 @@ var _ = Describe("Integration_Broker_Api", func() { }) It("should return 200", func() { - resp, err := unbindService(bindingId, appId, serviceInstanceId) + resp, err := unbindService(bindingId, appId, serviceInstanceId, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusOK)) resp.Body.Close() By("checking the API Server") - resp, err = getPolicy(appId, INTERNAL) + resp, err = getPolicy(appId, components.Ports[APIServer], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) resp.Body.Close() @@ -293,14 +293,14 @@ var _ = Describe("Integration_Broker_Api", func() { BeforeEach(func() { fakeScheduler.RouteToHandler("DELETE", regPath, ghttp.RespondWith(http.StatusOK, "successful")) //detach the appId's policy first - resp, err := detachPolicy(appId, INTERNAL) + resp, err := detachPolicy(appId, components.Ports[APIServer], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusOK)) resp.Body.Close() }) It("should return 200", func() { - resp, err := unbindService(bindingId, appId, serviceInstanceId) + resp, err := unbindService(bindingId, appId, serviceInstanceId, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusOK)) resp.Body.Close() @@ -310,13 +310,13 @@ var _ = Describe("Integration_Broker_Api", func() { Context("APIServer is down", func() { BeforeEach(func() { stopApiServer() - _, err := detachPolicy(appId, INTERNAL) + _, err := detachPolicy(appId, components.Ports[APIServer], httpClient) Expect(err).To(HaveOccurred()) fakeScheduler.RouteToHandler("DELETE", regPath, ghttp.RespondWith(http.StatusOK, "successful")) }) It("should return 500", func() { - resp, err := unbindService(bindingId, appId, serviceInstanceId) + resp, err := unbindService(bindingId, appId, serviceInstanceId, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusInternalServerError)) resp.Body.Close() @@ -329,13 +329,13 @@ var _ = Describe("Integration_Broker_Api", func() { }) It("should return 500 and not delete the binding info", func() { - resp, err := unbindService(bindingId, appId, serviceInstanceId) + resp, err := unbindService(bindingId, appId, serviceInstanceId, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusInternalServerError)) resp.Body.Close() By("checking the API Server") - resp, err = getPolicy(appId, INTERNAL) + resp, err = getPolicy(appId, components.Ports[APIServer], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) resp.Body.Close() @@ -353,7 +353,7 @@ var _ = Describe("Integration_Broker_Api", func() { brokerAuth = base64.StdEncoding.EncodeToString([]byte("username:password")) //do a bind first fakeScheduler.RouteToHandler("PUT", regPath, ghttp.RespondWith(http.StatusOK, "successful")) - resp, err := bindService(bindingId, appId, serviceInstanceId, schedulePolicyJson) + resp, err := bindService(bindingId, appId, serviceInstanceId, schedulePolicyJson, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) resp.Body.Close() @@ -367,13 +367,13 @@ var _ = Describe("Integration_Broker_Api", func() { }) It("should return 200", func() { - resp, err := unbindService(bindingId, appId, serviceInstanceId) + resp, err := unbindService(bindingId, appId, serviceInstanceId, components.Ports[ServiceBroker], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusOK)) resp.Body.Close() By("checking the API Server") - resp, err = getPolicy(appId, INTERNAL) + resp, err = getPolicy(appId, components.Ports[APIServer], httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) resp.Body.Close() diff --git a/src/integration/integration_golangapi_eventgenerator_test.go b/src/integration/integration_golangapi_eventgenerator_test.go new file mode 100644 index 000000000..6140fda86 --- /dev/null +++ b/src/integration/integration_golangapi_eventgenerator_test.go @@ -0,0 +1,265 @@ +package integration + +import ( + "autoscaler/cf" + "autoscaler/models" + "fmt" + "net/http" + "strings" + + . "github.com/onsi/ginkgo" + "github.com/onsi/gomega/ghttp" +) + +var _ = Describe("Integration_GolangApi_EventGenerator", func() { + var ( + appId string + pathVariables []string + parameters map[string]string + metric *models.AppMetric + metricType string = "memoryused" + initInstanceCount int = 2 + ) + + BeforeEach(func() { + startFakeCCNOAAUAA(initInstanceCount) + initializeHttpClient("api.crt", "api.key", "autoscaler-ca.crt", apiEventGeneratorHttpRequestTimeout) + initializeHttpClientForPublicApi("api_public.crt", "api_public.key", "autoscaler-ca.crt", apiEventGeneratorHttpRequestTimeout) + + eventGeneratorConfPath = components.PrepareEventGeneratorConfig(dbUrl, components.Ports[EventGenerator], fmt.Sprintf("https://127.0.0.1:%d", components.Ports[MetricsCollector]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[ScalingEngine]), aggregatorExecuteInterval, policyPollerInterval, saveInterval, evaluationManagerInterval, defaultHttpClientTimeout, tmpDir) + startEventGenerator() + golangApiServerConfPath = components.PrepareGolangApiServerConfig(dbUrl, components.Ports[GolangAPIServer], components.Ports[GolangServiceBroker], + fakeCCNOAAUAA.URL(), false, 200, fmt.Sprintf("https://127.0.0.1:%d", components.Ports[Scheduler]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[ScalingEngine]), + fmt.Sprintf("https://127.0.0.1:%d", components.Ports[MetricsCollector]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[EventGenerator]), "https://127.0.0.1:8888", + true, defaultHttpClientTimeout, tmpDir) + startGolangApiServer() + appId = getRandomId() + pathVariables = []string{appId, metricType} + + }) + + AfterEach(func() { + stopGolangApiServer() + stopEventGenerator() + }) + Describe("Get App Metrics", func() { + + Context("Cloud Controller api is not available", func() { + BeforeEach(func() { + fakeCCNOAAUAA.Reset() + fakeCCNOAAUAA.AllowUnhandledRequests = true + }) + It("should error with status code 500", func() { + By("check public api") + checkPublicAPIResponseContentWithParameters(getAppAggregatedMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ + "code": "Interal-Server-Error", + "message": "Failed to check space developer permission", + }) + }) + }) + + Context("UAA api is not available", func() { + BeforeEach(func() { + fakeCCNOAAUAA.Reset() + fakeCCNOAAUAA.AllowUnhandledRequests = true + fakeCCNOAAUAA.RouteToHandler("GET", "/v2/info", ghttp.RespondWithJSONEncoded(http.StatusOK, + cf.Endpoints{ + TokenEndpoint: fakeCCNOAAUAA.URL(), + DopplerEndpoint: strings.Replace(fakeCCNOAAUAA.URL(), "http", "ws", 1), + })) + }) + It("should error with status code 500", func() { + By("check public api") + checkPublicAPIResponseContentWithParameters(getAppAggregatedMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ + "code": "Interal-Server-Error", + "message": "Failed to check space developer permission", + }) + }) + }) + Context("UAA api returns 401", func() { + BeforeEach(func() { + fakeCCNOAAUAA.Reset() + fakeCCNOAAUAA.AllowUnhandledRequests = true + fakeCCNOAAUAA.RouteToHandler("GET", "/v2/info", ghttp.RespondWithJSONEncoded(http.StatusOK, + cf.Endpoints{ + TokenEndpoint: fakeCCNOAAUAA.URL(), + DopplerEndpoint: strings.Replace(fakeCCNOAAUAA.URL(), "http", "ws", 1), + })) + fakeCCNOAAUAA.RouteToHandler("POST", "/check_token", ghttp.RespondWithJSONEncoded(http.StatusOK, + struct { + Scope []string `json:"scope"` + }{ + []string{"cloud_controller.read", "cloud_controller.write", "password.write", "openid", "network.admin", "network.write", "uaa.user"}, + })) + fakeCCNOAAUAA.RouteToHandler("GET", "/userinfo", ghttp.RespondWithJSONEncoded(http.StatusUnauthorized, struct{}{})) + }) + It("should error with status code 401", func() { + By("check public api") + checkPublicAPIResponseContentWithParameters(getAppAggregatedMetrics, components.Ports[GolangAPIServer], pathVariables, + parameters, http.StatusUnauthorized, map[string]interface{}{ + "code": "Unauthorized", + "message": "You are not authorized to perform the requested action"}) + }) + }) + + Context("Check permission not passed", func() { + BeforeEach(func() { + fakeCCNOAAUAA.RouteToHandler("GET", checkUserSpaceRegPath, ghttp.RespondWithJSONEncoded(http.StatusOK, + struct { + TotalResults int `json:"total_results"` + }{ + 0, + })) + }) + It("should error with status code 401", func() { + By("check public api") + checkPublicAPIResponseContentWithParameters(getAppAggregatedMetrics, components.Ports[GolangAPIServer], + pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{ + "code": "Unauthorized", + "message": "You are not authorized to perform the requested action", + }) + }) + }) + + Context("EventGenerator is down", func() { + JustBeforeEach(func() { + stopEventGenerator() + }) + + It("should error with status code 500", func() { + By("check public api") + checkPublicAPIResponseContentWithParameters(getAppAggregatedMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ + "code": "Interal-Server-Error", + "message": "Error retrieving metrics history from eventgenerator", + }) + }) + }) + + Context("Get aggregated metrics", func() { + BeforeEach(func() { + metric = &models.AppMetric{ + AppId: appId, + MetricType: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + } + + metric.Timestamp = 666666 + insertAppMetric(metric) + + metric.Timestamp = 555555 + insertAppMetric(metric) + + metric.Timestamp = 555555 + insertAppMetric(metric) + + metric.Timestamp = 333333 + insertAppMetric(metric) + + metric.Timestamp = 444444 + insertAppMetric(metric) + + //add some other metric-type + metric.MetricType = models.MetricNameThroughput + metric.Unit = models.UnitNum + metric.Timestamp = 444444 + insertAppMetric(metric) + //add some other appId + metric.AppId = "some-other-app-id" + metric.MetricType = models.MetricNameMemoryUsed + metric.Unit = models.UnitMegaBytes + metric.Timestamp = 444444 + insertAppMetric(metric) + }) + It("should get the metrics ", func() { + By("get the 1st page") + parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "1", "results-per-page": "2"} + result := AppAggregatedMetricResult{ + TotalResults: 5, + TotalPages: 3, + Page: 1, + NextUrl: getAppAggregatedMetricUrl(appId, metricType, parameters, 2), + Resources: []models.AppMetric{ + models.AppMetric{ + AppId: appId, + MetricType: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 333333, + }, + models.AppMetric{ + AppId: appId, + MetricType: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 444444, + }, + }, + } + By("check public api") + checkAggregatedMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("get the 2nd page") + parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "2", "results-per-page": "2"} + result = AppAggregatedMetricResult{ + TotalResults: 5, + TotalPages: 3, + Page: 2, + PrevUrl: getAppAggregatedMetricUrl(appId, metricType, parameters, 1), + NextUrl: getAppAggregatedMetricUrl(appId, metricType, parameters, 3), + Resources: []models.AppMetric{ + models.AppMetric{ + AppId: appId, + MetricType: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 555555, + }, + models.AppMetric{ + AppId: appId, + MetricType: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 555555, + }, + }, + } + By("check public api") + checkAggregatedMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("get the 3rd page") + parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "3", "results-per-page": "2"} + result = AppAggregatedMetricResult{ + TotalResults: 5, + TotalPages: 3, + Page: 3, + PrevUrl: getAppAggregatedMetricUrl(appId, metricType, parameters, 2), + Resources: []models.AppMetric{ + models.AppMetric{ + AppId: appId, + MetricType: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 666666, + }, + }, + } + By("check public api") + checkAggregatedMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("the 4th page should be empty") + parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "4", "results-per-page": "2"} + result = AppAggregatedMetricResult{ + TotalResults: 5, + TotalPages: 3, + Page: 4, + PrevUrl: getAppAggregatedMetricUrl(appId, metricType, parameters, 3), + Resources: []models.AppMetric{}, + } + By("check public api") + checkAggregatedMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + }) + + }) + }) +}) diff --git a/src/integration/integration_golangapi_metricscollector_test.go b/src/integration/integration_golangapi_metricscollector_test.go new file mode 100644 index 000000000..b8d46650c --- /dev/null +++ b/src/integration/integration_golangapi_metricscollector_test.go @@ -0,0 +1,362 @@ +package integration + +import ( + "autoscaler/cf" + "autoscaler/metricscollector/config" + "autoscaler/models" + "fmt" + "net/http" + "strings" + + . "github.com/onsi/ginkgo" + "github.com/onsi/gomega/ghttp" +) + +var _ = Describe("Integration_GolangApi_MetricsCollector", func() { + var ( + appId string + pathVariables []string + parameters map[string]string + metric *models.AppInstanceMetric + metricType string = "memoryused" + collectMethod string = config.CollectMethodPolling + initInstanceCount int = 2 + ) + + BeforeEach(func() { + startFakeCCNOAAUAA(initInstanceCount) + fakeMetricsPolling(appId, 400*1024*1024, 600*1024*1024) + initializeHttpClient("api.crt", "api.key", "autoscaler-ca.crt", apiMetricsCollectorHttpRequestTimeout) + initializeHttpClientForPublicApi("api_public.crt", "api_public.key", "autoscaler-ca.crt", apiMetricsCollectorHttpRequestTimeout) + metricsCollectorConfPath = components.PrepareMetricsCollectorConfig(dbUrl, components.Ports[MetricsCollector], fakeCCNOAAUAA.URL(), collectInterval, + refreshInterval, saveInterval, collectMethod, defaultHttpClientTimeout, tmpDir) + startMetricsCollector() + + golangApiServerConfPath = components.PrepareGolangApiServerConfig(dbUrl, components.Ports[GolangAPIServer], components.Ports[GolangServiceBroker], + fakeCCNOAAUAA.URL(), false, 200, fmt.Sprintf("https://127.0.0.1:%d", components.Ports[Scheduler]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[ScalingEngine]), + fmt.Sprintf("https://127.0.0.1:%d", components.Ports[MetricsCollector]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[EventGenerator]), "https://127.0.0.1:8888", + true, defaultHttpClientTimeout, tmpDir) + startGolangApiServer() + appId = getRandomId() + pathVariables = []string{appId, metricType} + + }) + + AfterEach(func() { + stopGolangApiServer() + stopMetricsCollector() + }) + Describe("Get metrics", func() { + + Context("Cloud Controller api is not available", func() { + BeforeEach(func() { + fakeCCNOAAUAA.Reset() + fakeCCNOAAUAA.AllowUnhandledRequests = true + parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "asc", "page": "1", "results-per-page": "5"} + }) + It("should error with status code 500", func() { + By("check public api") + checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ + "code": "Interal-Server-Error", + "message": "Failed to check space developer permission", + }) + }) + }) + + Context("UAA api is not available", func() { + BeforeEach(func() { + fakeCCNOAAUAA.Reset() + fakeCCNOAAUAA.AllowUnhandledRequests = true + fakeCCNOAAUAA.RouteToHandler("GET", "/v2/info", ghttp.RespondWithJSONEncoded(http.StatusOK, + cf.Endpoints{ + AuthEndpoint: fakeCCNOAAUAA.URL(), + TokenEndpoint: fakeCCNOAAUAA.URL(), + DopplerEndpoint: strings.Replace(fakeCCNOAAUAA.URL(), "http", "ws", 1), + })) + parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "asc", "page": "1", "results-per-page": "5"} + }) + It("should error with status code 500", func() { + By("check public api") + checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ + "code": "Interal-Server-Error", + "message": "Failed to check space developer permission", + }) + }) + }) + Context("UAA api returns 401", func() { + BeforeEach(func() { + fakeCCNOAAUAA.Reset() + fakeCCNOAAUAA.AllowUnhandledRequests = true + fakeCCNOAAUAA.RouteToHandler("GET", "/v2/info", ghttp.RespondWithJSONEncoded(http.StatusOK, + cf.Endpoints{ + AuthEndpoint: fakeCCNOAAUAA.URL(), + TokenEndpoint: fakeCCNOAAUAA.URL(), + DopplerEndpoint: strings.Replace(fakeCCNOAAUAA.URL(), "http", "ws", 1), + })) + fakeCCNOAAUAA.RouteToHandler("POST", "/check_token", ghttp.RespondWithJSONEncoded(http.StatusOK, + struct { + Scope []string `json:"scope"` + }{ + []string{"cloud_controller.read", "cloud_controller.write", "password.write", "openid", "network.admin", "network.write", "uaa.user"}, + })) + fakeCCNOAAUAA.RouteToHandler("GET", "/userinfo", ghttp.RespondWithJSONEncoded(http.StatusUnauthorized, struct{}{})) + parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "asc", "page": "1", "results-per-page": "5"} + }) + It("should error with status code 401", func() { + By("check public api") + checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], + pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{ + "code": "Unauthorized", + "message": "You are not authorized to perform the requested action", + }) + }) + }) + + Context("Check permission not passed", func() { + BeforeEach(func() { + fakeCCNOAAUAA.RouteToHandler("GET", checkUserSpaceRegPath, ghttp.RespondWithJSONEncoded(http.StatusOK, + struct { + TotalResults int `json:"total_results"` + }{ + 0, + })) + parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "asc", "page": "1", "results-per-page": "5"} + }) + It("should error with status code 401", func() { + By("check public api") + checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], + pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{ + "code": "Unauthorized", + "message": "You are not authorized to perform the requested action", + }) + }) + }) + + Context("MetricsCollector is down", func() { + JustBeforeEach(func() { + stopMetricsCollector() + parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "asc", "page": "1", "results-per-page": "5"} + }) + + It("should error with status code 500", func() { + By("check internal api") + checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ + "code": "Interal-Server-Error", + "message": "Error retrieving metrics history from metricscollector", + }) + By("check public api") + checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ + "code": "Interal-Server-Error", + "message": "Error retrieving metrics history from metricscollector", + }) + + }) + + }) + + Context("Get metrics", func() { + BeforeEach(func() { + metric = &models.AppInstanceMetric{ + AppId: appId, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + } + + metric.Timestamp = 666666 + metric.InstanceIndex = 0 + insertAppInstanceMetric(metric) + + metric.Timestamp = 555555 + metric.InstanceIndex = 1 + insertAppInstanceMetric(metric) + + metric.Timestamp = 555555 + metric.InstanceIndex = 0 + insertAppInstanceMetric(metric) + + metric.Timestamp = 333333 + metric.InstanceIndex = 0 + insertAppInstanceMetric(metric) + + metric.Timestamp = 444444 + metric.InstanceIndex = 1 + insertAppInstanceMetric(metric) + + //add some other metric-type + metric.Name = models.MetricNameThroughput + metric.Unit = models.UnitNum + metric.Timestamp = 444444 + metric.InstanceIndex = 1 + insertAppInstanceMetric(metric) + //add some other appId + metric.AppId = "some-other-app-id" + metric.Name = models.MetricNameMemoryUsed + metric.Unit = models.UnitMegaBytes + metric.Timestamp = 444444 + metric.InstanceIndex = 1 + insertAppInstanceMetric(metric) + }) + Context("instance-index is not provided", func() { + It("should get the metrics of all instances", func() { + By("get the 1st page") + parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "1", "results-per-page": "2"} + result := AppInstanceMetricResult{ + TotalResults: 5, + TotalPages: 3, + Page: 1, + NextUrl: getInstanceMetricsUrl(appId, metricType, parameters, 2), + Resources: []models.AppInstanceMetric{ + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 0, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 333333, + }, + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 1, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 444444, + }, + }, + } + + By("check public api") + checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("get the 2nd page") + parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "2", "results-per-page": "2"} + result = AppInstanceMetricResult{ + TotalResults: 5, + TotalPages: 3, + Page: 2, + PrevUrl: getInstanceMetricsUrl(appId, metricType, parameters, 1), + NextUrl: getInstanceMetricsUrl(appId, metricType, parameters, 3), + Resources: []models.AppInstanceMetric{ + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 0, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 555555, + }, + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 1, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 555555, + }, + }, + } + By("check public api") + checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("get the 3rd page") + parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "3", "results-per-page": "2"} + result = AppInstanceMetricResult{ + TotalResults: 5, + TotalPages: 3, + Page: 3, + PrevUrl: getInstanceMetricsUrl(appId, metricType, parameters, 2), + Resources: []models.AppInstanceMetric{ + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 0, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 666666, + }, + }, + } + By("check public api") + checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("the 4th page should be empty") + parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "4", "results-per-page": "2"} + result = AppInstanceMetricResult{ + TotalResults: 5, + TotalPages: 3, + Page: 4, + PrevUrl: getInstanceMetricsUrl(appId, metricType, parameters, 3), + Resources: []models.AppInstanceMetric{}, + } + By("check public api") + checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("the 5th page should be empty") + parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "5", "results-per-page": "2"} + result = AppInstanceMetricResult{ + TotalResults: 5, + TotalPages: 3, + Page: 5, + Resources: []models.AppInstanceMetric{}, + } + By("check public api") + checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + }) + }) + Context("instance-index is provided", func() { + It("should get the metrics of the instance", func() { + By("get the 1st page") + parameters = map[string]string{"instance-index": "1", "start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "1", "results-per-page": "2"} + result := AppInstanceMetricResult{ + TotalResults: 2, + TotalPages: 1, + Page: 1, + Resources: []models.AppInstanceMetric{ + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 1, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 444444, + }, + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 1, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 555555, + }, + }, + } + + By("check public api") + checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("get the 2nd page") + parameters = map[string]string{"instance-index": "1", "start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "2", "results-per-page": "2"} + result = AppInstanceMetricResult{ + TotalResults: 2, + TotalPages: 1, + Page: 2, + PrevUrl: getInstanceMetricsUrlWithInstanceIndex(appId, metricType, parameters, 1), + Resources: []models.AppInstanceMetric{}, + } + By("check public api") + checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + }) + }) + + }) + }) +}) diff --git a/src/integration/integration_golangapi_scalingengine_test.go b/src/integration/integration_golangapi_scalingengine_test.go new file mode 100644 index 000000000..1c003fc4e --- /dev/null +++ b/src/integration/integration_golangapi_scalingengine_test.go @@ -0,0 +1,293 @@ +package integration + +import ( + "autoscaler/cf" + "autoscaler/models" + "fmt" + "net/http" + "strings" + + . "github.com/onsi/ginkgo" + "github.com/onsi/gomega/ghttp" +) + +var _ = Describe("Integration_GolangApi_ScalingEngine", func() { + var ( + initInstanceCount int = 2 + appId string + pathVariables []string + parameters map[string]string + history *models.AppScalingHistory + ) + + BeforeEach(func() { + initializeHttpClient("api.crt", "api.key", "autoscaler-ca.crt", apiScalingEngineHttpRequestTimeout) + initializeHttpClientForPublicApi("api_public.crt", "api_public.key", "autoscaler-ca.crt", apiMetricsCollectorHttpRequestTimeout) + startFakeCCNOAAUAA(initInstanceCount) + scalingEngineConfPath = components.PrepareScalingEngineConfig(dbUrl, components.Ports[ScalingEngine], fakeCCNOAAUAA.URL(), defaultHttpClientTimeout, tmpDir) + startScalingEngine() + + golangApiServerConfPath = components.PrepareGolangApiServerConfig(dbUrl, components.Ports[GolangAPIServer], components.Ports[GolangServiceBroker], + fakeCCNOAAUAA.URL(), false, 200, fmt.Sprintf("https://127.0.0.1:%d", components.Ports[Scheduler]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[ScalingEngine]), + fmt.Sprintf("https://127.0.0.1:%d", components.Ports[MetricsCollector]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[EventGenerator]), "https://127.0.0.1:8888", + true, defaultHttpClientTimeout, tmpDir) + startGolangApiServer() + appId = getRandomId() + pathVariables = []string{appId} + + }) + + AfterEach(func() { + stopGolangApiServer() + stopScalingEngine() + }) + Describe("Get scaling histories", func() { + + Context("Cloud Controller api is not available", func() { + BeforeEach(func() { + fakeCCNOAAUAA.Reset() + fakeCCNOAAUAA.AllowUnhandledRequests = true + parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "desc", "page": "1", "results-per-page": "5"} + }) + It("should error with status code 500", func() { + By("check public api") + checkPublicAPIResponseContentWithParameters(getScalingHistories, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ + "code": "Interal-Server-Error", + "message": "Failed to check space developer permission", + }) + }) + }) + + Context("UAA api is not available", func() { + BeforeEach(func() { + fakeCCNOAAUAA.Reset() + fakeCCNOAAUAA.AllowUnhandledRequests = true + fakeCCNOAAUAA.RouteToHandler("GET", "/v2/info", ghttp.RespondWithJSONEncoded(http.StatusOK, + cf.Endpoints{ + AuthEndpoint: fakeCCNOAAUAA.URL(), + TokenEndpoint: fakeCCNOAAUAA.URL(), + DopplerEndpoint: strings.Replace(fakeCCNOAAUAA.URL(), "http", "ws", 1), + })) + parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "desc", "page": "1", "results-per-page": "5"} + }) + It("should error with status code 500", func() { + By("check public api") + checkPublicAPIResponseContentWithParameters(getScalingHistories, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ + "code": "Interal-Server-Error", + "message": "Failed to check space developer permission", + }) + }) + }) + + Context("UAA api returns 401", func() { + BeforeEach(func() { + fakeCCNOAAUAA.Reset() + fakeCCNOAAUAA.AllowUnhandledRequests = true + fakeCCNOAAUAA.RouteToHandler("GET", "/v2/info", ghttp.RespondWithJSONEncoded(http.StatusOK, + cf.Endpoints{ + AuthEndpoint: fakeCCNOAAUAA.URL(), + TokenEndpoint: fakeCCNOAAUAA.URL(), + DopplerEndpoint: strings.Replace(fakeCCNOAAUAA.URL(), "http", "ws", 1), + })) + fakeCCNOAAUAA.RouteToHandler("POST", "/check_token", ghttp.RespondWithJSONEncoded(http.StatusOK, + struct { + Scope []string `json:"scope"` + }{ + []string{"cloud_controller.read", "cloud_controller.write", "password.write", "openid", "network.admin", "network.write", "uaa.user"}, + })) + fakeCCNOAAUAA.RouteToHandler("GET", "/userinfo", ghttp.RespondWithJSONEncoded(http.StatusUnauthorized, struct{}{})) + parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "desc", "page": "1", "results-per-page": "5"} + }) + It("should error with status code 401", func() { + By("check public api") + checkPublicAPIResponseContentWithParameters(getScalingHistories, components.Ports[GolangAPIServer], + pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{ + "code": "Unauthorized", + "message": "You are not authorized to perform the requested action", + }) + }) + }) + + Context("Check permission not passed", func() { + BeforeEach(func() { + fakeCCNOAAUAA.RouteToHandler("GET", checkUserSpaceRegPath, ghttp.RespondWithJSONEncoded(http.StatusOK, + struct { + TotalResults int `json:"total_results"` + }{ + 0, + })) + parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "desc", "page": "1", "results-per-page": "5"} + }) + It("should error with status code 401", func() { + By("check public api") + checkPublicAPIResponseContentWithParameters(getScalingHistories, components.Ports[GolangAPIServer], + pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{ + "code": "Unauthorized", + "message": "You are not authorized to perform the requested action", + }) + }) + }) + + Context("ScalingEngine is down", func() { + JustBeforeEach(func() { + stopScalingEngine() + parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "desc", "page": "1", "results-per-page": "5"} + }) + + It("should error with status code 500", func() { + By("check public api") + checkPublicAPIResponseContentWithParameters(getScalingHistories, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ + "message": "Error retrieving scaling history from scaling engine", + "code": "Interal-Server-Error", + }) + + }) + + }) + + Context("Get scaling histories", func() { + BeforeEach(func() { + history = &models.AppScalingHistory{ + AppId: appId, + OldInstances: 2, + NewInstances: 4, + Reason: "a reason", + Message: "a message", + ScalingType: models.ScalingTypeDynamic, + Status: models.ScalingStatusSucceeded, + Error: "", + } + + history.Timestamp = 666666 + insertScalingHistory(history) + + history.Timestamp = 222222 + insertScalingHistory(history) + + history.Timestamp = 555555 + insertScalingHistory(history) + + history.Timestamp = 333333 + insertScalingHistory(history) + + history.Timestamp = 444444 + insertScalingHistory(history) + + //add some other app id + history.AppId = "some-other-app-id" + history.Timestamp = 444444 + insertScalingHistory(history) + + }) + It("should get the scaling histories ", func() { + By("get the 1st page") + parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "desc", "page": "1", "results-per-page": "2"} + result := ScalingHistoryResult{ + TotalResults: 5, + TotalPages: 3, + Page: 1, + NextUrl: getScalingHistoriesUrl(appId, parameters, 2), + Resources: []models.AppScalingHistory{ + models.AppScalingHistory{ + AppId: appId, + Timestamp: 666666, + ScalingType: models.ScalingTypeDynamic, + Status: models.ScalingStatusSucceeded, + OldInstances: 2, + NewInstances: 4, + Reason: "a reason", + Message: "a message", + Error: "", + }, + models.AppScalingHistory{ + AppId: appId, + Timestamp: 555555, + ScalingType: models.ScalingTypeDynamic, + Status: models.ScalingStatusSucceeded, + OldInstances: 2, + NewInstances: 4, + Reason: "a reason", + Message: "a message", + Error: "", + }, + }, + } + By("check public api") + checkScalingHistoryResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("get the 2nd page") + parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "desc", "page": "2", "results-per-page": "2"} + result = ScalingHistoryResult{ + TotalResults: 5, + TotalPages: 3, + Page: 2, + PrevUrl: getScalingHistoriesUrl(appId, parameters, 1), + NextUrl: getScalingHistoriesUrl(appId, parameters, 3), + Resources: []models.AppScalingHistory{ + models.AppScalingHistory{ + AppId: appId, + Timestamp: 444444, + ScalingType: models.ScalingTypeDynamic, + Status: models.ScalingStatusSucceeded, + OldInstances: 2, + NewInstances: 4, + Reason: "a reason", + Message: "a message", + Error: "", + }, + models.AppScalingHistory{ + AppId: appId, + Timestamp: 333333, + ScalingType: models.ScalingTypeDynamic, + Status: models.ScalingStatusSucceeded, + OldInstances: 2, + NewInstances: 4, + Reason: "a reason", + Message: "a message", + Error: "", + }, + }, + } + By("check public api") + checkScalingHistoryResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("get the 3rd page") + parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "desc", "page": "3", "results-per-page": "2"} + result = ScalingHistoryResult{ + TotalResults: 5, + TotalPages: 3, + Page: 3, + PrevUrl: getScalingHistoriesUrl(appId, parameters, 2), + Resources: []models.AppScalingHistory{ + models.AppScalingHistory{ + AppId: appId, + Timestamp: 222222, + ScalingType: models.ScalingTypeDynamic, + Status: models.ScalingStatusSucceeded, + OldInstances: 2, + NewInstances: 4, + Reason: "a reason", + Message: "a message", + Error: "", + }, + }, + } + By("check public api") + checkScalingHistoryResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("the 4th page should be empty") + parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "desc", "page": "4", "results-per-page": "2"} + result = ScalingHistoryResult{ + TotalResults: 5, + TotalPages: 3, + Page: 4, + PrevUrl: getScalingHistoriesUrl(appId, parameters, 3), + Resources: []models.AppScalingHistory{}, + } + By("check public api") + checkScalingHistoryResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + }) + + }) + }) +}) diff --git a/src/integration/integration_golangapi_scheduler_test.go b/src/integration/integration_golangapi_scheduler_test.go new file mode 100644 index 000000000..211f11e7f --- /dev/null +++ b/src/integration/integration_golangapi_scheduler_test.go @@ -0,0 +1,431 @@ +package integration + +import ( + "autoscaler/cf" + "encoding/base64" + "fmt" + "net/http" + "strings" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/ghttp" +) + +var _ = Describe("Integration_GolangApi_Scheduler", func() { + var ( + appId string + policyStr []byte + initInstanceCount int = 2 + serviceInstanceId string + bindingId string + orgId string + spaceId string + ) + + BeforeEach(func() { + startFakeCCNOAAUAA(initInstanceCount) + initializeHttpClient("api.crt", "api.key", "autoscaler-ca.crt", apiSchedulerHttpRequestTimeout) + initializeHttpClientForPublicApi("api_public.crt", "api_public.key", "autoscaler-ca.crt", apiMetricsCollectorHttpRequestTimeout) + + schedulerConfPath = components.PrepareSchedulerConfig(dbUrl, fmt.Sprintf("https://127.0.0.1:%d", components.Ports[ScalingEngine]), tmpDir, defaultHttpClientTimeout) + startScheduler() + + serviceInstanceId = getRandomId() + orgId = getRandomId() + spaceId = getRandomId() + bindingId = getRandomId() + appId = getRandomId() + brokerAuth = base64.StdEncoding.EncodeToString([]byte("username:password")) + }) + + AfterEach(func() { + stopScheduler() + }) + + Describe("When offered as a service", func() { + + BeforeEach(func() { + golangApiServerConfPath = components.PrepareGolangApiServerConfig(dbUrl, components.Ports[GolangAPIServer], components.Ports[GolangServiceBroker], + fakeCCNOAAUAA.URL(), false, 200, fmt.Sprintf("https://127.0.0.1:%d", components.Ports[Scheduler]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[ScalingEngine]), + fmt.Sprintf("https://127.0.0.1:%d", components.Ports[MetricsCollector]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[EventGenerator]), "https://127.0.0.1:8888", + false, defaultHttpClientTimeout, tmpDir) + startGolangApiServer() + + resp, err := detachPolicy(appId, components.Ports[GolangAPIServer], httpClientForPublicApi) + Expect(err).NotTo(HaveOccurred()) + resp.Body.Close() + }) + AfterEach(func() { + stopGolangApiServer() + }) + + Context("Cloud Controller api is not available", func() { + BeforeEach(func() { + fakeCCNOAAUAA.Reset() + fakeCCNOAAUAA.AllowUnhandledRequests = true + }) + Context("Create policy", func() { + It("should error with status code 500", func() { + By("check public api") + policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + doAttachPolicy(appId, policyStr, http.StatusInternalServerError, components.Ports[GolangAPIServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusInternalServerError, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + }) + Context("Delete policy", func() { + BeforeEach(func() { + policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + doAttachPolicy(appId, policyStr, http.StatusInternalServerError, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + + It("should error with status code 500", func() { + doDetachPolicy(appId, http.StatusInternalServerError, "", components.Ports[GolangAPIServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusInternalServerError, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + }) + + }) + + Context("UAA api is not available", func() { + BeforeEach(func() { + fakeCCNOAAUAA.Reset() + fakeCCNOAAUAA.AllowUnhandledRequests = true + fakeCCNOAAUAA.RouteToHandler("GET", "/v2/info", ghttp.RespondWithJSONEncoded(http.StatusOK, + cf.Endpoints{ + TokenEndpoint: fakeCCNOAAUAA.URL(), + DopplerEndpoint: strings.Replace(fakeCCNOAAUAA.URL(), "http", "ws", 1), + })) + }) + Context("Create policy", func() { + It("should error with status code 500", func() { + By("check public api") + policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + doAttachPolicy(appId, policyStr, http.StatusInternalServerError, components.Ports[GolangAPIServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusInternalServerError, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + }) + Context("Delete policy", func() { + BeforeEach(func() { + policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + doAttachPolicy(appId, policyStr, http.StatusInternalServerError, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + + It("should error with status code 500", func() { + doDetachPolicy(appId, http.StatusInternalServerError, "", components.Ports[GolangAPIServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusInternalServerError, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + }) + + }) + + Context("UAA api returns 401", func() { + BeforeEach(func() { + fakeCCNOAAUAA.Reset() + fakeCCNOAAUAA.AllowUnhandledRequests = true + fakeCCNOAAUAA.RouteToHandler("GET", "/v2/info", ghttp.RespondWithJSONEncoded(http.StatusOK, + cf.Endpoints{ + TokenEndpoint: fakeCCNOAAUAA.URL(), + DopplerEndpoint: strings.Replace(fakeCCNOAAUAA.URL(), "http", "ws", 1), + })) + fakeCCNOAAUAA.RouteToHandler("POST", "/check_token", ghttp.RespondWithJSONEncoded(http.StatusOK, + struct { + Scope []string `json:"scope"` + }{ + []string{"cloud_controller.read", "cloud_controller.write", "password.write", "openid", "network.admin", "network.write", "uaa.user"}, + })) + fakeCCNOAAUAA.RouteToHandler("GET", "/userinfo", ghttp.RespondWithJSONEncoded(http.StatusUnauthorized, struct{}{})) + }) + Context("Create policy", func() { + It("should error with status code 401", func() { + By("check public api") + policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + doAttachPolicy(appId, policyStr, http.StatusUnauthorized, components.Ports[GolangAPIServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusUnauthorized, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + }) + Context("Delete policy", func() { + BeforeEach(func() { + policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + doAttachPolicy(appId, policyStr, http.StatusUnauthorized, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + + It("should error with status code 401", func() { + doDetachPolicy(appId, http.StatusUnauthorized, "", components.Ports[GolangAPIServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusUnauthorized, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + }) + + }) + + Context("Check permission not passed", func() { + BeforeEach(func() { + fakeCCNOAAUAA.RouteToHandler("GET", checkUserSpaceRegPath, ghttp.RespondWithJSONEncoded(http.StatusOK, + struct { + TotalResults int `json:"total_results"` + }{ + 0, + })) + }) + Context("Create policy", func() { + It("should error with status code 401", func() { + By("check public api") + policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + doAttachPolicy(appId, policyStr, http.StatusUnauthorized, components.Ports[GolangAPIServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusUnauthorized, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + }) + Context("Delete policy", func() { + BeforeEach(func() { + policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + doAttachPolicy(appId, policyStr, http.StatusUnauthorized, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + + It("should error with status code 401", func() { + doDetachPolicy(appId, http.StatusUnauthorized, "", components.Ports[GolangAPIServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusUnauthorized, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + }) + + }) + + Context("Scheduler is down", func() { + + JustBeforeEach(func() { + stopScheduler() + }) + BeforeEach(func() { + provisionAndBind(serviceInstanceId, orgId, spaceId, bindingId, appId, nil, components.Ports[GolangServiceBroker], httpClientForPublicApi) + }) + + Context("Create policy", func() { + Context("public api", func() { + It("should create policy", func() { + policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + }) + + }) + + Context("Delete policy", func() { + Context("public api", func() { + BeforeEach(func() { + //attach a policy first with 4 recurring and 2 specific_date schedules + policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + + It("should delete policy in API server", func() { + doDetachPolicy(appId, http.StatusInternalServerError, "", components.Ports[GolangAPIServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusNotFound, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + }) + + }) + + }) + + Describe("Create policy", func() { + BeforeEach(func() { + provisionAndBind(serviceInstanceId, orgId, spaceId, bindingId, appId, nil, components.Ports[GolangServiceBroker], httpClientForPublicApi) + }) + AfterEach(func() { + unbindAndDeprovision(bindingId, appId, serviceInstanceId, components.Ports[GolangServiceBroker], httpClientForPublicApi) + }) + Context("public api", func() { + Context("Policies with schedules", func() { + It("creates a policy and associated schedules", func() { + policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + + doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) + checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) + Expect(checkSchedule(appId, http.StatusOK, map[string]int{"recurring_schedule": 4, "specific_date": 2})).To(BeTrue()) + }) + + It("fails with an invalid policy", func() { + policyStr = readPolicyFromFile("fakeInvalidPolicy.json") + + doAttachPolicy(appId, policyStr, http.StatusBadRequest, components.Ports[GolangAPIServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusNotFound, components.Ports[GolangAPIServer], httpClientForPublicApi) + checkSchedulerStatus(appId, http.StatusNotFound) + }) + }) + + Context("Policies without schedules", func() { + It("creates only the policy", func() { + policyStr = readPolicyFromFile("fakePolicyWithoutSchedule.json") + + doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) + checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) + checkSchedulerStatus(appId, http.StatusNotFound) + + }) + }) + }) + + }) + + Describe("Update policy", func() { + BeforeEach(func() { + provisionAndBind(serviceInstanceId, orgId, spaceId, bindingId, appId, nil, components.Ports[GolangServiceBroker], httpClientForPublicApi) + }) + AfterEach(func() { + unbindAndDeprovision(bindingId, appId, serviceInstanceId, components.Ports[GolangServiceBroker], httpClientForPublicApi) + }) + Context("public api", func() { + Context("Update policies with schedules", func() { + BeforeEach(func() { + //attach a policy first with 4 recurring and 2 specific_date schedules + policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + + doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + + It("updates the policy and schedules", func() { + //attach another policy with 3 recurring and 1 specific_date schedules + policyStr = readPolicyFromFile("fakePolicyWithScheduleAnother.json") + + doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) + checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) + Expect(checkSchedule(appId, http.StatusOK, map[string]int{"recurring_schedule": 3, "specific_date": 1})).To(BeTrue()) + }) + }) + }) + + }) + + Describe("Delete Policies", func() { + BeforeEach(func() { + provisionAndBind(serviceInstanceId, orgId, spaceId, bindingId, appId, nil, components.Ports[GolangServiceBroker], httpClientForPublicApi) + }) + AfterEach(func() { + unbindAndDeprovision(bindingId, appId, serviceInstanceId, components.Ports[GolangServiceBroker], httpClientForPublicApi) + }) + + Context("public api", func() { + Context("for a non-existing app", func() { + It("Should return ok", func() { + doDetachPolicy(appId, http.StatusOK, `{}`, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + }) + + Context("with an existing app", func() { + BeforeEach(func() { + //attach a policy first with 4 recurring and 2 specific_date schedules + policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + + It("deletes the policy and schedules", func() { + doDetachPolicy(appId, http.StatusOK, "", components.Ports[GolangAPIServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusNotFound, components.Ports[GolangAPIServer], httpClientForPublicApi) + checkSchedulerStatus(appId, http.StatusNotFound) + }) + }) + }) + + }) + }) + + Describe("When offered as a built-in experience", func() { + BeforeEach(func() { + golangApiServerConfPath = components.PrepareGolangApiServerConfig(dbUrl, components.Ports[GolangAPIServer], components.Ports[GolangServiceBroker], + fakeCCNOAAUAA.URL(), false, 200, fmt.Sprintf("https://127.0.0.1:%d", components.Ports[Scheduler]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[ScalingEngine]), + fmt.Sprintf("https://127.0.0.1:%d", components.Ports[MetricsCollector]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[EventGenerator]), "https://127.0.0.1:8888", + true, defaultHttpClientTimeout, tmpDir) + startGolangApiServer() + + resp, err := detachPolicy(appId, components.Ports[GolangAPIServer], httpClientForPublicApi) + Expect(err).NotTo(HaveOccurred()) + resp.Body.Close() + }) + AfterEach(func() { + stopGolangApiServer() + }) + + Describe("Create policy", func() { + Context("public api", func() { + Context("Policies with schedules", func() { + It("creates a policy and associated schedules", func() { + policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + + doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) + checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) + Expect(checkSchedule(appId, http.StatusOK, map[string]int{"recurring_schedule": 4, "specific_date": 2})).To(BeTrue()) + }) + + It("fails with an invalid policy", func() { + policyStr = readPolicyFromFile("fakeInvalidPolicy.json") + + doAttachPolicy(appId, policyStr, http.StatusBadRequest, components.Ports[GolangAPIServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusNotFound, components.Ports[GolangAPIServer], httpClientForPublicApi) + checkSchedulerStatus(appId, http.StatusNotFound) + }) + + }) + + Context("Policies without schedules", func() { + It("creates only the policy", func() { + policyStr = readPolicyFromFile("fakePolicyWithoutSchedule.json") + + doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) + checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) + checkSchedulerStatus(appId, http.StatusNotFound) + + }) + }) + }) + + }) + + Describe("Update policy", func() { + Context("public api", func() { + Context("Update policies with schedules", func() { + BeforeEach(func() { + //attach a policy first with 4 recurring and 2 specific_date schedules + policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + + It("updates the policy and schedules", func() { + //attach another policy with 3 recurring and 1 specific_date schedules + policyStr = readPolicyFromFile("fakePolicyWithScheduleAnother.json") + + doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) + checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) + Expect(checkSchedule(appId, http.StatusOK, map[string]int{"recurring_schedule": 3, "specific_date": 1})).To(BeTrue()) + }) + }) + }) + + }) + + Describe("Delete Policies", func() { + Context("public api", func() { + Context("for a non-existing app", func() { + It("Should return OK", func() { + doDetachPolicy(appId, http.StatusOK, `{}`, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + }) + + Context("with an existing app", func() { + BeforeEach(func() { + //attach a policy first with 4 recurring and 2 specific_date schedules + policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) + }) + + It("deletes the policy and schedules", func() { + doDetachPolicy(appId, http.StatusOK, "", components.Ports[GolangAPIServer], httpClientForPublicApi) + checkApiServerStatus(appId, http.StatusNotFound, components.Ports[GolangAPIServer], httpClientForPublicApi) + checkSchedulerStatus(appId, http.StatusNotFound) + }) + }) + }) + + }) + + }) +}) diff --git a/src/integration/integration_operator_others_test.go b/src/integration/integration_operator_others_test.go index 198a918a0..e7004a944 100644 --- a/src/integration/integration_operator_others_test.go +++ b/src/integration/integration_operator_others_test.go @@ -43,7 +43,7 @@ var _ = Describe("Integration_Operator_Others", func() { }) AfterEach(func() { - detachPolicy(testAppId, INTERNAL) + detachPolicy(testAppId, components.Ports[APIServer], httpClient) stopScheduler() stopScalingEngine() stopOperator() @@ -63,7 +63,7 @@ var _ = Describe("Integration_Operator_Others", func() { JustBeforeEach(func() { policyStr = setPolicySpecificDateTime(readPolicyFromFile("fakePolicyWithSpecificDateSchedule.json"), 70*time.Second, 2*time.Hour) - doAttachPolicy(testAppId, []byte(policyStr), http.StatusCreated, INTERNAL) + doAttachPolicy(testAppId, []byte(policyStr), http.StatusCreated, components.Ports[APIServer], httpClient) }) It("should sync the active schedule to scaling engine after restart", func() { @@ -86,7 +86,7 @@ var _ = Describe("Integration_Operator_Others", func() { Context("Delete an active schedule", func() { BeforeEach(func() { policyStr = setPolicySpecificDateTime(readPolicyFromFile("fakePolicyWithSpecificDateSchedule.json"), 70*time.Second, 140*time.Second) - doAttachPolicy(testAppId, []byte(policyStr), http.StatusCreated, INTERNAL) + doAttachPolicy(testAppId, []byte(policyStr), http.StatusCreated, components.Ports[APIServer], httpClient) time.Sleep(70 * time.Second) Consistently(func() bool { @@ -163,7 +163,7 @@ var _ = Describe("Integration_Operator_Others", func() { Context("when update a policy to another schedule sets only in policy DB without any update in scheduler ", func() { BeforeEach(func() { - doAttachPolicy(testAppId, []byte(policyStr), http.StatusCreated, INTERNAL) + doAttachPolicy(testAppId, []byte(policyStr), http.StatusCreated, components.Ports[APIServer], httpClient) Expect(checkSchedule(testAppId, http.StatusOK, map[string]int{"recurring_schedule": 4, "specific_date": 2})).To(BeTrue()) newPolicyStr := string(readPolicyFromFile("fakePolicyWithScheduleAnother.json")) diff --git a/src/integration/integration_suite_test.go b/src/integration/integration_suite_test.go index 1e28192ed..4e455c651 100644 --- a/src/integration/integration_suite_test.go +++ b/src/integration/integration_suite_test.go @@ -52,6 +52,7 @@ var ( tmpDir string serviceBrokerConfPath string apiServerConfPath string + golangApiServerConfPath string schedulerConfPath string metricsCollectorConfPath string eventGeneratorConfPath string @@ -187,14 +188,19 @@ func CompileTestedExecutables() Executables { builtExecutables[MetricsServerHTTP], err = gexec.BuildIn(rootDir, "autoscaler/metricsserver/cmd/metricsserver", "-race") Expect(err).NotTo(HaveOccurred()) + builtExecutables[GolangAPIServer], err = gexec.BuildIn(rootDir, "autoscaler/api/cmd/api", "-race") + Expect(err).NotTo(HaveOccurred()) + return builtExecutables } func PreparePorts() Ports { return Ports{ APIServer: 10000 + GinkgoParallelNode(), + GolangAPIServer: 22000 + GinkgoParallelNode(), APIPublicServer: 12000 + GinkgoParallelNode(), ServiceBroker: 13000 + GinkgoParallelNode(), + GolangServiceBroker: 23000 + GinkgoParallelNode(), ServiceBrokerInternal: 14000 + GinkgoParallelNode(), Scheduler: 15000 + GinkgoParallelNode(), MetricsCollector: 16000 + GinkgoParallelNode(), @@ -213,6 +219,12 @@ func startApiServer() *ginkgomon.Runner { return runner } +func startGolangApiServer() { + processMap[GolangAPIServer] = ginkgomon.Invoke(grouper.NewOrdered(os.Interrupt, grouper.Members{ + {GolangAPIServer, components.GolangAPIServer(golangApiServerConfPath)}, + })) +} + func startServiceBroker() *ginkgomon.Runner { runner := components.ServiceBroker(serviceBrokerConfPath) processMap[ServiceBroker] = ginkgomon.Invoke(grouper.NewOrdered(os.Interrupt, grouper.Members{ @@ -266,6 +278,9 @@ func startMetricsServer() { func stopApiServer() { ginkgomon.Kill(processMap[APIServer], 5*time.Second) } +func stopGolangApiServer() { + ginkgomon.Kill(processMap[GolangAPIServer], 5*time.Second) +} func stopScheduler() { ginkgomon.Kill(processMap[Scheduler], 5*time.Second) } @@ -336,130 +351,101 @@ func initializeHttpClientForPublicApi(certFileName string, keyFileName string, c httpClientForPublicApi.Timeout = httpRequestTimeout } -func provisionServiceInstance(serviceInstanceId string, orgId string, spaceId string) (*http.Response, error) { - req, err := http.NewRequest("PUT", fmt.Sprintf("https://127.0.0.1:%d/v2/service_instances/%s", components.Ports[ServiceBroker], serviceInstanceId), strings.NewReader(fmt.Sprintf(`{"organization_guid":"%s","space_guid":"%s"}`, orgId, spaceId))) +func provisionServiceInstance(serviceInstanceId string, orgId string, spaceId string, brokerPort int, httpClient *http.Client) (*http.Response, error) { + req, err := http.NewRequest("PUT", fmt.Sprintf("https://127.0.0.1:%d/v2/service_instances/%s", brokerPort, serviceInstanceId), strings.NewReader(fmt.Sprintf(`{"organization_guid":"%s","space_guid":"%s","service_id":"app-autoscaler","plan_id":"free"}`, orgId, spaceId))) Expect(err).NotTo(HaveOccurred()) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Basic "+brokerAuth) return httpClient.Do(req) } -func deprovisionServiceInstance(serviceInstanceId string) (*http.Response, error) { - req, err := http.NewRequest("DELETE", fmt.Sprintf("https://127.0.0.1:%d/v2/service_instances/%s", components.Ports[ServiceBroker], serviceInstanceId), strings.NewReader("")) +func deprovisionServiceInstance(serviceInstanceId string, brokerPort int, httpClient *http.Client) (*http.Response, error) { + req, err := http.NewRequest("DELETE", fmt.Sprintf("https://127.0.0.1:%d/v2/service_instances/%s", brokerPort, serviceInstanceId), strings.NewReader(`{"service_id":"app-autoscaler","plan_id":"free"}`)) Expect(err).NotTo(HaveOccurred()) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Basic "+brokerAuth) return httpClient.Do(req) } -func bindService(bindingId string, appId string, serviceInstanceId string, policy []byte) (*http.Response, error) { +func bindService(bindingId string, appId string, serviceInstanceId string, policy []byte, brokerPort int, httpClient *http.Client) (*http.Response, error) { var bindBody map[string]interface{} if policy != nil { rawParameters := json.RawMessage(policy) bindBody = map[string]interface{}{ "app_guid": appId, + "service_id": "app-autoscaler", + "plan_id": "free", "parameters": &rawParameters, } } else { bindBody = map[string]interface{}{ - "app_guid": appId, + "app_guid": appId, + "service_id": "app-autoscaler", + "plan_id": "free", } } body, err := json.Marshal(bindBody) - req, err := http.NewRequest("PUT", fmt.Sprintf("https://127.0.0.1:%d/v2/service_instances/%s/service_bindings/%s", components.Ports[ServiceBroker], serviceInstanceId, bindingId), bytes.NewReader(body)) + req, err := http.NewRequest("PUT", fmt.Sprintf("https://127.0.0.1:%d/v2/service_instances/%s/service_bindings/%s", brokerPort, serviceInstanceId, bindingId), bytes.NewReader(body)) Expect(err).NotTo(HaveOccurred()) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Basic "+brokerAuth) return httpClient.Do(req) } -func unbindService(bindingId string, appId string, serviceInstanceId string) (*http.Response, error) { - req, err := http.NewRequest("DELETE", fmt.Sprintf("https://127.0.0.1:%d/v2/service_instances/%s/service_bindings/%s", components.Ports[ServiceBroker], serviceInstanceId, bindingId), strings.NewReader(fmt.Sprintf(`{"app_guid":"%s"}`, appId))) +func unbindService(bindingId string, appId string, serviceInstanceId string, brokerPort int, httpClient *http.Client) (*http.Response, error) { + req, err := http.NewRequest("DELETE", fmt.Sprintf("https://127.0.0.1:%d/v2/service_instances/%s/service_bindings/%s", brokerPort, serviceInstanceId, bindingId), strings.NewReader(fmt.Sprintf(`{"app_guid":"%s","service_id":"app-autoscaler","plan_id":"free"}`, appId))) Expect(err).NotTo(HaveOccurred()) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Basic "+brokerAuth) return httpClient.Do(req) } -func provisionAndBind(serviceInstanceId string, orgId string, spaceId string, bindingId string, appId string, policy []byte) { - resp, err := provisionServiceInstance(serviceInstanceId, orgId, spaceId) +func provisionAndBind(serviceInstanceId string, orgId string, spaceId string, bindingId string, appId string, policy []byte, brokerPort int, httpClient *http.Client) { + resp, err := provisionServiceInstance(serviceInstanceId, orgId, spaceId, brokerPort, httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) resp.Body.Close() - resp, err = bindService(bindingId, appId, serviceInstanceId, policy) + resp, err = bindService(bindingId, appId, serviceInstanceId, policy, brokerPort, httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusCreated)) resp.Body.Close() } -func unbindAndDeprovision(bindingId string, appId string, serviceInstanceId string) { - resp, err := unbindService(bindingId, appId, serviceInstanceId) +func unbindAndDeprovision(bindingId string, appId string, serviceInstanceId string, brokerPort int, httpClient *http.Client) { + resp, err := unbindService(bindingId, appId, serviceInstanceId, brokerPort, httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusOK)) resp.Body.Close() - resp, err = deprovisionServiceInstance(serviceInstanceId) + resp, err = deprovisionServiceInstance(serviceInstanceId, brokerPort, httpClient) Expect(err).NotTo(HaveOccurred()) Expect(resp.StatusCode).To(Equal(http.StatusOK)) resp.Body.Close() } -func getPolicy(appId string, apiType APIType) (*http.Response, error) { - var apiServerPort int - var httpClientTmp *http.Client - if apiType == INTERNAL { - apiServerPort = components.Ports[APIServer] - httpClientTmp = httpClient - } else { - apiServerPort = components.Ports[APIPublicServer] - httpClientTmp = httpClientForPublicApi - } +func getPolicy(appId string, apiServerPort int, httpClient *http.Client) (*http.Response, error) { + req, err := http.NewRequest("GET", fmt.Sprintf("https://127.0.0.1:%d/v1/apps/%s/policy", apiServerPort, appId), nil) - if apiType == PUBLIC { - req.Header.Set("Authorization", "bearer fake-token") - } + req.Header.Set("Authorization", "bearer fake-token") Expect(err).NotTo(HaveOccurred()) - return httpClientTmp.Do(req) + return httpClient.Do(req) } -func detachPolicy(appId string, apiType APIType) (*http.Response, error) { - var apiServerPort int - var httpClientTmp *http.Client - if apiType == INTERNAL { - apiServerPort = components.Ports[APIServer] - httpClientTmp = httpClient - } else { - apiServerPort = components.Ports[APIPublicServer] - httpClientTmp = httpClientForPublicApi - } +func detachPolicy(appId string, apiServerPort int, httpClient *http.Client) (*http.Response, error) { req, err := http.NewRequest("DELETE", fmt.Sprintf("https://127.0.0.1:%d/v1/apps/%s/policy", apiServerPort, appId), strings.NewReader("")) Expect(err).NotTo(HaveOccurred()) req.Header.Set("Content-Type", "application/json") - if apiType == PUBLIC { - req.Header.Set("Authorization", "bearer fake-token") - } - return httpClientTmp.Do(req) + req.Header.Set("Authorization", "bearer fake-token") + return httpClient.Do(req) } -func attachPolicy(appId string, policy []byte, apiType APIType) (*http.Response, error) { - var apiServerPort int - var httpClientTmp *http.Client - if apiType == INTERNAL { - apiServerPort = components.Ports[APIServer] - httpClientTmp = httpClient - } else { - apiServerPort = components.Ports[APIPublicServer] - httpClientTmp = httpClientForPublicApi - } - +func attachPolicy(appId string, policy []byte, apiServerPort int, httpClient *http.Client) (*http.Response, error) { req, err := http.NewRequest("PUT", fmt.Sprintf("https://127.0.0.1:%d/v1/apps/%s/policy", apiServerPort, appId), bytes.NewReader(policy)) Expect(err).NotTo(HaveOccurred()) req.Header.Set("Content-Type", "application/json") - if apiType == PUBLIC { - req.Header.Set("Authorization", "bearer fake-token") - } - return httpClientTmp.Do(req) + req.Header.Set("Authorization", "bearer fake-token") + return httpClient.Do(req) } func getSchedules(appId string) (*http.Response, error) { @@ -510,10 +496,8 @@ func setPolicySpecificDateTime(policyByte []byte, start time.Duration, end time. return fmt.Sprintf(string(policyByte), timeZone, startTime, endTime) } -func getScalingHistories(pathVariables []string, parameters map[string]string) (*http.Response, error) { - var apiServerPort int +func getScalingHistories(apiServerPort int, pathVariables []string, parameters map[string]string) (*http.Response, error) { var httpClientTmp *http.Client - apiServerPort = components.Ports[APIPublicServer] httpClientTmp = httpClientForPublicApi url := "https://127.0.0.1:%d/v1/apps/%s/scaling_histories" @@ -529,10 +513,8 @@ func getScalingHistories(pathVariables []string, parameters map[string]string) ( req.Header.Set("Authorization", "bearer fake-token") return httpClientTmp.Do(req) } -func getAppInstanceMetrics(pathVariables []string, parameters map[string]string) (*http.Response, error) { - var apiServerPort int +func getAppInstanceMetrics(apiServerPort int, pathVariables []string, parameters map[string]string) (*http.Response, error) { var httpClientTmp *http.Client - apiServerPort = components.Ports[APIPublicServer] httpClientTmp = httpClientForPublicApi url := "https://127.0.0.1:%d/v1/apps/%s/metric_histories/%s" if parameters != nil && len(parameters) > 0 { @@ -548,10 +530,8 @@ func getAppInstanceMetrics(pathVariables []string, parameters map[string]string) return httpClientTmp.Do(req) } -func getAppAggregatedMetrics(pathVariables []string, parameters map[string]string) (*http.Response, error) { - var apiServerPort int +func getAppAggregatedMetrics(apiServerPort int, pathVariables []string, parameters map[string]string) (*http.Response, error) { var httpClientTmp *http.Client - apiServerPort = components.Ports[APIPublicServer] httpClientTmp = httpClientForPublicApi url := "https://127.0.0.1:%d/v1/apps/%s/aggregated_metric_histories/%s" if parameters != nil && len(parameters) > 0 { @@ -680,16 +660,16 @@ func getCredentialsCount(appId string) int { return count } -type GetResponse func(id string, apiType APIType) (*http.Response, error) -type GetResponseWithParameters func(pathVariables []string, parameters map[string]string) (*http.Response, error) +type GetResponse func(id string, port int, httpClient *http.Client) (*http.Response, error) +type GetResponseWithParameters func(apiServerPort int, pathVariables []string, parameters map[string]string) (*http.Response, error) -func checkResponseContent(getResponse GetResponse, id string, expectHttpStatus int, expectResponseMap map[string]interface{}, apiType APIType) { - resp, err := getResponse(id, apiType) +func checkResponseContent(getResponse GetResponse, id string, expectHttpStatus int, expectResponseMap map[string]interface{}, port int, httpClient *http.Client) { + resp, err := getResponse(id, port, httpClient) checkResponse(resp, err, expectHttpStatus, expectResponseMap) } -func checkPublicAPIResponseContentWithParameters(getResponseWithParameters GetResponseWithParameters, pathVariables []string, parameters map[string]string, expectHttpStatus int, expectResponseMap map[string]interface{}) { - resp, err := getResponseWithParameters(pathVariables, parameters) +func checkPublicAPIResponseContentWithParameters(getResponseWithParameters GetResponseWithParameters, apiServerPort int, pathVariables []string, parameters map[string]string, expectHttpStatus int, expectResponseMap map[string]interface{}) { + resp, err := getResponseWithParameters(apiServerPort, pathVariables, parameters) checkResponse(resp, err, expectHttpStatus, expectResponseMap) } func checkResponse(resp *http.Response, err error, expectHttpStatus int, expectResponseMap map[string]interface{}) { From 7df0ec43b02f248e789a631f001d3df2a9e64104 Mon Sep 17 00:00:00 2001 From: qibobo Date: Mon, 26 Aug 2019 15:56:52 +0800 Subject: [PATCH 02/16] add integration test for golangapiserver-metricsserver --- ...ntegration_golangapi_metricsserver_test.go | 359 ++++++++++++++++++ src/integration/integration_suite_test.go | 1 + 2 files changed, 360 insertions(+) create mode 100644 src/integration/integration_golangapi_metricsserver_test.go diff --git a/src/integration/integration_golangapi_metricsserver_test.go b/src/integration/integration_golangapi_metricsserver_test.go new file mode 100644 index 000000000..a25308fa5 --- /dev/null +++ b/src/integration/integration_golangapi_metricsserver_test.go @@ -0,0 +1,359 @@ +package integration + +import ( + "autoscaler/cf" + "autoscaler/models" + "fmt" + "net/http" + "strings" + + . "github.com/onsi/ginkgo" + "github.com/onsi/gomega/ghttp" +) + +var _ = Describe("Integration_GolangApi_MetricsServer", func() { + var ( + appId string + pathVariables []string + parameters map[string]string + metric *models.AppInstanceMetric + metricType string = "memoryused" + initInstanceCount int = 2 + ) + + BeforeEach(func() { + startFakeCCNOAAUAA(initInstanceCount) + fakeMetricsPolling(appId, 400*1024*1024, 600*1024*1024) + initializeHttpClient("api.crt", "api.key", "autoscaler-ca.crt", apiMetricsServerHttpRequestTimeout) + initializeHttpClientForPublicApi("api_public.crt", "api_public.key", "autoscaler-ca.crt", apiMetricsServerHttpRequestTimeout) + metricsServerConfPath = components.PrepareMetricsServerConfig(dbUrl, defaultHttpClientTimeout, components.Ports[MetricsServerHTTP], components.Ports[MetricsServerWS], tmpDir) + startMetricsServer() + + golangApiServerConfPath = components.PrepareGolangApiServerConfig(dbUrl, components.Ports[GolangAPIServer], components.Ports[GolangServiceBroker], + fakeCCNOAAUAA.URL(), false, 200, fmt.Sprintf("https://127.0.0.1:%d", components.Ports[Scheduler]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[ScalingEngine]), + fmt.Sprintf("https://127.0.0.1:%d", components.Ports[MetricsServerHTTP]), fmt.Sprintf("https://127.0.0.1:%d", components.Ports[EventGenerator]), "https://127.0.0.1:8888", + true, defaultHttpClientTimeout, tmpDir) + startGolangApiServer() + appId = getRandomId() + pathVariables = []string{appId, metricType} + + }) + + AfterEach(func() { + stopGolangApiServer() + stopMetricsServer() + }) + Describe("Get metrics", func() { + + Context("Cloud Controller api is not available", func() { + BeforeEach(func() { + fakeCCNOAAUAA.Reset() + fakeCCNOAAUAA.AllowUnhandledRequests = true + parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "asc", "page": "1", "results-per-page": "5"} + }) + It("should error with status code 500", func() { + By("check public api") + checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ + "code": "Interal-Server-Error", + "message": "Failed to check space developer permission", + }) + }) + }) + + Context("UAA api is not available", func() { + BeforeEach(func() { + fakeCCNOAAUAA.Reset() + fakeCCNOAAUAA.AllowUnhandledRequests = true + fakeCCNOAAUAA.RouteToHandler("GET", "/v2/info", ghttp.RespondWithJSONEncoded(http.StatusOK, + cf.Endpoints{ + AuthEndpoint: fakeCCNOAAUAA.URL(), + TokenEndpoint: fakeCCNOAAUAA.URL(), + DopplerEndpoint: strings.Replace(fakeCCNOAAUAA.URL(), "http", "ws", 1), + })) + parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "asc", "page": "1", "results-per-page": "5"} + }) + It("should error with status code 500", func() { + By("check public api") + checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ + "code": "Interal-Server-Error", + "message": "Failed to check space developer permission", + }) + }) + }) + Context("UAA api returns 401", func() { + BeforeEach(func() { + fakeCCNOAAUAA.Reset() + fakeCCNOAAUAA.AllowUnhandledRequests = true + fakeCCNOAAUAA.RouteToHandler("GET", "/v2/info", ghttp.RespondWithJSONEncoded(http.StatusOK, + cf.Endpoints{ + AuthEndpoint: fakeCCNOAAUAA.URL(), + TokenEndpoint: fakeCCNOAAUAA.URL(), + DopplerEndpoint: strings.Replace(fakeCCNOAAUAA.URL(), "http", "ws", 1), + })) + fakeCCNOAAUAA.RouteToHandler("POST", "/check_token", ghttp.RespondWithJSONEncoded(http.StatusOK, + struct { + Scope []string `json:"scope"` + }{ + []string{"cloud_controller.read", "cloud_controller.write", "password.write", "openid", "network.admin", "network.write", "uaa.user"}, + })) + fakeCCNOAAUAA.RouteToHandler("GET", "/userinfo", ghttp.RespondWithJSONEncoded(http.StatusUnauthorized, struct{}{})) + parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "asc", "page": "1", "results-per-page": "5"} + }) + It("should error with status code 401", func() { + By("check public api") + checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], + pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{ + "code": "Unauthorized", + "message": "You are not authorized to perform the requested action", + }) + }) + }) + + Context("Check permission not passed", func() { + BeforeEach(func() { + fakeCCNOAAUAA.RouteToHandler("GET", checkUserSpaceRegPath, ghttp.RespondWithJSONEncoded(http.StatusOK, + struct { + TotalResults int `json:"total_results"` + }{ + 0, + })) + parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "asc", "page": "1", "results-per-page": "5"} + }) + It("should error with status code 401", func() { + By("check public api") + checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], + pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{ + "code": "Unauthorized", + "message": "You are not authorized to perform the requested action", + }) + }) + }) + + Context("MetricsServer is down", func() { + JustBeforeEach(func() { + stopMetricsServer() + parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "asc", "page": "1", "results-per-page": "5"} + }) + + It("should error with status code 500", func() { + By("check internal api") + checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ + "code": "Interal-Server-Error", + "message": "Error retrieving metrics history from metricscollector", + }) + By("check public api") + checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ + "code": "Interal-Server-Error", + "message": "Error retrieving metrics history from metricscollector", + }) + + }) + + }) + + Context("Get metrics", func() { + BeforeEach(func() { + metric = &models.AppInstanceMetric{ + AppId: appId, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + } + + metric.Timestamp = 666666 + metric.InstanceIndex = 0 + insertAppInstanceMetric(metric) + + metric.Timestamp = 555555 + metric.InstanceIndex = 1 + insertAppInstanceMetric(metric) + + metric.Timestamp = 555555 + metric.InstanceIndex = 0 + insertAppInstanceMetric(metric) + + metric.Timestamp = 333333 + metric.InstanceIndex = 0 + insertAppInstanceMetric(metric) + + metric.Timestamp = 444444 + metric.InstanceIndex = 1 + insertAppInstanceMetric(metric) + + //add some other metric-type + metric.Name = models.MetricNameThroughput + metric.Unit = models.UnitNum + metric.Timestamp = 444444 + metric.InstanceIndex = 1 + insertAppInstanceMetric(metric) + //add some other appId + metric.AppId = "some-other-app-id" + metric.Name = models.MetricNameMemoryUsed + metric.Unit = models.UnitMegaBytes + metric.Timestamp = 444444 + metric.InstanceIndex = 1 + insertAppInstanceMetric(metric) + }) + Context("instance-index is not provided", func() { + It("should get the metrics of all instances", func() { + By("get the 1st page") + parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "1", "results-per-page": "2"} + result := AppInstanceMetricResult{ + TotalResults: 5, + TotalPages: 3, + Page: 1, + NextUrl: getInstanceMetricsUrl(appId, metricType, parameters, 2), + Resources: []models.AppInstanceMetric{ + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 0, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 333333, + }, + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 1, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 444444, + }, + }, + } + + By("check public api") + checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("get the 2nd page") + parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "2", "results-per-page": "2"} + result = AppInstanceMetricResult{ + TotalResults: 5, + TotalPages: 3, + Page: 2, + PrevUrl: getInstanceMetricsUrl(appId, metricType, parameters, 1), + NextUrl: getInstanceMetricsUrl(appId, metricType, parameters, 3), + Resources: []models.AppInstanceMetric{ + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 0, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 555555, + }, + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 1, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 555555, + }, + }, + } + By("check public api") + checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("get the 3rd page") + parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "3", "results-per-page": "2"} + result = AppInstanceMetricResult{ + TotalResults: 5, + TotalPages: 3, + Page: 3, + PrevUrl: getInstanceMetricsUrl(appId, metricType, parameters, 2), + Resources: []models.AppInstanceMetric{ + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 0, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 666666, + }, + }, + } + By("check public api") + checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("the 4th page should be empty") + parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "4", "results-per-page": "2"} + result = AppInstanceMetricResult{ + TotalResults: 5, + TotalPages: 3, + Page: 4, + PrevUrl: getInstanceMetricsUrl(appId, metricType, parameters, 3), + Resources: []models.AppInstanceMetric{}, + } + By("check public api") + checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("the 5th page should be empty") + parameters = map[string]string{"start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "5", "results-per-page": "2"} + result = AppInstanceMetricResult{ + TotalResults: 5, + TotalPages: 3, + Page: 5, + Resources: []models.AppInstanceMetric{}, + } + By("check public api") + checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + }) + }) + Context("instance-index is provided", func() { + It("should get the metrics of the instance", func() { + By("get the 1st page") + parameters = map[string]string{"instance-index": "1", "start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "1", "results-per-page": "2"} + result := AppInstanceMetricResult{ + TotalResults: 2, + TotalPages: 1, + Page: 1, + Resources: []models.AppInstanceMetric{ + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 1, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 444444, + }, + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 1, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 555555, + }, + }, + } + + By("check public api") + checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("get the 2nd page") + parameters = map[string]string{"instance-index": "1", "start-time": "111111", "end-time": "999999", "order-direction": "asc", "page": "2", "results-per-page": "2"} + result = AppInstanceMetricResult{ + TotalResults: 2, + TotalPages: 1, + Page: 2, + PrevUrl: getInstanceMetricsUrlWithInstanceIndex(appId, metricType, parameters, 1), + Resources: []models.AppInstanceMetric{}, + } + By("check public api") + checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + }) + }) + + }) + }) +}) diff --git a/src/integration/integration_suite_test.go b/src/integration/integration_suite_test.go index 4e455c651..444bbaad5 100644 --- a/src/integration/integration_suite_test.go +++ b/src/integration/integration_suite_test.go @@ -87,6 +87,7 @@ var ( apiSchedulerHttpRequestTimeout time.Duration = 10 * time.Second apiScalingEngineHttpRequestTimeout time.Duration = 10 * time.Second apiMetricsCollectorHttpRequestTimeout time.Duration = 10 * time.Second + apiMetricsServerHttpRequestTimeout time.Duration = 10 * time.Second apiEventGeneratorHttpRequestTimeout time.Duration = 10 * time.Second schedulerScalingEngineHttpRequestTimeout time.Duration = 10 * time.Second From 2bb30808f13380f5473feaeb63af6e065a1fde71 Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Fri, 9 Aug 2019 15:22:08 +0800 Subject: [PATCH 03/16] add an extra trigger for recurring schedule when its start time prior to now --- .../scheduler/entity/ScheduleEntity.java | 11 ++ .../scheduler/service/ScheduleManager.java | 80 +++++++++-- .../rest/ScheduleRestControllerTest.java | 7 +- .../service/ScheduleManagerTest.java | 130 +++++++++++++++--- .../RecurringScheduleEntitiesBuilder.java | 9 +- .../scheduler/util/TestDataSetupHelper.java | 36 ++--- scheduler/src/test/resources/fakePolicy.json | 27 +--- 7 files changed, 223 insertions(+), 77 deletions(-) diff --git a/scheduler/src/main/java/org/cloudfoundry/autoscaler/scheduler/entity/ScheduleEntity.java b/scheduler/src/main/java/org/cloudfoundry/autoscaler/scheduler/entity/ScheduleEntity.java index de1f46299..21ddb6046 100644 --- a/scheduler/src/main/java/org/cloudfoundry/autoscaler/scheduler/entity/ScheduleEntity.java +++ b/scheduler/src/main/java/org/cloudfoundry/autoscaler/scheduler/entity/ScheduleEntity.java @@ -70,6 +70,17 @@ public class ScheduleEntity { @JsonProperty(value = "guid") private String guid; + public void copy(ScheduleEntity orig) { + this.appId = orig.appId; + this.timeZone = orig.timeZone; + this.defaultInstanceMaxCount = orig.defaultInstanceMaxCount; + this.defaultInstanceMinCount = orig.defaultInstanceMinCount; + this.instanceMaxCount = orig.instanceMaxCount; + this.instanceMinCount = orig.instanceMinCount; + this.initialMinInstanceCount = orig.initialMinInstanceCount; + this.guid = orig.guid; + } + public Long getId() { return id; } diff --git a/scheduler/src/main/java/org/cloudfoundry/autoscaler/scheduler/service/ScheduleManager.java b/scheduler/src/main/java/org/cloudfoundry/autoscaler/scheduler/service/ScheduleManager.java index b75fac6f5..b80876b22 100644 --- a/scheduler/src/main/java/org/cloudfoundry/autoscaler/scheduler/service/ScheduleManager.java +++ b/scheduler/src/main/java/org/cloudfoundry/autoscaler/scheduler/service/ScheduleManager.java @@ -1,12 +1,20 @@ package org.cloudfoundry.autoscaler.scheduler.service; import java.io.IOException; +import java.text.ParseException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TimeZone; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -23,11 +31,13 @@ import org.cloudfoundry.autoscaler.scheduler.rest.model.Schedules; import org.cloudfoundry.autoscaler.scheduler.rest.model.SynchronizeResult; import org.cloudfoundry.autoscaler.scheduler.util.ScalingEngineUtil; +import org.cloudfoundry.autoscaler.scheduler.util.ScheduleJobHelper; import org.cloudfoundry.autoscaler.scheduler.util.ScheduleTypeEnum; import org.cloudfoundry.autoscaler.scheduler.util.error.DatabaseValidationException; import org.cloudfoundry.autoscaler.scheduler.util.error.MessageBundleResourceHelper; import org.cloudfoundry.autoscaler.scheduler.util.error.SchedulerInternalException; import org.cloudfoundry.autoscaler.scheduler.util.error.ValidationErrorResult; +import org.quartz.CronExpression; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; @@ -156,33 +166,45 @@ private void setUpSchedules(String appId, String guid, ApplicationSchedules appl */ @Transactional public void createSchedules(Schedules schedules) { - + + List recurringSchedules = schedules.getRecurringSchedule(); List specificDateSchedules = schedules.getSpecificDate(); - if (specificDateSchedules != null) { - for (SpecificDateScheduleEntity specificDateScheduleEntity : specificDateSchedules) { + + if (recurringSchedules != null) { + for (RecurringScheduleEntity recurringScheduleEntity : recurringSchedules) { // Persist the schedule in database - SpecificDateScheduleEntity savedScheduleEntity = saveNewSpecificDateSchedule( - specificDateScheduleEntity); + RecurringScheduleEntity savedScheduleEntity = saveNewRecurringSchedule(recurringScheduleEntity); // Ask ScalingJobManager to create scaling job if (savedScheduleEntity != null) { - scheduleJobManager.createSimpleJob(savedScheduleEntity); + SpecificDateScheduleEntity compensatorySchedule = createCompensatorySchedule(recurringScheduleEntity); + if (compensatorySchedule != null){ + //create a compensatory schedule to bring the first fire back + if (specificDateSchedules == null) { + specificDateSchedules = new ArrayList(); + } + specificDateSchedules.add(compensatorySchedule); + logger.debug("add an addition specific date event to compensate the misfire for TODAY: " + compensatorySchedule.toString()); + } + scheduleJobManager.createCronJob(savedScheduleEntity); } } } - - List recurringSchedules = schedules.getRecurringSchedule(); - if (recurringSchedules != null) { - for (RecurringScheduleEntity recurringScheduleEntity : recurringSchedules) { + + if (specificDateSchedules != null) { + for (SpecificDateScheduleEntity specificDateScheduleEntity : specificDateSchedules) { // Persist the schedule in database - RecurringScheduleEntity savedScheduleEntity = saveNewRecurringSchedule(recurringScheduleEntity); + SpecificDateScheduleEntity savedScheduleEntity = saveNewSpecificDateSchedule( + specificDateScheduleEntity); // Ask ScalingJobManager to create scaling job if (savedScheduleEntity != null) { - scheduleJobManager.createCronJob(savedScheduleEntity); + scheduleJobManager.createSimpleJob(savedScheduleEntity); } } } + + } /** @@ -218,6 +240,40 @@ private RecurringScheduleEntity saveNewRecurringSchedule(RecurringScheduleEntity return savedScheduleEntity; } + + private SpecificDateScheduleEntity createCompensatorySchedule(RecurringScheduleEntity recurringScheduleEntity){ + + SpecificDateScheduleEntity compenstatorySchedule = null; + try { + ZoneId timezone = ZoneId.of(recurringScheduleEntity.getTimeZone()); + CronExpression expression = new CronExpression(ScheduleJobHelper.convertRecurringScheduleToCronExpression( + recurringScheduleEntity.getStartTime(), recurringScheduleEntity)); + expression.setTimeZone(TimeZone.getTimeZone(timezone)); + + Date firstValidTime = expression.getNextValidTimeAfter(Date.from(LocalDate.now(timezone).atStartOfDay(timezone).toInstant())); + if (recurringScheduleEntity.getStartTime() == LocalTime.of(0, 0)) { + firstValidTime = expression.getNextValidTimeAfter(Date.from(LocalDate.now(timezone).atStartOfDay(timezone).toInstant().minusSeconds(60))); + } + + if (!firstValidTime.toInstant().atZone(timezone).toLocalDateTime().isAfter(LocalDateTime.now(timezone))){ + if (recurringScheduleEntity.getStartDate() == null || + !(recurringScheduleEntity.getStartDate().atStartOfDay(timezone).isAfter(ZonedDateTime.now(timezone)))){ + compenstatorySchedule = new SpecificDateScheduleEntity(); + compenstatorySchedule.copy(recurringScheduleEntity); + LocalDateTime startDateTime = LocalDateTime.now(timezone).plusMinutes(1); + LocalDateTime endDateTime = LocalDateTime.of(LocalDate.now(timezone),recurringScheduleEntity.getEndTime()); + compenstatorySchedule.setStartDateTime(startDateTime); + compenstatorySchedule.setEndDateTime(endDateTime); + } + } + + } catch (ParseException e) { + logger.error("Invalid parse or clone"); + } + + return compenstatorySchedule; + + } /** * Calls private helper methods to delete the schedules from the database and * calls ScalingJobManager to delete scaling action jobs. diff --git a/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/rest/ScheduleRestControllerTest.java b/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/rest/ScheduleRestControllerTest.java index 91c6141e9..09a45a81d 100644 --- a/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/rest/ScheduleRestControllerTest.java +++ b/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/rest/ScheduleRestControllerTest.java @@ -50,6 +50,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; +import junit.framework.Assert; + @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @DirtiesContext(classMode = ClassMode.BEFORE_CLASS) @@ -174,9 +176,10 @@ public void testCreateAndGetSchedules_from_jsonFile() throws Exception { resultActions = mockMvc.perform(get(TestDataSetupHelper.getSchedulerPath(appId)).accept(MediaType.APPLICATION_JSON)); ApplicationSchedules applicationSchedules = getApplicationSchedulesFromResultActions(resultActions); - assertSchedulesFoundEquals(applicationSchedules, appId, resultActions, 2, 4); + assertSchedulesFoundEquals(applicationSchedules, appId, resultActions, 4, 3); + + Mockito.verify(scheduler, Mockito.times(7)).scheduleJob(Mockito.anyObject(), Mockito.anyObject()); - Mockito.verify(scheduler, Mockito.times(6)).scheduleJob(Mockito.anyObject(), Mockito.anyObject()); } @Test diff --git a/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/service/ScheduleManagerTest.java b/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/service/ScheduleManagerTest.java index 0a871d5f3..9fa2542bd 100644 --- a/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/service/ScheduleManagerTest.java +++ b/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/service/ScheduleManagerTest.java @@ -21,6 +21,9 @@ import static org.springframework.test.web.client.response.MockRestResponseCreators.withNoContent; import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; import java.util.ArrayList; import java.util.List; @@ -238,6 +241,90 @@ public void testCreateSchedules_with_dayOfWeek_recurringSchedule() { noOfDOWRecurringSchedules); } + @Test + public void testCreateSchedules_with_dayOfWeek_recurringSchedule_compensatoryRequired() { + String appId = TestDataSetupHelper.generateAppIds(1)[0]; + String guid = TestDataSetupHelper.generateGuid(); + int noOfDOMRecurringSchedules = 0; + int noOfDOWRecurringSchedules = 1; + + Schedules schedules = TestDataSetupHelper.generateSchedulesWithEntitiesOnly(appId, guid, false, 0, + noOfDOMRecurringSchedules, noOfDOWRecurringSchedules); + + RecurringScheduleEntity recurringSchedule = schedules.getRecurringSchedule().get(0); + recurringSchedule.setStartTime(TestDataSetupHelper.getZoneTimeWithOffset(-5)); + recurringSchedule.setEndTime(TestDataSetupHelper.getZoneTimeWithOffset(-5)); + + RecurringScheduleEntity recurringScheduleEntity = new RecurringScheduleEntitiesBuilder(1, 0).setAppId(appId) + .setScheduleId().build().get(0); + Mockito.when(recurringScheduleDao.create(Mockito.anyObject())).thenReturn(recurringScheduleEntity); + + SpecificDateScheduleEntity specificDateScheduleEntity = new SpecificDateScheduleEntitiesBuilder(1) + .setAppid(appId).setScheduleId().build().get(0); + Mockito.when(specificDateScheduleDao.create(Mockito.anyObject())).thenReturn(specificDateScheduleEntity); + + scheduleManager.createSchedules(schedules); + + assertCreateSchedules(schedules, specificDateScheduleEntity, recurringScheduleEntity, 1, noOfDOMRecurringSchedules, + noOfDOWRecurringSchedules); + } + + + @Test + public void testCreateSchedules_with_dayOfMonth_recurringSchedule_compensatoryRequired() { + String appId = TestDataSetupHelper.generateAppIds(1)[0]; + String guid = TestDataSetupHelper.generateGuid(); + int noOfDOMRecurringSchedules = 1; + int noOfDOWRecurringSchedules = 0; + + Schedules schedules = TestDataSetupHelper.generateSchedulesWithEntitiesOnly(appId, guid, false, 0, + noOfDOMRecurringSchedules, noOfDOWRecurringSchedules); + + RecurringScheduleEntity recurringSchedule = schedules.getRecurringSchedule().get(0); + recurringSchedule.setStartTime(TestDataSetupHelper.getZoneTimeWithOffset(-5)); + recurringSchedule.setEndTime(TestDataSetupHelper.getZoneTimeWithOffset(-5)); + + RecurringScheduleEntity recurringScheduleEntity = new RecurringScheduleEntitiesBuilder(1, 0).setAppId(appId) + .setScheduleId().build().get(0); + Mockito.when(recurringScheduleDao.create(Mockito.anyObject())).thenReturn(recurringScheduleEntity); + + SpecificDateScheduleEntity specificDateScheduleEntity = new SpecificDateScheduleEntitiesBuilder(1) + .setAppid(appId).setScheduleId().build().get(0); + Mockito.when(specificDateScheduleDao.create(Mockito.anyObject())).thenReturn(specificDateScheduleEntity); + + scheduleManager.createSchedules(schedules); + + assertCreateSchedules(schedules, specificDateScheduleEntity, recurringScheduleEntity, 1, noOfDOMRecurringSchedules, + noOfDOWRecurringSchedules); + } + + + @Test + public void testCreateSchedules_with_dayOfWeek_recurringSchedule_compensatoryNotRequiredPerStartDate() { + String appId = TestDataSetupHelper.generateAppIds(1)[0]; + String guid = TestDataSetupHelper.generateGuid(); + int noOfDOMRecurringSchedules = 1; + int noOfDOWRecurringSchedules = 0; + + Schedules schedules = TestDataSetupHelper.generateSchedulesWithEntitiesOnly(appId, guid, false, 0, + noOfDOMRecurringSchedules, noOfDOWRecurringSchedules); + + RecurringScheduleEntity recurringSchedule = schedules.getRecurringSchedule().get(0); + recurringSchedule.setStartTime(TestDataSetupHelper.getZoneTimeWithOffset(-5)); + recurringSchedule.setEndTime(TestDataSetupHelper.getZoneTimeWithOffset(-5)); + recurringSchedule.setStartDate(TestDataSetupHelper.getZoneDateNow().plusDays(2)); + + RecurringScheduleEntity recurringScheduleEntity = new RecurringScheduleEntitiesBuilder(1, 0).setAppId(appId) + .setScheduleId().build().get(0); + Mockito.when(recurringScheduleDao.create(Mockito.anyObject())).thenReturn(recurringScheduleEntity); + + scheduleManager.createSchedules(schedules); + + assertCreateSchedules(schedules, null, recurringScheduleEntity, 0, noOfDOMRecurringSchedules, + noOfDOWRecurringSchedules); + } + + @Test public void testCreateSchedules() { String appId = TestDataSetupHelper.generateAppIds(1)[0]; @@ -683,9 +770,9 @@ public void testSynchronizeSchedules_with_existed_policy_and_no_schedule() throw int noOfDOMRecurringSchedules = 3; int noOfDOWRecurringSchedules = 3; - List recurringEntities = new RecurringScheduleEntitiesBuilder(noOfDOMRecurringSchedules, noOfDOWRecurringSchedules).setAppId(appId).setGuid(guid).setTimeZone("timeZone").setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); - List specificDateEntities = new SpecificDateScheduleEntitiesBuilder(noOfSpecificDateSchedules).setAppid(appId).setGuid(guid).setTimeZone("timeZone").setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); - Schedules schedules = new ScheduleBuilder().setSpecificDate(specificDateEntities).setRecurringSchedule(recurringEntities).setTimeZone("timeZone").build(); + List recurringEntities = new RecurringScheduleEntitiesBuilder(noOfDOMRecurringSchedules, noOfDOWRecurringSchedules).setAppId(appId).setGuid(guid).setTimeZone(TestDataSetupHelper.timeZone).setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); + List specificDateEntities = new SpecificDateScheduleEntitiesBuilder(noOfSpecificDateSchedules).setAppid(appId).setGuid(guid).setTimeZone(TestDataSetupHelper.timeZone).setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); + Schedules schedules = new ScheduleBuilder().setSpecificDate(specificDateEntities).setRecurringSchedule(recurringEntities).setTimeZone(TestDataSetupHelper.timeZone).build(); ApplicationSchedules applicationSchedule = new ApplicationPolicyBuilder(1,5).setSchedules(schedules).build(); List policyJsonList = new ArrayList() { @@ -719,9 +806,9 @@ public void testSynchronizeSchedules_with_no_policy_and_existed_schedules() { int noOfDOMRecurringSchedules = 3; int noOfDOWRecurringSchedules = 3; - List recurringEntities = new RecurringScheduleEntitiesBuilder(noOfDOMRecurringSchedules, noOfDOWRecurringSchedules).setAppId(appId).setGuid(guid).setTimeZone("timeZone").setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); - List specificDateEntities = new SpecificDateScheduleEntitiesBuilder(noOfSpecificDateSchedules).setAppid(appId).setGuid(guid).setTimeZone("timeZone").setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); - Schedules schedules = new ScheduleBuilder().setSpecificDate(specificDateEntities).setRecurringSchedule(recurringEntities).setTimeZone("tomeZone").build(); + List recurringEntities = new RecurringScheduleEntitiesBuilder(noOfDOMRecurringSchedules, noOfDOWRecurringSchedules).setAppId(appId).setGuid(guid).setTimeZone(TestDataSetupHelper.timeZone).setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); + List specificDateEntities = new SpecificDateScheduleEntitiesBuilder(noOfSpecificDateSchedules).setAppid(appId).setGuid(guid).setTimeZone(TestDataSetupHelper.timeZone).setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); + Schedules schedules = new ScheduleBuilder().setSpecificDate(specificDateEntities).setRecurringSchedule(recurringEntities).setTimeZone(TestDataSetupHelper.timeZone).build(); String[] appIdAndGuid = {appId, guid}; when(policyJsonDao.getAllPolicies()).thenReturn(new ArrayList()); @@ -749,13 +836,13 @@ public void testSynchronizeSchedules_with_both_policy_with_schedules_and_schedul int noOfDOMRecurringSchedules = 3; int noOfDOWRecurringSchedules = 3; - List recurringEntities = new RecurringScheduleEntitiesBuilder(noOfDOMRecurringSchedules, noOfDOWRecurringSchedules).setAppId(appId).setGuid(guid).setTimeZone("timeZone").setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); - List specificDateEntities = new SpecificDateScheduleEntitiesBuilder(noOfSpecificDateSchedules).setAppid(appId).setGuid(guid).setTimeZone("timeZone").setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); - Schedules schedules = new ScheduleBuilder().setSpecificDate(specificDateEntities).setRecurringSchedule(recurringEntities).setTimeZone("tomeZone").build(); + List recurringEntities = new RecurringScheduleEntitiesBuilder(noOfDOMRecurringSchedules, noOfDOWRecurringSchedules).setAppId(appId).setGuid(guid).setTimeZone(TestDataSetupHelper.timeZone).setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); + List specificDateEntities = new SpecificDateScheduleEntitiesBuilder(noOfSpecificDateSchedules).setAppid(appId).setGuid(guid).setTimeZone(TestDataSetupHelper.timeZone).setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); + Schedules schedules = new ScheduleBuilder().setSpecificDate(specificDateEntities).setRecurringSchedule(recurringEntities).setTimeZone(TestDataSetupHelper.timeZone).build(); - List anotherRecurringEntities = new RecurringScheduleEntitiesBuilder(noOfDOMRecurringSchedules, noOfDOWRecurringSchedules).setAppId(appId).setGuid(anotherGuid).setTimeZone("timeZone").setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); - List anotherSpecificDateEntities = new SpecificDateScheduleEntitiesBuilder(noOfSpecificDateSchedules).setAppid(appId).setGuid(anotherGuid).setTimeZone("timeZone").setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); - Schedules anotherSchedules = new ScheduleBuilder().setSpecificDate(anotherSpecificDateEntities).setRecurringSchedule(anotherRecurringEntities).setTimeZone("timeZone").build(); + List anotherRecurringEntities = new RecurringScheduleEntitiesBuilder(noOfDOMRecurringSchedules, noOfDOWRecurringSchedules).setAppId(appId).setGuid(anotherGuid).setTimeZone(TestDataSetupHelper.timeZone).setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); + List anotherSpecificDateEntities = new SpecificDateScheduleEntitiesBuilder(noOfSpecificDateSchedules).setAppid(appId).setGuid(anotherGuid).setTimeZone(TestDataSetupHelper.timeZone).setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); + Schedules anotherSchedules = new ScheduleBuilder().setSpecificDate(anotherSpecificDateEntities).setRecurringSchedule(anotherRecurringEntities).setTimeZone(TestDataSetupHelper.timeZone).build(); ApplicationSchedules anotherApplicationSchedule = new ApplicationPolicyBuilder(1,5).setSchedules(anotherSchedules).build(); String[] appIdAndGuid = {appId, guid}; @@ -793,9 +880,9 @@ public void testSynchronizeSchedules_with_both_policy_without_schedule_and_sched int noOfDOMRecurringSchedules = 3; int noOfDOWRecurringSchedules = 3; - List recurringEntities = new RecurringScheduleEntitiesBuilder(noOfDOMRecurringSchedules, noOfDOWRecurringSchedules).setAppId(appId).setGuid(guid).setTimeZone("timeZone").setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); - List specificDateEntities = new SpecificDateScheduleEntitiesBuilder(noOfSpecificDateSchedules).setAppid(appId).setGuid(guid).setTimeZone("timeZone").setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); - Schedules schedules = new ScheduleBuilder().setSpecificDate(specificDateEntities).setRecurringSchedule(recurringEntities).setTimeZone("tomeZone").build(); + List recurringEntities = new RecurringScheduleEntitiesBuilder(noOfDOMRecurringSchedules, noOfDOWRecurringSchedules).setAppId(appId).setGuid(guid).setTimeZone(TestDataSetupHelper.timeZone).setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); + List specificDateEntities = new SpecificDateScheduleEntitiesBuilder(noOfSpecificDateSchedules).setAppid(appId).setGuid(guid).setTimeZone(TestDataSetupHelper.timeZone).setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); + Schedules schedules = new ScheduleBuilder().setSpecificDate(specificDateEntities).setRecurringSchedule(recurringEntities).setTimeZone(TestDataSetupHelper.timeZone).build(); ApplicationSchedules anotherApplicationSchedule = new ApplicationPolicyBuilder(1,5).setSchedules(null).build(); @@ -828,13 +915,13 @@ public void testSynchronizeSchedules_with_both_policy_and_schedules_existed_and_ int noOfDOMRecurringSchedules = 3; int noOfDOWRecurringSchedules = 3; - List recurringEntities = new RecurringScheduleEntitiesBuilder(noOfDOMRecurringSchedules, noOfDOWRecurringSchedules).setAppId(appId).setGuid(guid).setTimeZone("timeZone").setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); - List specificDateEntities = new SpecificDateScheduleEntitiesBuilder(noOfSpecificDateSchedules).setAppid(appId).setGuid(guid).setTimeZone("timeZone").setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); - Schedules schedules = new ScheduleBuilder().setSpecificDate(specificDateEntities).setRecurringSchedule(recurringEntities).setTimeZone("tomeZone").build(); + List recurringEntities = new RecurringScheduleEntitiesBuilder(noOfDOMRecurringSchedules, noOfDOWRecurringSchedules).setAppId(appId).setGuid(guid).setTimeZone(TestDataSetupHelper.timeZone).setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); + List specificDateEntities = new SpecificDateScheduleEntitiesBuilder(noOfSpecificDateSchedules).setAppid(appId).setGuid(guid).setTimeZone(TestDataSetupHelper.timeZone).setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); + Schedules schedules = new ScheduleBuilder().setSpecificDate(specificDateEntities).setRecurringSchedule(recurringEntities).setTimeZone(TestDataSetupHelper.timeZone).build(); - List anotherRecurringEntities = new RecurringScheduleEntitiesBuilder(noOfDOMRecurringSchedules, noOfDOWRecurringSchedules).setAppId(appId).setGuid(guid).setTimeZone("timeZone").setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); - List anotherSpecificDateEntities = new SpecificDateScheduleEntitiesBuilder(noOfSpecificDateSchedules).setAppid(appId).setGuid(guid).setTimeZone("timeZone").setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); - Schedules anotherSchedules = new ScheduleBuilder().setSpecificDate(anotherSpecificDateEntities).setRecurringSchedule(anotherRecurringEntities).setTimeZone("tomeZone").build(); + List anotherRecurringEntities = new RecurringScheduleEntitiesBuilder(noOfDOMRecurringSchedules, noOfDOWRecurringSchedules).setAppId(appId).setGuid(guid).setTimeZone(TestDataSetupHelper.timeZone).setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); + List anotherSpecificDateEntities = new SpecificDateScheduleEntitiesBuilder(noOfSpecificDateSchedules).setAppid(appId).setGuid(guid).setTimeZone(TestDataSetupHelper.timeZone).setDefaultInstanceMinCount(1).setDefaultInstanceMaxCount(5).setScheduleId().build(); + Schedules anotherSchedules = new ScheduleBuilder().setSpecificDate(anotherSpecificDateEntities).setRecurringSchedule(anotherRecurringEntities).setTimeZone(TestDataSetupHelper.timeZone).build(); ApplicationSchedules anotherapplicationSchedule = new ApplicationPolicyBuilder(1,5).setSchedules(anotherSchedules).build(); String[] appIdAndGuid = {appId, guid}; @@ -883,6 +970,7 @@ private void assertCreateSchedules(Schedules schedules, SpecificDateScheduleEnti if (schedules.getRecurringSchedule() != null) { Mockito.verify(recurringScheduleDao, Mockito.times(noOfDOMRecurringSchedules + noOfDOWRecurringSchedules)).create(recurringCaptor.capture()); List recurringList = recurringCaptor.getAllValues(); + for (RecurringScheduleEntity foundRecurringScheduleEntity : schedules.getRecurringSchedule()) { assert(recurringList.contains(foundRecurringScheduleEntity)); } diff --git a/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/util/RecurringScheduleEntitiesBuilder.java b/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/util/RecurringScheduleEntitiesBuilder.java index b5c794b8b..c945b55ce 100644 --- a/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/util/RecurringScheduleEntitiesBuilder.java +++ b/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/util/RecurringScheduleEntitiesBuilder.java @@ -14,7 +14,7 @@ public class RecurringScheduleEntitiesBuilder { public RecurringScheduleEntitiesBuilder(int noOfDOMSchedules, int noOfDOWSchedules) { recurringScheduleEntities = generateEntities(noOfDOMSchedules, noOfDOWSchedules); } - + public RecurringScheduleEntitiesBuilder setTimeZone(String timeZone) { if (recurringScheduleEntities != null) { for (RecurringScheduleEntity recurringScheduleEntity : recurringScheduleEntities) { @@ -118,7 +118,6 @@ private List generateEntities(int noOfDOMSchedules, int if ((noOfDOMSchedules + noOfDOWSchedules) == 0) { return null; } - entities.addAll(generateDOM_DOWEntities(noOfDOMSchedules, false)); entities.addAll(generateDOM_DOWEntities(noOfDOWSchedules, true)); @@ -129,10 +128,12 @@ private List generateDOM_DOWEntities(int noOfSchedules, List recurringScheduleEntities = new ArrayList<>(); for (int i = 0; i < noOfSchedules; i++) { RecurringScheduleEntity recurringScheduleEntity = new RecurringScheduleEntity(); + recurringScheduleEntity - .setStartTime(TestDataSetupHelper.getTime(TestDataSetupHelper.getStarTime(), scheduleIndex, 0)); + .setStartTime(TestDataSetupHelper.getZoneTimeWithOffset(10*i+10)); + recurringScheduleEntity - .setEndTime(TestDataSetupHelper.getTime(TestDataSetupHelper.getEndTime(), scheduleIndex, 5)); + .setEndTime(TestDataSetupHelper.getZoneTimeWithOffset(10*i+15)); recurringScheduleEntity.setInstanceMinCount(i + 5); recurringScheduleEntity.setInstanceMaxCount(i + 6); diff --git a/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/util/TestDataSetupHelper.java b/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/util/TestDataSetupHelper.java index b10fe006e..51f616f80 100644 --- a/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/util/TestDataSetupHelper.java +++ b/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/util/TestDataSetupHelper.java @@ -3,9 +3,12 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -42,7 +45,7 @@ public class TestDataSetupHelper { private static Logger logger = LogManager.getLogger(clazz); private static List genAppIds = new ArrayList<>(); - private static String timeZone = "GMT"; + public static String timeZone = "GMT"; private static String currentStartDateTime = getCurrentDateOrTime(5, DateHelper.DATE_TIME_FORMAT, getTimeZone()); private static String currentEndDateTime = getCurrentDateOrTime(6, DateHelper.DATE_TIME_FORMAT, getTimeZone()); @@ -79,7 +82,7 @@ public static Schedules generateSchedulesWithEntitiesOnly(String appId, String g .build(); } - + public static List generateSpecificDateScheduleEntities(String appId, String guid, boolean generateScheduleId, int noOfSpecificDateSchedulesToSetUp) { SpecificDateScheduleEntitiesBuilder builder = new SpecificDateScheduleEntitiesBuilder( @@ -174,16 +177,9 @@ public static String convertDateTimeString(Date dateTime, TimeZone timeZone) { sdf.setTimeZone(timeZone); return sdf.format(dateTime); } - - static LocalTime getTime(String[] timeArr, int pos, int offsetMin) { - DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DateHelper.TIME_FORMAT); - String timeStr; - if (timeArr != null && timeArr.length > pos) { - timeStr = timeArr[pos]; - } else { - timeStr = getCurrentDateOrTime(offsetMin, DateHelper.TIME_FORMAT, getTimeZone()); - } - return LocalTime.parse(timeStr, dateTimeFormatter); + + public static LocalTime getZoneTimeWithOffset(int offsetMin){ + return LocalDateTime.now(ZoneId.of(TestDataSetupHelper.timeZone)).plusMinutes(offsetMin).toLocalTime().truncatedTo(ChronoUnit.MINUTES); } private static String getCurrentDateOrTime(int offsetMin, String format, String timeZone) { @@ -195,8 +191,8 @@ private static String getCurrentDateOrTime(int offsetMin, String format, String return sdfDate.format(calNow.getTime()); } - public static LocalDate getZoneDateNow(String timeZoneId) { - TimeZone timeZone = TimeZone.getTimeZone(timeZoneId); + public static LocalDate getZoneDateNow() { + TimeZone timeZone = TimeZone.getTimeZone(TestDataSetupHelper.timeZone); return ZonedDateTime.now(timeZone.toZoneId()).toLocalDate(); } @@ -218,23 +214,29 @@ public static String generateGuid(){ } public static int[] generateDayOfWeek() { int arraySize = (int) (new Date().getTime() % 7) + 1; + int today = LocalDateTime.now(ZoneId.of(timeZone)).getDayOfWeek().getValue(); int[] array = makeRandomArray(new Random(Calendar.getInstance().getTimeInMillis()), arraySize, - DateHelper.DAY_OF_WEEK_MINIMUM, DateHelper.DAY_OF_WEEK_MAXIMUM); + DateHelper.DAY_OF_WEEK_MINIMUM, DateHelper.DAY_OF_WEEK_MAXIMUM, today); logger.debug("Generate day of week array:" + Arrays.toString(array)); return array; } public static int[] generateDayOfMonth() { int arraySize = (int) (new Date().getTime() % 31) + 1; + int today = LocalDateTime.now(ZoneId.of(timeZone)).getDayOfMonth(); int[] array = makeRandomArray(new Random(Calendar.getInstance().getTimeInMillis()), arraySize, - DateHelper.DAY_OF_MONTH_MINIMUM, DateHelper.DAY_OF_MONTH_MAXIMUM); + DateHelper.DAY_OF_MONTH_MINIMUM, DateHelper.DAY_OF_MONTH_MAXIMUM, today); logger.debug("Generate day of month array:" + Arrays.toString(array)); return array; } - private static int[] makeRandomArray(Random rand, int size, int randMin, int randMax) { + private static int[] makeRandomArray(Random rand, int size, int randMin, int randMax, int fixValue) { int[] array = rand.ints(randMin, randMax + 1).distinct().limit(size).toArray(); Arrays.sort(array); + if (Arrays.binarySearch(array, fixValue) < 0) { + array[0] = fixValue; + } + Arrays.sort(array); return array; } diff --git a/scheduler/src/test/resources/fakePolicy.json b/scheduler/src/test/resources/fakePolicy.json index f726451e5..370b30cbb 100644 --- a/scheduler/src/test/resources/fakePolicy.json +++ b/scheduler/src/test/resources/fakePolicy.json @@ -25,12 +25,10 @@ "timezone":"Asia/Shanghai", "recurring_schedule":[ { - "start_time":"10:00", - "end_time":"18:00", + "start_time":"00:00", + "end_time":"23:59", "days_of_week":[ - 1, - 2, - 3 + 1,2,3,4,5,6,7 ], "instance_min_count":1, "instance_max_count":10, @@ -51,23 +49,10 @@ "initial_min_instance_count":5 }, { - "start_time":"10:00", - "end_time":"18:00", - "days_of_week":[ - 4, - 5, - 6 - ], - "instance_min_count":1, - "instance_max_count":10 - }, - { - "start_time":"11:00", - "end_time":"19:30", + "start_time":"00:00", + "end_time":"23:59", "days_of_month":[ - 10, - 20, - 30 + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 ], "instance_min_count":1, "instance_max_count":10 From c6de7f7b5211d3628eaa29d8005aa3126b7ee188 Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Wed, 14 Aug 2019 09:55:09 +0800 Subject: [PATCH 04/16] fix integration test issue --- .../scheduler/dao/ActiveScheduleDao.java | 4 +-- .../scheduler/dao/ActiveScheduleDaoImpl.java | 1 - .../scheduler/service/ScheduleManager.java | 2 +- .../rest/ScheduleRestControllerTest.java | 3 -- .../service/ScheduleManagerTest.java | 3 -- .../scheduler/util/TestDataDbUtil.java | 1 - scheduler/src/test/resources/fakePolicy.json | 2 +- .../integration_api_scheduler_test.go | 24 +++++++-------- .../integration_operator_others_test.go | 2 +- src/integration/integration_suite_test.go | 30 +++++++++++++++++++ 10 files changed, 47 insertions(+), 25 deletions(-) diff --git a/scheduler/src/main/java/org/cloudfoundry/autoscaler/scheduler/dao/ActiveScheduleDao.java b/scheduler/src/main/java/org/cloudfoundry/autoscaler/scheduler/dao/ActiveScheduleDao.java index bfa1bbe94..8aaf5ff87 100644 --- a/scheduler/src/main/java/org/cloudfoundry/autoscaler/scheduler/dao/ActiveScheduleDao.java +++ b/scheduler/src/main/java/org/cloudfoundry/autoscaler/scheduler/dao/ActiveScheduleDao.java @@ -1,9 +1,9 @@ package org.cloudfoundry.autoscaler.scheduler.dao; -import org.cloudfoundry.autoscaler.scheduler.entity.ActiveScheduleEntity; - import java.util.List; +import org.cloudfoundry.autoscaler.scheduler.entity.ActiveScheduleEntity; + public interface ActiveScheduleDao { ActiveScheduleEntity find(Long id); diff --git a/scheduler/src/main/java/org/cloudfoundry/autoscaler/scheduler/dao/ActiveScheduleDaoImpl.java b/scheduler/src/main/java/org/cloudfoundry/autoscaler/scheduler/dao/ActiveScheduleDaoImpl.java index 84c369965..6d3859704 100644 --- a/scheduler/src/main/java/org/cloudfoundry/autoscaler/scheduler/dao/ActiveScheduleDaoImpl.java +++ b/scheduler/src/main/java/org/cloudfoundry/autoscaler/scheduler/dao/ActiveScheduleDaoImpl.java @@ -7,7 +7,6 @@ import org.cloudfoundry.autoscaler.scheduler.entity.ActiveScheduleEntity; import org.cloudfoundry.autoscaler.scheduler.util.error.DatabaseValidationException; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.support.JdbcDaoSupport; diff --git a/scheduler/src/main/java/org/cloudfoundry/autoscaler/scheduler/service/ScheduleManager.java b/scheduler/src/main/java/org/cloudfoundry/autoscaler/scheduler/service/ScheduleManager.java index b80876b22..a222585d2 100644 --- a/scheduler/src/main/java/org/cloudfoundry/autoscaler/scheduler/service/ScheduleManager.java +++ b/scheduler/src/main/java/org/cloudfoundry/autoscaler/scheduler/service/ScheduleManager.java @@ -255,7 +255,7 @@ private SpecificDateScheduleEntity createCompensatorySchedule(RecurringScheduleE firstValidTime = expression.getNextValidTimeAfter(Date.from(LocalDate.now(timezone).atStartOfDay(timezone).toInstant().minusSeconds(60))); } - if (!firstValidTime.toInstant().atZone(timezone).toLocalDateTime().isAfter(LocalDateTime.now(timezone))){ + if (firstValidTime.toInstant().atZone(timezone).toLocalDateTime().isBefore(LocalDateTime.now(timezone))){ if (recurringScheduleEntity.getStartDate() == null || !(recurringScheduleEntity.getStartDate().atStartOfDay(timezone).isAfter(ZonedDateTime.now(timezone)))){ compenstatorySchedule = new SpecificDateScheduleEntity(); diff --git a/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/rest/ScheduleRestControllerTest.java b/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/rest/ScheduleRestControllerTest.java index 09a45a81d..f6f44235e 100644 --- a/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/rest/ScheduleRestControllerTest.java +++ b/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/rest/ScheduleRestControllerTest.java @@ -14,7 +14,6 @@ import java.io.IOException; import java.text.DateFormat; -import java.util.ArrayList; import java.util.List; import org.cloudfoundry.autoscaler.scheduler.dao.ActiveScheduleDao; @@ -50,8 +49,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; -import junit.framework.Assert; - @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @DirtiesContext(classMode = ClassMode.BEFORE_CLASS) diff --git a/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/service/ScheduleManagerTest.java b/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/service/ScheduleManagerTest.java index 9fa2542bd..3211e8d11 100644 --- a/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/service/ScheduleManagerTest.java +++ b/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/service/ScheduleManagerTest.java @@ -21,9 +21,6 @@ import static org.springframework.test.web.client.response.MockRestResponseCreators.withNoContent; import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.ZoneId; import java.util.ArrayList; import java.util.List; diff --git a/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/util/TestDataDbUtil.java b/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/util/TestDataDbUtil.java index b206199b8..4b317534f 100644 --- a/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/util/TestDataDbUtil.java +++ b/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/util/TestDataDbUtil.java @@ -16,7 +16,6 @@ import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.impl.matchers.GroupMatcher; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; diff --git a/scheduler/src/test/resources/fakePolicy.json b/scheduler/src/test/resources/fakePolicy.json index 370b30cbb..89a9fb83c 100644 --- a/scheduler/src/test/resources/fakePolicy.json +++ b/scheduler/src/test/resources/fakePolicy.json @@ -52,7 +52,7 @@ "start_time":"00:00", "end_time":"23:59", "days_of_month":[ - 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 ], "instance_min_count":1, "instance_max_count":10 diff --git a/src/integration/integration_api_scheduler_test.go b/src/integration/integration_api_scheduler_test.go index 790271dfc..9f0dca588 100644 --- a/src/integration/integration_api_scheduler_test.go +++ b/src/integration/integration_api_scheduler_test.go @@ -263,7 +263,7 @@ var _ = Describe("Integration_Api_Scheduler", func() { Context("internal api", func() { Context("Policies with schedules", func() { It("creates a policy and associated schedules", func() { - policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + policyStr = setPolicyRecurringDate(readPolicyFromFile("fakePolicyWithSchedule.json")) doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIServer], httpClient) checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[APIServer], httpClient) @@ -294,7 +294,7 @@ var _ = Describe("Integration_Api_Scheduler", func() { Context("public api", func() { Context("Policies with schedules", func() { It("creates a policy and associated schedules", func() { - policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + policyStr = setPolicyRecurringDate(readPolicyFromFile("fakePolicyWithSchedule.json")) doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIPublicServer], httpClientForPublicApi) checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[APIPublicServer], httpClientForPublicApi) @@ -335,14 +335,14 @@ var _ = Describe("Integration_Api_Scheduler", func() { Context("Update policies with schedules", func() { BeforeEach(func() { //attach a policy first with 4 recurring and 2 specific_date schedules - policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + policyStr = setPolicyRecurringDate(readPolicyFromFile("fakePolicyWithSchedule.json")) doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIServer], httpClient) }) It("updates the policy and schedules", func() { //attach another policy with 3 recurring and 1 specific_date schedules - policyStr = readPolicyFromFile("fakePolicyWithScheduleAnother.json") + policyStr = setPolicyRecurringDate(readPolicyFromFile("fakePolicyWithScheduleAnother.json")) doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[APIServer], httpClient) checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[APIServer], httpClient) @@ -355,14 +355,14 @@ var _ = Describe("Integration_Api_Scheduler", func() { Context("Update policies with schedules", func() { BeforeEach(func() { //attach a policy first with 4 recurring and 2 specific_date schedules - policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + policyStr = setPolicyRecurringDate(readPolicyFromFile("fakePolicyWithSchedule.json")) doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIPublicServer], httpClientForPublicApi) }) It("updates the policy and schedules", func() { //attach another policy with 3 recurring and 1 specific_date schedules - policyStr = readPolicyFromFile("fakePolicyWithScheduleAnother.json") + policyStr = setPolicyRecurringDate(readPolicyFromFile("fakePolicyWithScheduleAnother.json")) doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[APIPublicServer], httpClientForPublicApi) checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[APIPublicServer], httpClientForPublicApi) @@ -445,7 +445,7 @@ var _ = Describe("Integration_Api_Scheduler", func() { Context("internal api", func() { Context("Policies with schedules", func() { It("creates a policy and associated schedules", func() { - policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + policyStr = setPolicyRecurringDate(readPolicyFromFile("fakePolicyWithSchedule.json")) doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIServer], httpClient) checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[APIServer], httpClient) @@ -477,7 +477,7 @@ var _ = Describe("Integration_Api_Scheduler", func() { Context("public api", func() { Context("Policies with schedules", func() { It("creates a policy and associated schedules", func() { - policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + policyStr = setPolicyRecurringDate(readPolicyFromFile("fakePolicyWithSchedule.json")) doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIPublicServer], httpClientForPublicApi) checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[APIPublicServer], httpClientForPublicApi) @@ -513,13 +513,13 @@ var _ = Describe("Integration_Api_Scheduler", func() { Context("Update policies with schedules", func() { BeforeEach(func() { //attach a policy first with 4 recurring and 2 specific_date schedules - policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + policyStr = setPolicyRecurringDate(readPolicyFromFile("fakePolicyWithSchedule.json")) doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIServer], httpClient) }) It("updates the policy and schedules", func() { //attach another policy with 3 recurring and 1 specific_date schedules - policyStr = readPolicyFromFile("fakePolicyWithScheduleAnother.json") + policyStr = setPolicyRecurringDate(readPolicyFromFile("fakePolicyWithScheduleAnother.json")) doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[APIServer], httpClient) checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[APIServer], httpClient) @@ -532,13 +532,13 @@ var _ = Describe("Integration_Api_Scheduler", func() { Context("Update policies with schedules", func() { BeforeEach(func() { //attach a policy first with 4 recurring and 2 specific_date schedules - policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + policyStr = setPolicyRecurringDate(readPolicyFromFile("fakePolicyWithSchedule.json")) doAttachPolicy(appId, policyStr, http.StatusCreated, components.Ports[APIPublicServer], httpClientForPublicApi) }) It("updates the policy and schedules", func() { //attach another policy with 3 recurring and 1 specific_date schedules - policyStr = readPolicyFromFile("fakePolicyWithScheduleAnother.json") + policyStr = setPolicyRecurringDate(readPolicyFromFile("fakePolicyWithScheduleAnother.json")) doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[APIPublicServer], httpClientForPublicApi) checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[APIPublicServer], httpClientForPublicApi) diff --git a/src/integration/integration_operator_others_test.go b/src/integration/integration_operator_others_test.go index e7004a944..ede1be2b1 100644 --- a/src/integration/integration_operator_others_test.go +++ b/src/integration/integration_operator_others_test.go @@ -166,7 +166,7 @@ var _ = Describe("Integration_Operator_Others", func() { doAttachPolicy(testAppId, []byte(policyStr), http.StatusCreated, components.Ports[APIServer], httpClient) Expect(checkSchedule(testAppId, http.StatusOK, map[string]int{"recurring_schedule": 4, "specific_date": 2})).To(BeTrue()) - newPolicyStr := string(readPolicyFromFile("fakePolicyWithScheduleAnother.json")) + newPolicyStr := string(setPolicyRecurringDate(readPolicyFromFile("fakePolicyWithScheduleAnother.json"))) deletePolicy(testAppId) insertPolicy(testAppId, newPolicyStr, testGuid) diff --git a/src/integration/integration_suite_test.go b/src/integration/integration_suite_test.go index 444bbaad5..a61f170e4 100644 --- a/src/integration/integration_suite_test.go +++ b/src/integration/integration_suite_test.go @@ -487,6 +487,36 @@ func activeScheduleExists(appId string) bool { return resp.StatusCode == http.StatusOK } +func setPolicyRecurringDate(policyByte []byte) []byte { + + var policy models.ScalingPolicy + err := json.Unmarshal(policyByte, &policy) + Expect(err).NotTo(HaveOccurred()) + + if policy.Schedules != nil { + location, err := time.LoadLocation(policy.Schedules.Timezone) + Expect(err).NotTo(HaveOccurred()) + now := time.Now().In(location) + starttime := now.Add(time.Minute * 10) + endtime := now.Add(time.Minute * 20) + for _, entry := range policy.Schedules.RecurringSchedules { + if endtime.Day() != starttime.Day() { + entry.StartTime = "00:01" + entry.EndTime = "23:59" + entry.StartDate = endtime.Format("2006-01-02") + } else { + entry.StartTime = starttime.Format("15:04") + entry.EndTime = endtime.Format("15:04") + } + } + } + + content, err := json.Marshal(policy) + Expect(err).NotTo(HaveOccurred()) + return content + +} + func setPolicySpecificDateTime(policyByte []byte, start time.Duration, end time.Duration) string { timeZone := "GMT" location, _ := time.LoadLocation(timeZone) From b662c8d42fc72a7e9da4e66f2cde14ab60806d05 Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Wed, 14 Aug 2019 10:51:59 +0800 Subject: [PATCH 05/16] append more fix in integration test --- src/integration/integration_operator_others_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/integration/integration_operator_others_test.go b/src/integration/integration_operator_others_test.go index ede1be2b1..eb48c5105 100644 --- a/src/integration/integration_operator_others_test.go +++ b/src/integration/integration_operator_others_test.go @@ -117,7 +117,7 @@ var _ = Describe("Integration_Operator_Others", func() { Describe("Synchronize policy DB and scheduler", func() { BeforeEach(func() { - policyStr = string(readPolicyFromFile("fakePolicyWithSchedule.json")) + policyStr = string(setPolicyRecurringDate(readPolicyFromFile("fakePolicyWithSchedule.json"))) }) AfterEach(func() { From b71e30e968579110653db9e5478f969a13c0804b Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Wed, 14 Aug 2019 16:00:58 +0800 Subject: [PATCH 06/16] fix ut error --- .../autoscaler/scheduler/service/ScheduleManagerTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/service/ScheduleManagerTest.java b/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/service/ScheduleManagerTest.java index 3211e8d11..6723ec014 100644 --- a/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/service/ScheduleManagerTest.java +++ b/scheduler/src/test/java/org/cloudfoundry/autoscaler/scheduler/service/ScheduleManagerTest.java @@ -250,7 +250,7 @@ public void testCreateSchedules_with_dayOfWeek_recurringSchedule_compensatoryReq RecurringScheduleEntity recurringSchedule = schedules.getRecurringSchedule().get(0); recurringSchedule.setStartTime(TestDataSetupHelper.getZoneTimeWithOffset(-5)); - recurringSchedule.setEndTime(TestDataSetupHelper.getZoneTimeWithOffset(-5)); + recurringSchedule.setEndTime(TestDataSetupHelper.getZoneTimeWithOffset(5)); RecurringScheduleEntity recurringScheduleEntity = new RecurringScheduleEntitiesBuilder(1, 0).setAppId(appId) .setScheduleId().build().get(0); @@ -279,7 +279,7 @@ public void testCreateSchedules_with_dayOfMonth_recurringSchedule_compensatoryRe RecurringScheduleEntity recurringSchedule = schedules.getRecurringSchedule().get(0); recurringSchedule.setStartTime(TestDataSetupHelper.getZoneTimeWithOffset(-5)); - recurringSchedule.setEndTime(TestDataSetupHelper.getZoneTimeWithOffset(-5)); + recurringSchedule.setEndTime(TestDataSetupHelper.getZoneTimeWithOffset(5)); RecurringScheduleEntity recurringScheduleEntity = new RecurringScheduleEntitiesBuilder(1, 0).setAppId(appId) .setScheduleId().build().get(0); @@ -308,7 +308,7 @@ public void testCreateSchedules_with_dayOfWeek_recurringSchedule_compensatoryNot RecurringScheduleEntity recurringSchedule = schedules.getRecurringSchedule().get(0); recurringSchedule.setStartTime(TestDataSetupHelper.getZoneTimeWithOffset(-5)); - recurringSchedule.setEndTime(TestDataSetupHelper.getZoneTimeWithOffset(-5)); + recurringSchedule.setEndTime(TestDataSetupHelper.getZoneTimeWithOffset(5)); recurringSchedule.setStartDate(TestDataSetupHelper.getZoneDateNow().plusDays(2)); RecurringScheduleEntity recurringScheduleEntity = new RecurringScheduleEntitiesBuilder(1, 0).setAppId(appId) From 88bce97f0c49d47db97ab271ec98d10f02ea3cb2 Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Wed, 14 Aug 2019 17:33:57 +0800 Subject: [PATCH 07/16] remove related limitation from docs --- docs/policy.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/policy.md b/docs/policy.md index a686219ce..afa6dc0ef 100644 --- a/docs/policy.md +++ b/docs/policy.md @@ -65,12 +65,6 @@ With above definition, schedule #1 and #3 will be applied, while scheudle #2 is ignored. -* If a schedule's start time is earlier than the policy creation/update time, the schedule will not be executed. For example: - - - Schedule #1: 09:00 - 13:00 , Everyday - - If above schedule is created at 10:00AM someday, it won't take effect when it creates, but will be certainly triggered on the next day. - ## Sample Policy * [Autoscaling policy with dynamic scaling rules][policy-dynamic] From 2a325221c0db09707b5ef45d982dba5e3e82102a Mon Sep 17 00:00:00 2001 From: qibobo Date: Tue, 3 Sep 2019 15:38:03 +0800 Subject: [PATCH 08/16] upgrade pq --- src/github.com/lib/pq | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/github.com/lib/pq b/src/github.com/lib/pq index 4a82388eb..78223426e 160000 --- a/src/github.com/lib/pq +++ b/src/github.com/lib/pq @@ -1 +1 @@ -Subproject commit 4a82388ebc5138c8289fe9bc602cb0b3e32cd617 +Subproject commit 78223426e7c66d631117c0a9da1b7f3fde4d23a5 From 6a405f4cadba27e044b0ae6c07c539d8c84b89c8 Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Tue, 3 Sep 2019 15:42:34 +0800 Subject: [PATCH 09/16] fix errors in integration_golangapi_scheduler_test --- .../integration_golangapi_scheduler_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/integration/integration_golangapi_scheduler_test.go b/src/integration/integration_golangapi_scheduler_test.go index 211f11e7f..2a65e1241 100644 --- a/src/integration/integration_golangapi_scheduler_test.go +++ b/src/integration/integration_golangapi_scheduler_test.go @@ -237,7 +237,7 @@ var _ = Describe("Integration_GolangApi_Scheduler", func() { Context("public api", func() { Context("Policies with schedules", func() { It("creates a policy and associated schedules", func() { - policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + policyStr = setPolicyRecurringDate(readPolicyFromFile("fakePolicyWithSchedule.json")) doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) @@ -278,14 +278,14 @@ var _ = Describe("Integration_GolangApi_Scheduler", func() { Context("Update policies with schedules", func() { BeforeEach(func() { //attach a policy first with 4 recurring and 2 specific_date schedules - policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + policyStr = setPolicyRecurringDate(readPolicyFromFile("fakePolicyWithSchedule.json")) doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) }) It("updates the policy and schedules", func() { //attach another policy with 3 recurring and 1 specific_date schedules - policyStr = readPolicyFromFile("fakePolicyWithScheduleAnother.json") + policyStr = setPolicyRecurringDate(readPolicyFromFile("fakePolicyWithScheduleAnother.json")) doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) @@ -349,7 +349,7 @@ var _ = Describe("Integration_GolangApi_Scheduler", func() { Context("public api", func() { Context("Policies with schedules", func() { It("creates a policy and associated schedules", func() { - policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + policyStr = setPolicyRecurringDate(readPolicyFromFile("fakePolicyWithSchedule.json")) doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) @@ -385,13 +385,13 @@ var _ = Describe("Integration_GolangApi_Scheduler", func() { Context("Update policies with schedules", func() { BeforeEach(func() { //attach a policy first with 4 recurring and 2 specific_date schedules - policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") + policyStr = setPolicyRecurringDate(readPolicyFromFile("fakePolicyWithSchedule.json")) doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) }) It("updates the policy and schedules", func() { //attach another policy with 3 recurring and 1 specific_date schedules - policyStr = readPolicyFromFile("fakePolicyWithScheduleAnother.json") + policyStr = setPolicyRecurringDate(readPolicyFromFile("fakePolicyWithScheduleAnother.json")) doAttachPolicy(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) checkApiServerContent(appId, policyStr, http.StatusOK, components.Ports[GolangAPIServer], httpClientForPublicApi) From 26f5492c5479e20669e0a36586da1fead793356a Mon Sep 17 00:00:00 2001 From: zyjiaobj Date: Thu, 5 Sep 2019 09:15:29 +0800 Subject: [PATCH 10/16] [api] add validation on the length of the metric type (#526) --- .../policyvalidator/policy_json.schema.json | 3 ++- .../policyvalidator/policy_validator_test.go | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/autoscaler/api/policyvalidator/policy_json.schema.json b/src/autoscaler/api/policyvalidator/policy_json.schema.json index 0b33287c1..1b85ce821 100644 --- a/src/autoscaler/api/policyvalidator/policy_json.schema.json +++ b/src/autoscaler/api/policyvalidator/policy_json.schema.json @@ -45,7 +45,8 @@ "$id": "#/properties/scaling_rules/items/properties/metric_type", "type": "string", "title": "The Metric_type Schema", - "pattern": "^[a-zA-Z0-9_]+$" + "pattern": "^[a-zA-Z0-9_]+$", + "maxLength": 100 }, "breach_duration_secs": { "$id": "#/properties/scaling_rules/items/properties/breach_duration_secs", diff --git a/src/autoscaler/api/policyvalidator/policy_validator_test.go b/src/autoscaler/api/policyvalidator/policy_validator_test.go index dc884a0dc..b556cfeb1 100644 --- a/src/autoscaler/api/policyvalidator/policy_validator_test.go +++ b/src/autoscaler/api/policyvalidator/policy_validator_test.go @@ -235,6 +235,33 @@ var _ = Describe("PolicyValidator", func() { }) }) + Context("when metric_type is too lang", func() { + BeforeEach(func() { + policyString = `{ + "instance_max_count":4, + "instance_min_count":1, + "scaling_rules":[ + { + "metric_type": "custom_metric_custom_metric_custom_metric_custom_metric_custom_metric_custom_metric_custom_metric_custom_metric", + "breach_duration_secs":600, + "threshold":90, + "operator":">=", + "cool_down_secs":300, + "adjustment":"+1" + }] + }` + }) + It("should fail", func() { + Expect(valid).To(BeFalse()) + Expect(errResult).To(Equal(&[]PolicyValidationErrors{ + { + Context: "(root).scaling_rules.0.metric_type", + Description: "String length must be less than or equal to 100", + }, + })) + }) + }) + Context("when threshold is missing", func() { BeforeEach(func() { policyString = `{ From 8c10a3befb4c43801abef08325d81c4d5b91cc84 Mon Sep 17 00:00:00 2001 From: qibobo Date: Wed, 4 Sep 2019 15:20:51 +0800 Subject: [PATCH 11/16] add pprof endpoints for all golang components --- .../api/brokerserver/broker_server.go | 9 ++-- .../brokerserver/broker_server_suite_test.go | 4 +- src/autoscaler/api/cmd/api/api_suite_test.go | 8 +++- src/autoscaler/api/cmd/api/api_test.go | 42 +++++++++++++++++++ src/autoscaler/api/cmd/api/main.go | 25 +++++++++-- src/autoscaler/api/config/config.go | 1 + src/autoscaler/api/config/config_test.go | 40 +++++++++++++++++- .../api/publicapiserver/public_api_server.go | 9 +++- .../publicapiserver_suite_test.go | 4 +- .../eventgenerator_suite_test.go | 7 ++++ .../cmd/eventgenerator/eventgenerator_test.go | 42 +++++++++++++++++++ src/autoscaler/healthendpoint/server.go | 12 ++++-- .../metricscollector/metricscollector_test.go | 20 +++++++++ .../metricsforwarder/metricsforwarder_test.go | 20 +++++++++ .../cmd/metricsgateway/metricsgateway_test.go | 20 +++++++++ .../cmd/metricsserver/metricsserver_test.go | 20 +++++++++ .../operator/cmd/operator/operator_test.go | 20 +++++++++ .../cmd/scalingengine/scalingengine_test.go | 20 +++++++++ 18 files changed, 304 insertions(+), 19 deletions(-) diff --git a/src/autoscaler/api/brokerserver/broker_server.go b/src/autoscaler/api/brokerserver/broker_server.go index 8f74ba332..75c970558 100644 --- a/src/autoscaler/api/brokerserver/broker_server.go +++ b/src/autoscaler/api/brokerserver/broker_server.go @@ -4,10 +4,9 @@ import ( "fmt" "net/http" - "golang.org/x/crypto/bcrypt" - "autoscaler/api/config" "autoscaler/db" + "autoscaler/healthendpoint" "autoscaler/routes" "code.cloudfoundry.org/cfhttp" @@ -15,6 +14,7 @@ import ( "github.com/gorilla/mux" "github.com/tedsuo/ifrit" "github.com/tedsuo/ifrit/http_server" + "golang.org/x/crypto/bcrypt" ) type VarsFunc func(w http.ResponseWriter, r *http.Request, vars map[string]string) @@ -41,7 +41,7 @@ func (bam *basicAuthenticationMiddleware) Middleware(next http.Handler) http.Han }) } -func NewBrokerServer(logger lager.Logger, conf *config.Config, bindingdb db.BindingDB, policydb db.PolicyDB) (ifrit.Runner, error) { +func NewBrokerServer(logger lager.Logger, conf *config.Config, bindingdb db.BindingDB, policydb db.PolicyDB, httpStatusCollector healthendpoint.HTTPStatusCollector) (ifrit.Runner, error) { var usernameHash []byte if conf.BrokerUsernameHash != "" { @@ -71,12 +71,13 @@ func NewBrokerServer(logger lager.Logger, conf *config.Config, bindingdb db.Bind usernameHash: usernameHash, passwordHash: passwordHash, } - + httpStatusCollectMiddleware := healthendpoint.NewHTTPStatusCollectMiddleware(httpStatusCollector) ah := NewBrokerHandler(logger, conf, bindingdb, policydb) r := routes.BrokerRoutes() r.Use(basicAuthentication.Middleware) + r.Use(httpStatusCollectMiddleware.Collect) r.Get(routes.BrokerCatalogRouteName).Handler(VarsFunc(ah.GetBrokerCatalog)) r.Get(routes.BrokerCreateInstanceRouteName).Handler(VarsFunc(ah.CreateServiceInstance)) r.Get(routes.BrokerDeleteInstanceRouteName).Handler(VarsFunc(ah.DeleteServiceInstance)) diff --git a/src/autoscaler/api/brokerserver/broker_server_suite_test.go b/src/autoscaler/api/brokerserver/broker_server_suite_test.go index eff3e84bf..ea1375f37 100644 --- a/src/autoscaler/api/brokerserver/broker_server_suite_test.go +++ b/src/autoscaler/api/brokerserver/broker_server_suite_test.go @@ -64,8 +64,8 @@ var _ = BeforeSuite(func() { } fakeBindingDB := &fakes.FakeBindingDB{} fakePolicyDB := &fakes.FakePolicyDB{} - - httpServer, err := brokerserver.NewBrokerServer(lager.NewLogger("test"), conf, fakeBindingDB, fakePolicyDB) + httpStatusCollector := &fakes.FakeHTTPStatusCollector{} + httpServer, err := brokerserver.NewBrokerServer(lager.NewLogger("test"), conf, fakeBindingDB, fakePolicyDB, httpStatusCollector) Expect(err).NotTo(HaveOccurred()) serverUrl, err = url.Parse("http://127.0.0.1:" + strconv.Itoa(port)) diff --git a/src/autoscaler/api/cmd/api/api_suite_test.go b/src/autoscaler/api/cmd/api/api_suite_test.go index 25caf329d..fe728ceb8 100644 --- a/src/autoscaler/api/cmd/api/api_suite_test.go +++ b/src/autoscaler/api/cmd/api/api_suite_test.go @@ -39,10 +39,12 @@ var ( configFile *os.File apiHttpClient *http.Client brokerHttpClient *http.Client + healthHttpClient *http.Client catalogBytes []byte schedulerServer *ghttp.Server brokerPort int publicApiPort int + healthport int infoBytes []byte ccServer *ghttp.Server ) @@ -90,7 +92,7 @@ var _ = SynchronizedBeforeSuite(func() []byte { brokerPort = 8000 + GinkgoParallelNode() publicApiPort = 9000 + GinkgoParallelNode() - + healthport = 7000 + GinkgoParallelNode() testCertDir := "../../../../../test-certs" cfg.BrokerServer = config.ServerConfig{ @@ -166,6 +168,9 @@ var _ = SynchronizedBeforeSuite(func() []byte { cfg.CF.ClientID = "client-id" cfg.CF.Secret = "client-secret" cfg.CF.SkipSSLValidation = true + cfg.Health = models.HealthConfig{ + Port: healthport, + } configFile = writeConfig(&cfg) apiClientTLSConfig, err := cfhttp.NewTLSConfig( @@ -187,6 +192,7 @@ var _ = SynchronizedBeforeSuite(func() []byte { TLSClientConfig: brokerClientTLSConfig, }, } + healthHttpClient = &http.Client{} }) diff --git a/src/autoscaler/api/cmd/api/api_test.go b/src/autoscaler/api/cmd/api/api_test.go index 2525aa9ac..b65b9bfbe 100644 --- a/src/autoscaler/api/cmd/api/api_test.go +++ b/src/autoscaler/api/cmd/api/api_test.go @@ -171,5 +171,47 @@ var _ = Describe("Api", func() { }) }) }) + Describe("when Health server is ready to serve RESTful API", func() { + BeforeEach(func() { + runner.Start() + + }) + Context("when a request to query health comes", func() { + It("returns with a 200", func() { + rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d/health", healthport)) + Expect(err).NotTo(HaveOccurred()) + Expect(rsp.StatusCode).To(Equal(http.StatusOK)) + raw, _ := ioutil.ReadAll(rsp.Body) + healthData := string(raw) + Expect(healthData).To(ContainSubstring("autoscaler_golangapiserver_concurrent_http_request")) + Expect(healthData).To(ContainSubstring("autoscaler_golangapiserver_policyDB")) + Expect(healthData).To(ContainSubstring("autoscaler_golangapiserver_bindingDB")) + Expect(healthData).To(ContainSubstring("go_goroutines")) + Expect(healthData).To(ContainSubstring("go_memstats_alloc_bytes")) + rsp.Body.Close() + + }) + }) + Context("when a request to query profile comes", func() { + It("returns with a 200", func() { + rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d/debug/pprof", healthport)) + Expect(err).NotTo(HaveOccurred()) + Expect(rsp.StatusCode).To(Equal(http.StatusOK)) + raw, _ := ioutil.ReadAll(rsp.Body) + profileIndexBody := string(raw) + Expect(profileIndexBody).To(ContainSubstring("allocs")) + Expect(profileIndexBody).To(ContainSubstring("block")) + Expect(profileIndexBody).To(ContainSubstring("cmdline")) + Expect(profileIndexBody).To(ContainSubstring("goroutine")) + Expect(profileIndexBody).To(ContainSubstring("heap")) + Expect(profileIndexBody).To(ContainSubstring("mutex")) + Expect(profileIndexBody).To(ContainSubstring("profile")) + Expect(profileIndexBody).To(ContainSubstring("threadcreate")) + Expect(profileIndexBody).To(ContainSubstring("trace")) + rsp.Body.Close() + + }) + }) + }) }) diff --git a/src/autoscaler/api/cmd/api/main.go b/src/autoscaler/api/cmd/api/main.go index a82812478..4f0c1747e 100644 --- a/src/autoscaler/api/cmd/api/main.go +++ b/src/autoscaler/api/cmd/api/main.go @@ -12,10 +12,12 @@ import ( "autoscaler/cf" "autoscaler/db" "autoscaler/db/sqldb" + "autoscaler/healthendpoint" "autoscaler/helpers" "code.cloudfoundry.org/clock" "code.cloudfoundry.org/lager" + "github.com/prometheus/client_golang/prometheus" "github.com/tedsuo/ifrit" "github.com/tedsuo/ifrit/grouper" "github.com/tedsuo/ifrit/sigmon" @@ -61,6 +63,12 @@ func main() { os.Exit(1) } defer policyDb.Close() + + httpStatusCollector := healthendpoint.NewHTTPStatusCollector("autoscaler", "golangapiserver") + prometheusCollectors := []prometheus.Collector{ + healthendpoint.NewDatabaseStatusCollector("autoscaler", "golangapiserver", "policyDB", policyDb), + httpStatusCollector, + } var checkBindingFunc api.CheckBindingFunc if !conf.UseBuildInMode { var bindingDB db.BindingDB @@ -70,10 +78,12 @@ func main() { os.Exit(1) } defer bindingDB.Close() + prometheusCollectors = append(prometheusCollectors, + healthendpoint.NewDatabaseStatusCollector("autoscaler", "golangapiserver", "bindingDB", bindingDB)) checkBindingFunc = func(appId string) bool { return bindingDB.CheckServiceBinding(appId) } - brokerHttpServer, err := brokerserver.NewBrokerServer(logger.Session("broker_http_server"), conf, bindingDB, policyDb) + brokerHttpServer, err := brokerserver.NewBrokerServer(logger.Session("broker_http_server"), conf, bindingDB, policyDb, httpStatusCollector) if err != nil { logger.Error("failed to create broker http server", err) os.Exit(1) @@ -85,6 +95,9 @@ func main() { } } + promRegistry := prometheus.NewRegistry() + healthendpoint.RegisterCollectors(promRegistry, prometheusCollectors, true, logger.Session("golangapiserver-prometheus")) + paClock := clock.NewClock() cfClient := cf.NewCFClient(&conf.CF, logger.Session("cf"), paClock) err = cfClient.Login() @@ -93,13 +106,19 @@ func main() { os.Exit(1) } - publicApiHttpServer, err := publicapiserver.NewPublicApiServer(logger.Session("public_api_http_server"), conf, policyDb, checkBindingFunc, cfClient) + publicApiHttpServer, err := publicapiserver.NewPublicApiServer(logger.Session("public_api_http_server"), conf, policyDb, checkBindingFunc, cfClient, httpStatusCollector) if err != nil { logger.Error("failed to create public api http server", err) os.Exit(1) } + healthServer, err := healthendpoint.NewServer(logger.Session("health-server"), conf.Health.Port, promRegistry) + if err != nil { + logger.Error("failed to create health server", err) + os.Exit(1) + } - members = append(members, grouper.Member{"public_api_http_server", publicApiHttpServer}) + members = append(members, grouper.Member{"public_api_http_server", publicApiHttpServer}, + grouper.Member{"health_server", healthServer}) monitor := ifrit.Invoke(sigmon.New(grouper.NewOrdered(os.Interrupt, members))) diff --git a/src/autoscaler/api/config/config.go b/src/autoscaler/api/config/config.go index fe902cfe1..4f344177a 100644 --- a/src/autoscaler/api/config/config.go +++ b/src/autoscaler/api/config/config.go @@ -86,6 +86,7 @@ type Config struct { UseBuildInMode bool `yaml:"use_buildin_mode"` InfoFilePath string `yaml:"info_file_path"` MetricsForwarder MetricsForwarderConfig `yaml:"metrics_forwarder"` + Health models.HealthConfig `yaml:"health"` } func LoadConfig(reader io.Reader) (*Config, error) { diff --git a/src/autoscaler/api/config/config_test.go b/src/autoscaler/api/config/config_test.go index aaf9d4bf8..7d79265e2 100644 --- a/src/autoscaler/api/config/config_test.go +++ b/src/autoscaler/api/config/config_test.go @@ -280,11 +280,49 @@ cf: }) }) - Context("when it gives a non integer port", func() { + Context("when it gives a non integer broker_server port", func() { BeforeEach(func() { configBytes = []byte(` broker_server: port: port +public_api_server: + port: 8081 +health: + port: 8888 +`) + }) + + It("should error", func() { + Expect(err).To(BeAssignableToTypeOf(&yaml.TypeError{})) + Expect(err).To(MatchError(MatchRegexp("cannot unmarshal.*into int"))) + }) + }) + Context("when it gives a non integer public_api_server port", func() { + BeforeEach(func() { + configBytes = []byte(` +broker_server: + port: 8080 +public_api_server: + port: port +health: + port: 8888 +`) + }) + + It("should error", func() { + Expect(err).To(BeAssignableToTypeOf(&yaml.TypeError{})) + Expect(err).To(MatchError(MatchRegexp("cannot unmarshal.*into int"))) + }) + }) + Context("when it gives a non integer health server port", func() { + BeforeEach(func() { + configBytes = []byte(` +broker_server: + port: 8080 +public_api_server: + port: 8081 +health: + port: port `) }) diff --git a/src/autoscaler/api/publicapiserver/public_api_server.go b/src/autoscaler/api/publicapiserver/public_api_server.go index 9d71f5a42..24df40ca2 100644 --- a/src/autoscaler/api/publicapiserver/public_api_server.go +++ b/src/autoscaler/api/publicapiserver/public_api_server.go @@ -8,6 +8,7 @@ import ( "autoscaler/api/config" "autoscaler/cf" "autoscaler/db" + "autoscaler/healthendpoint" "autoscaler/routes" "code.cloudfoundry.org/cfhttp" @@ -24,16 +25,18 @@ func (vh VarsFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) { vh(w, r, vars) } -func NewPublicApiServer(logger lager.Logger, conf *config.Config, policydb db.PolicyDB, checkBindingFunc api.CheckBindingFunc, cfclient cf.CFClient) (ifrit.Runner, error) { +func NewPublicApiServer(logger lager.Logger, conf *config.Config, policydb db.PolicyDB, checkBindingFunc api.CheckBindingFunc, cfclient cf.CFClient, httpStatusCollector healthendpoint.HTTPStatusCollector) (ifrit.Runner, error) { pah := NewPublicApiHandler(logger, conf, policydb) mw := NewMiddleware(logger, cfclient, checkBindingFunc) - + httpStatusCollectMiddleware := healthendpoint.NewHTTPStatusCollectMiddleware(httpStatusCollector) r := routes.ApiOpenRoutes() + r.Use(httpStatusCollectMiddleware.Collect) r.Get(routes.PublicApiInfoRouteName).Handler(VarsFunc(pah.GetApiInfo)) r.Get(routes.PublicApiHealthRouteName).Handler(VarsFunc(pah.GetHealth)) rp := routes.ApiRoutes() rp.Use(mw.Oauth) + rp.Use(httpStatusCollectMiddleware.Collect) rp.Get(routes.PublicApiScalingHistoryRouteName).Handler(VarsFunc(pah.GetScalingHistories)) rp.Get(routes.PublicApiMetricsHistoryRouteName).Handler(VarsFunc(pah.GetInstanceMetricsHistories)) rp.Get(routes.PublicApiAggregatedMetricsHistoryRouteName).Handler(VarsFunc(pah.GetAggregatedMetricsHistories)) @@ -43,6 +46,7 @@ func NewPublicApiServer(logger lager.Logger, conf *config.Config, policydb db.Po if !conf.UseBuildInMode { rpolicy.Use(mw.CheckServiceBinding) } + rpolicy.Use(httpStatusCollectMiddleware.Collect) rpolicy.Get(routes.PublicApiGetPolicyRouteName).Handler(VarsFunc(pah.GetScalingPolicy)) rpolicy.Get(routes.PublicApiAttachPolicyRouteName).Handler(VarsFunc(pah.AttachScalingPolicy)) rpolicy.Get(routes.PublicApiDetachPolicyRouteName).Handler(VarsFunc(pah.DetachScalingPolicy)) @@ -51,6 +55,7 @@ func NewPublicApiServer(logger lager.Logger, conf *config.Config, policydb db.Po if !conf.UseBuildInMode { rcredential.Use(mw.RejectCredentialOperationInServiceOffering) } + rcredential.Use(httpStatusCollectMiddleware.Collect) rcredential.Use(mw.Oauth) rcredential.Get(routes.PublicApiCreateCredentialRouteName).Handler(VarsFunc(pah.CreateCredential)) rcredential.Get(routes.PublicApiDeleteCredentialRouteName).Handler(VarsFunc(pah.DeleteCredential)) diff --git a/src/autoscaler/api/publicapiserver/publicapiserver_suite_test.go b/src/autoscaler/api/publicapiserver/publicapiserver_suite_test.go index 227f4da4f..e15bcf8aa 100644 --- a/src/autoscaler/api/publicapiserver/publicapiserver_suite_test.go +++ b/src/autoscaler/api/publicapiserver/publicapiserver_suite_test.go @@ -89,8 +89,8 @@ var _ = BeforeSuite(func() { return hasBinding } fakeCFClient = &fakes.FakeCFClient{} - - httpServer, err := publicapiserver.NewPublicApiServer(lagertest.NewTestLogger("public_apiserver"), conf, fakePolicyDB, checkBindingFunc, fakeCFClient) + httpStatusCollector := &fakes.FakeHTTPStatusCollector{} + httpServer, err := publicapiserver.NewPublicApiServer(lagertest.NewTestLogger("public_apiserver"), conf, fakePolicyDB, checkBindingFunc, fakeCFClient, httpStatusCollector) Expect(err).NotTo(HaveOccurred()) serverUrl, err = url.Parse("http://127.0.0.1:" + strconv.Itoa(apiPort)) diff --git a/src/autoscaler/eventgenerator/cmd/eventgenerator/eventgenerator_suite_test.go b/src/autoscaler/eventgenerator/cmd/eventgenerator/eventgenerator_suite_test.go index a39dbbe6a..82ea61e52 100644 --- a/src/autoscaler/eventgenerator/cmd/eventgenerator/eventgenerator_suite_test.go +++ b/src/autoscaler/eventgenerator/cmd/eventgenerator/eventgenerator_suite_test.go @@ -36,7 +36,9 @@ var ( configFile *os.File conf config.Config egPort int + healthport int httpClient *http.Client + healthHttpClient *http.Client metricCollector *ghttp.Server scalingEngine *ghttp.Server breachDurationSecs int = 10 @@ -141,6 +143,7 @@ func initDB() { err = egDB.Close() Expect(err).NotTo(HaveOccurred()) + healthHttpClient = &http.Client{} } func initHttpEndPoints() { @@ -175,6 +178,7 @@ func initConfig() { testCertDir := "../../../../../test-certs" egPort = 7000 + GinkgoParallelNode() + healthport = 8000 + GinkgoParallelNode() conf = config.Config{ Logging: helpers.LoggingConfig{ Level: "debug", @@ -241,6 +245,9 @@ func initConfig() { DefaultBreachDurationSecs: 600, DefaultStatWindowSecs: 300, HttpClientTimeout: 10 * time.Second, + Health: models.HealthConfig{ + Port: healthport, + }, } configFile = writeConfig(&conf) diff --git a/src/autoscaler/eventgenerator/cmd/eventgenerator/eventgenerator_test.go b/src/autoscaler/eventgenerator/cmd/eventgenerator/eventgenerator_test.go index 0d296b8de..ee58a8074 100644 --- a/src/autoscaler/eventgenerator/cmd/eventgenerator/eventgenerator_test.go +++ b/src/autoscaler/eventgenerator/cmd/eventgenerator/eventgenerator_test.go @@ -134,5 +134,47 @@ var _ = Describe("Eventgenerator", func() { }) }) + Describe("when Health server is ready to serve RESTful API", func() { + BeforeEach(func() { + runner.Start() + + }) + Context("when a request to query health comes", func() { + It("returns with a 200", func() { + rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d/health", healthport)) + Expect(err).NotTo(HaveOccurred()) + Expect(rsp.StatusCode).To(Equal(http.StatusOK)) + raw, _ := ioutil.ReadAll(rsp.Body) + healthData := string(raw) + Expect(healthData).To(ContainSubstring("autoscaler_eventgenerator_concurrent_http_request")) + Expect(healthData).To(ContainSubstring("autoscaler_eventgenerator_policyDB")) + Expect(healthData).To(ContainSubstring("autoscaler_eventgenerator_appMetricDB")) + Expect(healthData).To(ContainSubstring("go_goroutines")) + Expect(healthData).To(ContainSubstring("go_memstats_alloc_bytes")) + rsp.Body.Close() + + }) + }) + Context("when a request to query profile comes", func() { + It("returns with a 200", func() { + rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d/debug/pprof", healthport)) + Expect(err).NotTo(HaveOccurred()) + Expect(rsp.StatusCode).To(Equal(http.StatusOK)) + raw, _ := ioutil.ReadAll(rsp.Body) + profileIndexBody := string(raw) + Expect(profileIndexBody).To(ContainSubstring("allocs")) + Expect(profileIndexBody).To(ContainSubstring("block")) + Expect(profileIndexBody).To(ContainSubstring("cmdline")) + Expect(profileIndexBody).To(ContainSubstring("goroutine")) + Expect(profileIndexBody).To(ContainSubstring("heap")) + Expect(profileIndexBody).To(ContainSubstring("mutex")) + Expect(profileIndexBody).To(ContainSubstring("profile")) + Expect(profileIndexBody).To(ContainSubstring("threadcreate")) + Expect(profileIndexBody).To(ContainSubstring("trace")) + rsp.Body.Close() + + }) + }) + }) }) diff --git a/src/autoscaler/healthendpoint/server.go b/src/autoscaler/healthendpoint/server.go index b576eda88..1732d5c80 100644 --- a/src/autoscaler/healthendpoint/server.go +++ b/src/autoscaler/healthendpoint/server.go @@ -1,19 +1,23 @@ package healthendpoint import ( - "fmt" - "code.cloudfoundry.org/lager" + "fmt" + "github.com/gorilla/mux" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/tedsuo/ifrit" "github.com/tedsuo/ifrit/http_server" + "net/http" + _ "net/http/pprof" ) func NewServer(logger lager.Logger, port int, gatherer prometheus.Gatherer) (ifrit.Runner, error) { - + router := mux.NewRouter() r := promhttp.HandlerFor(gatherer, promhttp.HandlerOpts{}) + router.PathPrefix("/debug/pprof").Handler(http.DefaultServeMux) + router.PathPrefix("").Handler(r) addr := fmt.Sprintf("0.0.0.0:%d", port) logger.Info("new-health-server", lager.Data{"addr": addr}) - return http_server.New(addr, r), nil + return http_server.New(addr, router), nil } diff --git a/src/autoscaler/metricscollector/cmd/metricscollector/metricscollector_test.go b/src/autoscaler/metricscollector/cmd/metricscollector/metricscollector_test.go index 37a4eca2f..d096d4598 100644 --- a/src/autoscaler/metricscollector/cmd/metricscollector/metricscollector_test.go +++ b/src/autoscaler/metricscollector/cmd/metricscollector/metricscollector_test.go @@ -158,6 +158,26 @@ var _ = Describe("MetricsCollector", func() { }) }) + Context("when a request to query profile comes", func() { + It("returns with a 200", func() { + rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d/debug/pprof", healthport)) + Expect(err).NotTo(HaveOccurred()) + Expect(rsp.StatusCode).To(Equal(http.StatusOK)) + raw, _ := ioutil.ReadAll(rsp.Body) + profileIndexBody := string(raw) + Expect(profileIndexBody).To(ContainSubstring("allocs")) + Expect(profileIndexBody).To(ContainSubstring("block")) + Expect(profileIndexBody).To(ContainSubstring("cmdline")) + Expect(profileIndexBody).To(ContainSubstring("goroutine")) + Expect(profileIndexBody).To(ContainSubstring("heap")) + Expect(profileIndexBody).To(ContainSubstring("mutex")) + Expect(profileIndexBody).To(ContainSubstring("profile")) + Expect(profileIndexBody).To(ContainSubstring("threadcreate")) + Expect(profileIndexBody).To(ContainSubstring("trace")) + rsp.Body.Close() + + }) + }) }) }) diff --git a/src/autoscaler/metricsforwarder/cmd/metricsforwarder/metricsforwarder_test.go b/src/autoscaler/metricsforwarder/cmd/metricsforwarder/metricsforwarder_test.go index 24a5fbabd..a655d456d 100644 --- a/src/autoscaler/metricsforwarder/cmd/metricsforwarder/metricsforwarder_test.go +++ b/src/autoscaler/metricsforwarder/cmd/metricsforwarder/metricsforwarder_test.go @@ -153,6 +153,26 @@ var _ = Describe("Metricsforwarder", func() { }) }) + Context("when a request to query profile comes", func() { + It("returns with a 200", func() { + rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d/debug/pprof", healthport)) + Expect(err).NotTo(HaveOccurred()) + Expect(rsp.StatusCode).To(Equal(http.StatusOK)) + raw, _ := ioutil.ReadAll(rsp.Body) + profileIndexBody := string(raw) + Expect(profileIndexBody).To(ContainSubstring("allocs")) + Expect(profileIndexBody).To(ContainSubstring("block")) + Expect(profileIndexBody).To(ContainSubstring("cmdline")) + Expect(profileIndexBody).To(ContainSubstring("goroutine")) + Expect(profileIndexBody).To(ContainSubstring("heap")) + Expect(profileIndexBody).To(ContainSubstring("mutex")) + Expect(profileIndexBody).To(ContainSubstring("profile")) + Expect(profileIndexBody).To(ContainSubstring("threadcreate")) + Expect(profileIndexBody).To(ContainSubstring("trace")) + rsp.Body.Close() + + }) + }) AfterEach(func() { runner.KillWithFire() }) diff --git a/src/autoscaler/metricsgateway/cmd/metricsgateway/metricsgateway_test.go b/src/autoscaler/metricsgateway/cmd/metricsgateway/metricsgateway_test.go index d4b49c69a..5b686962a 100644 --- a/src/autoscaler/metricsgateway/cmd/metricsgateway/metricsgateway_test.go +++ b/src/autoscaler/metricsgateway/cmd/metricsgateway/metricsgateway_test.go @@ -122,5 +122,25 @@ var _ = Describe("Metricsgateway", func() { }) }) + Context("when a request to query profile comes", func() { + It("returns with a 200", func() { + rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d/debug/pprof", healthport)) + Expect(err).NotTo(HaveOccurred()) + Expect(rsp.StatusCode).To(Equal(http.StatusOK)) + raw, _ := ioutil.ReadAll(rsp.Body) + profileIndexBody := string(raw) + Expect(profileIndexBody).To(ContainSubstring("allocs")) + Expect(profileIndexBody).To(ContainSubstring("block")) + Expect(profileIndexBody).To(ContainSubstring("cmdline")) + Expect(profileIndexBody).To(ContainSubstring("goroutine")) + Expect(profileIndexBody).To(ContainSubstring("heap")) + Expect(profileIndexBody).To(ContainSubstring("mutex")) + Expect(profileIndexBody).To(ContainSubstring("profile")) + Expect(profileIndexBody).To(ContainSubstring("threadcreate")) + Expect(profileIndexBody).To(ContainSubstring("trace")) + rsp.Body.Close() + + }) + }) }) }) diff --git a/src/autoscaler/metricsserver/cmd/metricsserver/metricsserver_test.go b/src/autoscaler/metricsserver/cmd/metricsserver/metricsserver_test.go index 11e3aaf89..7463b5f49 100644 --- a/src/autoscaler/metricsserver/cmd/metricsserver/metricsserver_test.go +++ b/src/autoscaler/metricsserver/cmd/metricsserver/metricsserver_test.go @@ -132,6 +132,26 @@ var _ = Describe("MetricsServer", func() { }) }) + Context("when a request to query profile comes", func() { + It("returns with a 200", func() { + rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d/debug/pprof", healthport)) + Expect(err).NotTo(HaveOccurred()) + Expect(rsp.StatusCode).To(Equal(http.StatusOK)) + raw, _ := ioutil.ReadAll(rsp.Body) + profileIndexBody := string(raw) + Expect(profileIndexBody).To(ContainSubstring("allocs")) + Expect(profileIndexBody).To(ContainSubstring("block")) + Expect(profileIndexBody).To(ContainSubstring("cmdline")) + Expect(profileIndexBody).To(ContainSubstring("goroutine")) + Expect(profileIndexBody).To(ContainSubstring("heap")) + Expect(profileIndexBody).To(ContainSubstring("mutex")) + Expect(profileIndexBody).To(ContainSubstring("profile")) + Expect(profileIndexBody).To(ContainSubstring("threadcreate")) + Expect(profileIndexBody).To(ContainSubstring("trace")) + rsp.Body.Close() + + }) + }) }) //TODO : Add test cases for testing WebServer endpoints diff --git a/src/autoscaler/operator/cmd/operator/operator_test.go b/src/autoscaler/operator/cmd/operator/operator_test.go index a0a9eadf4..b0938288c 100644 --- a/src/autoscaler/operator/cmd/operator/operator_test.go +++ b/src/autoscaler/operator/cmd/operator/operator_test.go @@ -362,5 +362,25 @@ var _ = Describe("Operator", func() { }) }) + Context("when a request to query profile comes", func() { + It("returns with a 200", func() { + rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d/debug/pprof", healthport)) + Expect(err).NotTo(HaveOccurred()) + Expect(rsp.StatusCode).To(Equal(http.StatusOK)) + raw, _ := ioutil.ReadAll(rsp.Body) + profileIndexBody := string(raw) + Expect(profileIndexBody).To(ContainSubstring("allocs")) + Expect(profileIndexBody).To(ContainSubstring("block")) + Expect(profileIndexBody).To(ContainSubstring("cmdline")) + Expect(profileIndexBody).To(ContainSubstring("goroutine")) + Expect(profileIndexBody).To(ContainSubstring("heap")) + Expect(profileIndexBody).To(ContainSubstring("mutex")) + Expect(profileIndexBody).To(ContainSubstring("profile")) + Expect(profileIndexBody).To(ContainSubstring("threadcreate")) + Expect(profileIndexBody).To(ContainSubstring("trace")) + rsp.Body.Close() + + }) + }) }) }) diff --git a/src/autoscaler/scalingengine/cmd/scalingengine/scalingengine_test.go b/src/autoscaler/scalingengine/cmd/scalingengine/scalingengine_test.go index a52c817a4..e5e684cb3 100644 --- a/src/autoscaler/scalingengine/cmd/scalingengine/scalingengine_test.go +++ b/src/autoscaler/scalingengine/cmd/scalingengine/scalingengine_test.go @@ -217,5 +217,25 @@ var _ = Describe("Main", func() { }) }) + Context("when a request to query profile comes", func() { + It("returns with a 200", func() { + rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d/debug/pprof", healthport)) + Expect(err).NotTo(HaveOccurred()) + Expect(rsp.StatusCode).To(Equal(http.StatusOK)) + raw, _ := ioutil.ReadAll(rsp.Body) + profileIndexBody := string(raw) + Expect(profileIndexBody).To(ContainSubstring("allocs")) + Expect(profileIndexBody).To(ContainSubstring("block")) + Expect(profileIndexBody).To(ContainSubstring("cmdline")) + Expect(profileIndexBody).To(ContainSubstring("goroutine")) + Expect(profileIndexBody).To(ContainSubstring("heap")) + Expect(profileIndexBody).To(ContainSubstring("mutex")) + Expect(profileIndexBody).To(ContainSubstring("profile")) + Expect(profileIndexBody).To(ContainSubstring("threadcreate")) + Expect(profileIndexBody).To(ContainSubstring("trace")) + rsp.Body.Close() + + }) + }) }) }) From 16242fbb665444ce18eb28d8837ae46ee2ec255e Mon Sep 17 00:00:00 2001 From: qibobo Date: Thu, 5 Sep 2019 11:17:20 +0800 Subject: [PATCH 12/16] update document for golang version (#525) --- README.md | 2 +- src/autoscaler/eventgenerator/README.md | 2 +- src/autoscaler/metricscollector/README.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 58b387a5b..845c34816 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ You can follow the development progress on [Pivotal Tracker][t]. * Node 6.2 or above * NPM 3.9.5 or above * [Cloud Foundry cf command line][f] -* Go 1.7 +* Go 1.11 or above ### Database requirement diff --git a/src/autoscaler/eventgenerator/README.md b/src/autoscaler/eventgenerator/README.md index 76a936a93..271b50bbc 100644 --- a/src/autoscaler/eventgenerator/README.md +++ b/src/autoscaler/eventgenerator/README.md @@ -6,7 +6,7 @@ Data Aggregator is one of the components of CF `app-autoscaler`. ### System requirements: -* Go 1.6 or above +* Go 1.11 or above ### Build and test diff --git a/src/autoscaler/metricscollector/README.md b/src/autoscaler/metricscollector/README.md index 5472f03c9..2d2fc1dd1 100644 --- a/src/autoscaler/metricscollector/README.md +++ b/src/autoscaler/metricscollector/README.md @@ -6,7 +6,7 @@ Metrics Collector is one of the components of CF `app-autoscaler`. It is used to ### System requirements: -* Go 1.6 or above +* Go 1.11 or above * Cloud Foundry release 235 or later ### Build and test From 128ecfa0745443b71b58ffeab1477c9988edde40 Mon Sep 17 00:00:00 2001 From: qibobo Date: Thu, 5 Sep 2019 15:53:07 +0800 Subject: [PATCH 13/16] enable db transaction timeout & rollback db transaction if there is an error --- .../policyvalidator/policy_validator_test.go | 2 +- src/autoscaler/db/sqldb/appmetric_sqldb.go | 14 +++-- .../db/sqldb/appmetric_sqldb_test.go | 55 +++++++++++++++++-- .../db/sqldb/instancemetrics_sqldb.go | 11 +++- .../db/sqldb/instancemetrics_sqldb_test.go | 50 +++++++++++++++++ .../eventgenerator/aggregator/aggregator.go | 21 ++++--- .../aggregator/aggregator_test.go | 50 +++++++++++------ .../metricscollector/collector/collector.go | 14 +++-- .../metricsserver/collector/collector.go | 2 +- .../metricsserver/collector/collector_test.go | 17 ++++++ 10 files changed, 193 insertions(+), 43 deletions(-) diff --git a/src/autoscaler/api/policyvalidator/policy_validator_test.go b/src/autoscaler/api/policyvalidator/policy_validator_test.go index b556cfeb1..fa1ccfce4 100644 --- a/src/autoscaler/api/policyvalidator/policy_validator_test.go +++ b/src/autoscaler/api/policyvalidator/policy_validator_test.go @@ -235,7 +235,7 @@ var _ = Describe("PolicyValidator", func() { }) }) - Context("when metric_type is too lang", func() { + Context("when metric_type is too long", func() { BeforeEach(func() { policyString = `{ "instance_max_count":4, diff --git a/src/autoscaler/db/sqldb/appmetric_sqldb.go b/src/autoscaler/db/sqldb/appmetric_sqldb.go index fa395ab0b..acb403fe1 100644 --- a/src/autoscaler/db/sqldb/appmetric_sqldb.go +++ b/src/autoscaler/db/sqldb/appmetric_sqldb.go @@ -3,6 +3,7 @@ package sqldb import ( "autoscaler/db" "autoscaler/models" + "context" "code.cloudfoundry.org/lager" . "github.com/lib/pq" @@ -62,39 +63,44 @@ func (adb *AppMetricSQLDB) SaveAppMetric(appMetric *models.AppMetric) error { return err } func (adb *AppMetricSQLDB) SaveAppMetricsInBulk(appMetrics []*models.AppMetric) error { - txn, err := adb.sqldb.Begin() + ctx, cancelFunc := context.WithTimeout(context.Background(), 5*time.Second) + defer cancelFunc() + txn, err := adb.sqldb.BeginTx(ctx, nil) if err != nil { adb.logger.Error("failed-to-start-transaction", err) return err } - stmt, err := txn.Prepare(CopyIn("app_metric", "app_id", "metric_type", "unit", "timestamp", "value")) if err != nil { adb.logger.Error("failed-to-prepare-statement", err) + txn.Rollback() return err } for _, appMetric := range appMetrics { _, err := stmt.Exec(appMetric.AppId, appMetric.MetricType, appMetric.Unit, appMetric.Timestamp, appMetric.Value) if err != nil { adb.logger.Error("failed-to-execute", err) + txn.Rollback() + return err } } - _, err = stmt.Exec() if err != nil { adb.logger.Error("failed-to-execute-statement", err) + txn.Rollback() return err } - err = stmt.Close() if err != nil { adb.logger.Error("failed-to-close-statement", err) + txn.Rollback() return err } err = txn.Commit() if err != nil { adb.logger.Error("failed-to-commit-transaction", err) + txn.Rollback() return err } diff --git a/src/autoscaler/db/sqldb/appmetric_sqldb_test.go b/src/autoscaler/db/sqldb/appmetric_sqldb_test.go index 62eda9388..5e6c7a021 100644 --- a/src/autoscaler/db/sqldb/appmetric_sqldb_test.go +++ b/src/autoscaler/db/sqldb/appmetric_sqldb_test.go @@ -1,6 +1,10 @@ package sqldb_test import ( + "os" + "sync" + "time" + "autoscaler/db" . "autoscaler/db/sqldb" "autoscaler/models" @@ -9,9 +13,6 @@ import ( "github.com/lib/pq" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - - "os" - "time" ) var _ = Describe("AppMetricSQLDB", func() { @@ -24,7 +25,7 @@ var _ = Describe("AppMetricSQLDB", func() { start, end int64 before int64 appId, metricName string - testMetricName string = "Test-Metric-Name" + testMetricName string testMetricUnit string = "Test-Metric-Unit" testAppId string = "Test-App-ID" orderType db.OrderType @@ -38,6 +39,8 @@ var _ = Describe("AppMetricSQLDB", func() { MaxIdleConnections: 5, ConnectionMaxLifetime: 10 * time.Second, } + testMetricName = "Test-Metric-Name" + }) Context("NewAppMetricSQLDB", func() { @@ -139,6 +142,50 @@ var _ = Describe("AppMetricSQLDB", func() { Expect(hasAppMetric(testAppId, testMetricName, 22222222, "400")).To(BeTrue()) }) }) + Context("When there are errors in transaction", func() { + var lock *sync.Mutex = &sync.Mutex{} + var count int = 0 + BeforeEach(func() { + testMetricName = "Test-Metric-Name-this-is-a-too-long-metric-name-too-looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong" + appMetrics := []*models.AppMetric{ + &models.AppMetric{ + AppId: testAppId, + MetricType: testMetricName, + Unit: testMetricUnit, + Timestamp: 11111111, + Value: "300", + }, + &models.AppMetric{ + AppId: testAppId, + MetricType: testMetricName, + Unit: testMetricUnit, + Timestamp: 22222222, + Value: "400", + }, + } + for i := 0; i < 100; i++ { + go func(count *int) { + err := adb.SaveAppMetricsInBulk(appMetrics) + Expect(err).To(HaveOccurred()) + lock.Lock() + *count = *count + 1 + lock.Unlock() + }(&count) + + } + + }) + It("all connections should be released after transactions' rolling back", func() { + Eventually(func() int { + lock.Lock() + defer lock.Unlock() + return count + }, 120*time.Second, 1*time.Second).Should(Equal(100)) + Eventually(func() int { + return adb.GetDBStatus().OpenConnections + }, 120*time.Second, 10*time.Millisecond).Should(BeZero()) + }) + }) }) Context("RetrieveAppMetrics", func() { BeforeEach(func() { diff --git a/src/autoscaler/db/sqldb/instancemetrics_sqldb.go b/src/autoscaler/db/sqldb/instancemetrics_sqldb.go index ba8d97afe..d3d1fdf63 100644 --- a/src/autoscaler/db/sqldb/instancemetrics_sqldb.go +++ b/src/autoscaler/db/sqldb/instancemetrics_sqldb.go @@ -7,6 +7,7 @@ import ( "code.cloudfoundry.org/lager" . "github.com/lib/pq" + "context" "database/sql" "time" ) @@ -62,7 +63,9 @@ func (idb *InstanceMetricsSQLDB) SaveMetric(metric *models.AppInstanceMetric) er } func (idb *InstanceMetricsSQLDB) SaveMetricsInBulk(metrics []*models.AppInstanceMetric) error { - txn, err := idb.sqldb.Begin() + ctx, cancelFunc := context.WithTimeout(context.Background(), 5*time.Second) + defer cancelFunc() + txn, err := idb.sqldb.BeginTx(ctx, nil) if err != nil { idb.logger.Error("failed-to-start-transaction", err) return err @@ -71,30 +74,36 @@ func (idb *InstanceMetricsSQLDB) SaveMetricsInBulk(metrics []*models.AppInstance stmt, err := txn.Prepare(CopyIn("appinstancemetrics", "appid", "instanceindex", "collectedat", "name", "unit", "value", "timestamp")) if err != nil { idb.logger.Error("failed-to-prepare-statement", err) + txn.Rollback() return err } for _, metric := range metrics { _, err := stmt.Exec(metric.AppId, metric.InstanceIndex, metric.CollectedAt, metric.Name, metric.Unit, metric.Value, metric.Timestamp) if err != nil { idb.logger.Error("failed-to-execute", err) + txn.Rollback() + return err } } _, err = stmt.Exec() if err != nil { idb.logger.Error("failed-to-execute-statement", err) + txn.Rollback() return err } err = stmt.Close() if err != nil { idb.logger.Error("failed-to-close-statement", err) + txn.Rollback() return err } err = txn.Commit() if err != nil { idb.logger.Error("failed-to-commit-transaction", err) + txn.Rollback() return err } diff --git a/src/autoscaler/db/sqldb/instancemetrics_sqldb_test.go b/src/autoscaler/db/sqldb/instancemetrics_sqldb_test.go index 3088b7c0e..a25542973 100644 --- a/src/autoscaler/db/sqldb/instancemetrics_sqldb_test.go +++ b/src/autoscaler/db/sqldb/instancemetrics_sqldb_test.go @@ -12,6 +12,7 @@ import ( "github.com/onsi/gomega/gstruct" "os" + "sync" "time" ) @@ -45,6 +46,7 @@ var _ = Describe("InstancemetricsSqldb", func() { ConnectionMaxLifetime: 10 * time.Second, } instanceIndex = -1 + testMetricName = "TestMetricType" }) Describe("NewInstanceMetricsSQLDB", func() { @@ -187,6 +189,54 @@ var _ = Describe("InstancemetricsSqldb", func() { Expect(hasInstanceMetric(testAppId, 1, testMetricName, 220000)).To(BeTrue()) }) }) + + Context("When there are errors in transaction", func() { + var lock *sync.Mutex = &sync.Mutex{} + var count int = 0 + BeforeEach(func() { + testMetricName = "This-is-a-too-long-meitrc-name-too-loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong" + metric1 := models.AppInstanceMetric{ + AppId: testAppId, + InstanceIndex: 0, + CollectedAt: 111111, + Name: testMetricName, + Unit: testMetricUnit, + Value: "123", + Timestamp: 110000, + } + metric2 := models.AppInstanceMetric{ + AppId: testAppId, + InstanceIndex: 1, + CollectedAt: 222222, + Name: testMetricName, + Unit: testMetricUnit, + Value: "234", + Timestamp: 220000, + } + + for i := 0; i < 100; i++ { + go func(count *int) { + err := idb.SaveMetricsInBulk([]*models.AppInstanceMetric{&metric1, &metric2}) + Expect(err).To(HaveOccurred()) + lock.Lock() + *count = *count + 1 + lock.Unlock() + }(&count) + + } + }) + + It("all connections should be released after transactions' rolling back", func() { + Eventually(func() int { + lock.Lock() + defer lock.Unlock() + return count + }, 120*time.Second, 1*time.Second).Should(Equal(100)) + Eventually(func() int { + return idb.GetDBStatus().OpenConnections + }, 120*time.Second, 10*time.Millisecond).Should(BeZero()) + }) + }) }) Describe("RetrieveInstanceMetrics", func() { diff --git a/src/autoscaler/eventgenerator/aggregator/aggregator.go b/src/autoscaler/eventgenerator/aggregator/aggregator.go index 440a1e15c..ece04a9f4 100644 --- a/src/autoscaler/eventgenerator/aggregator/aggregator.go +++ b/src/autoscaler/eventgenerator/aggregator/aggregator.go @@ -28,10 +28,10 @@ type Aggregator struct { func NewAggregator(logger lager.Logger, clock clock.Clock, aggregatorExecuteInterval time.Duration, saveInterval time.Duration, appMonitorChan chan *models.AppMonitor, getPolicies GetPoliciesFunc, saveAppMetricToCache SaveAppMetricToCacheFunc, defaultStatWindowSecs int, appMetricChan chan *models.AppMetric, appMetricDB db.AppMetricDB) (*Aggregator, error) { aggregator := &Aggregator{ - logger: logger.Session("Aggregator"), - doneChan: make(chan bool), - appChan: appMonitorChan, - cclock: clock, + logger: logger.Session("Aggregator"), + doneChan: make(chan bool), + appChan: appMonitorChan, + cclock: clock, aggregatorExecuteInterval: aggregatorExecuteInterval, saveInterval: saveInterval, getPolicies: getPolicies, @@ -104,11 +104,14 @@ func (a *Aggregator) startSavingAppMetric() { appMetricArray = append(appMetricArray, appMetric) a.saveAppMetricToCache(appMetric) case <-ticker.C(): - go func(appMetricDB db.AppMetricDB, metrics []*models.AppMetric) { - appMetricDB.SaveAppMetricsInBulk(metrics) - return - }(a.appMetricDB, appMetricArray) - appMetricArray = []*models.AppMetric{} + if len(appMetricArray) > 0 { + go func(appMetricDB db.AppMetricDB, metrics []*models.AppMetric) { + appMetricDB.SaveAppMetricsInBulk(metrics) + return + }(a.appMetricDB, appMetricArray) + appMetricArray = []*models.AppMetric{} + } + } } } diff --git a/src/autoscaler/eventgenerator/aggregator/aggregator_test.go b/src/autoscaler/eventgenerator/aggregator/aggregator_test.go index fc41a8009..571ddc04b 100644 --- a/src/autoscaler/eventgenerator/aggregator/aggregator_test.go +++ b/src/autoscaler/eventgenerator/aggregator/aggregator_test.go @@ -88,30 +88,46 @@ var _ = Describe("Aggregator", func() { getPolicies, saveAppMetricToCache, fakeStatWindowSecs, appMetricChan, appMetricDatabase) Expect(err).NotTo(HaveOccurred()) aggregator.Start() - Expect(appMetricChan).Should(BeSent(&models.AppMetric{ - AppId: testAppId, - MetricType: testMetricType, - Value: "250", - Unit: testMetricUnit, - Timestamp: time.Now().UnixNano(), - })) Eventually(clock.WatcherCount).Should(Equal(2)) }) AfterEach(func() { aggregator.Stop() }) - - It("should send appMonitors and save appMetrics", func() { - clock.Increment(1 * fakeWaitDuration) - Eventually(appMonitorsChan).Should(Receive()) - Eventually(func() int { - cacheLock.RLock() - defer cacheLock.RUnlock() - return saveToCacheCallCount - }).Should(Equal(1)) - Eventually(appMetricDatabase.SaveAppMetricsInBulkCallCount).Should(Equal(1)) + Context("when there are incoming metrics", func() { + BeforeEach(func() { + Expect(appMetricChan).Should(BeSent(&models.AppMetric{ + AppId: testAppId, + MetricType: testMetricType, + Value: "250", + Unit: testMetricUnit, + Timestamp: time.Now().UnixNano(), + })) + }) + It("should send appMonitors and save appMetrics", func() { + clock.Increment(1 * fakeWaitDuration) + Eventually(appMonitorsChan).Should(Receive()) + Eventually(func() int { + cacheLock.RLock() + defer cacheLock.RUnlock() + return saveToCacheCallCount + }).Should(Equal(1)) + Eventually(appMetricDatabase.SaveAppMetricsInBulkCallCount).Should(Equal(1)) + }) }) + Context("when there is no metrics", func() { + It("does not save metrics to db", func() { + clock.Increment(1 * fakeWaitDuration) + Eventually(appMonitorsChan).Should(Receive()) + Eventually(func() int { + cacheLock.RLock() + defer cacheLock.RUnlock() + return saveToCacheCallCount + }).Should(BeZero()) + Eventually(appMetricDatabase.SaveAppMetricsInBulkCallCount).Should(BeZero()) + }) + }) + }) Context("Stop", func() { diff --git a/src/autoscaler/metricscollector/collector/collector.go b/src/autoscaler/metricscollector/collector/collector.go index cc8fbf4e8..3d27a7233 100644 --- a/src/autoscaler/metricscollector/collector/collector.go +++ b/src/autoscaler/metricscollector/collector/collector.go @@ -66,7 +66,6 @@ func NewCollector(refreshInterval time.Duration, collectInterval time.Duration, func (c *Collector) Start() { go c.startAppRefresh() - if c.persistMetrics { go c.SaveMetricsInDB() } @@ -196,12 +195,15 @@ func (c *Collector) SaveMetricsInDB() { case metric := <-c.dataChan: metrics = append(metrics, metric) case <-ticker.C(): - go func(instancemetricsDb db.InstanceMetricsDB, metrics []*models.AppInstanceMetric) { - instancemetricsDb.SaveMetricsInBulk(metrics) + if c.persistMetrics && len(metrics) > 0 { + go func(instancemetricsDb db.InstanceMetricsDB, metrics []*models.AppInstanceMetric) { + instancemetricsDb.SaveMetricsInBulk(metrics) + metrics = nil + return + }(c.instancemetricsDb, metrics) metrics = nil - return - }(c.instancemetricsDb, metrics) - metrics = nil + } + case <-c.doneSaveChan: return } diff --git a/src/autoscaler/metricsserver/collector/collector.go b/src/autoscaler/metricsserver/collector/collector.go index 760520bd1..89980d4d2 100644 --- a/src/autoscaler/metricsserver/collector/collector.go +++ b/src/autoscaler/metricsserver/collector/collector.go @@ -210,7 +210,7 @@ func (c *metricCollector) saveMetrics() { metrics = append(metrics, m) } case <-ticker.C(): - if c.PersistMetrics { + if c.PersistMetrics && len(metrics) > 0 { go func(instancemetricsDb db.InstanceMetricsDB, metrics []*models.AppInstanceMetric) { instancemetricsDb.SaveMetricsInBulk(metrics) metrics = nil diff --git a/src/autoscaler/metricsserver/collector/collector_test.go b/src/autoscaler/metricsserver/collector/collector_test.go index a425f86de..b785a0849 100644 --- a/src/autoscaler/metricsserver/collector/collector_test.go +++ b/src/autoscaler/metricsserver/collector/collector_test.go @@ -241,6 +241,23 @@ var _ = Describe("Collector", func() { }) }) }) + Context("when there is no metrics", func() { + BeforeEach(func() { + policyDb.GetAppIdsReturns(map[string]bool{"an-app-id": true}, nil) + + }) + Context("when metric persistency is supported", func() { + BeforeEach(func() { + isMetricPersistencySuppported = true + }) + It("does not save metrics to db", func() { + Consistently(instanceMetricsDb.SaveMetricCallCount).Should(BeZero()) + + fclock.WaitForWatcherAndIncrement(TestSaveInterval) + Consistently(instanceMetricsDb.SaveMetricsInBulkCallCount).Should(BeZero()) + }) + }) + }) }) Describe("QueryMetrics", func() { From 54ba2ecd2603ae5905579a016c1b6801600b14a9 Mon Sep 17 00:00:00 2001 From: qibobo Date: Thu, 5 Sep 2019 16:27:17 +0800 Subject: [PATCH 14/16] update health endpoint ut --- src/autoscaler/api/cmd/api/api_test.go | 2 +- .../eventgenerator/cmd/eventgenerator/eventgenerator_test.go | 2 +- .../cmd/metricscollector/metricscollector_test.go | 2 +- .../cmd/metricsforwarder/metricsforwarder_test.go | 2 +- .../metricsgateway/cmd/metricsgateway/metricsgateway_test.go | 2 +- .../metricsserver/cmd/metricsserver/metricsserver_test.go | 2 +- src/autoscaler/operator/cmd/operator/operator_test.go | 2 +- .../scalingengine/cmd/scalingengine/scalingengine_test.go | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/autoscaler/api/cmd/api/api_test.go b/src/autoscaler/api/cmd/api/api_test.go index b65b9bfbe..8f6ed63fe 100644 --- a/src/autoscaler/api/cmd/api/api_test.go +++ b/src/autoscaler/api/cmd/api/api_test.go @@ -178,7 +178,7 @@ var _ = Describe("Api", func() { }) Context("when a request to query health comes", func() { It("returns with a 200", func() { - rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d/health", healthport)) + rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d", healthport)) Expect(err).NotTo(HaveOccurred()) Expect(rsp.StatusCode).To(Equal(http.StatusOK)) raw, _ := ioutil.ReadAll(rsp.Body) diff --git a/src/autoscaler/eventgenerator/cmd/eventgenerator/eventgenerator_test.go b/src/autoscaler/eventgenerator/cmd/eventgenerator/eventgenerator_test.go index ee58a8074..c0b073625 100644 --- a/src/autoscaler/eventgenerator/cmd/eventgenerator/eventgenerator_test.go +++ b/src/autoscaler/eventgenerator/cmd/eventgenerator/eventgenerator_test.go @@ -141,7 +141,7 @@ var _ = Describe("Eventgenerator", func() { }) Context("when a request to query health comes", func() { It("returns with a 200", func() { - rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d/health", healthport)) + rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d", healthport)) Expect(err).NotTo(HaveOccurred()) Expect(rsp.StatusCode).To(Equal(http.StatusOK)) raw, _ := ioutil.ReadAll(rsp.Body) diff --git a/src/autoscaler/metricscollector/cmd/metricscollector/metricscollector_test.go b/src/autoscaler/metricscollector/cmd/metricscollector/metricscollector_test.go index d096d4598..6b50a0549 100644 --- a/src/autoscaler/metricscollector/cmd/metricscollector/metricscollector_test.go +++ b/src/autoscaler/metricscollector/cmd/metricscollector/metricscollector_test.go @@ -144,7 +144,7 @@ var _ = Describe("MetricsCollector", func() { }) Context("when a request to query health comes", func() { It("returns with a 200", func() { - rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d/health", healthport)) + rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d", healthport)) Expect(err).NotTo(HaveOccurred()) Expect(rsp.StatusCode).To(Equal(http.StatusOK)) raw, _ := ioutil.ReadAll(rsp.Body) diff --git a/src/autoscaler/metricsforwarder/cmd/metricsforwarder/metricsforwarder_test.go b/src/autoscaler/metricsforwarder/cmd/metricsforwarder/metricsforwarder_test.go index a655d456d..624d3bd83 100644 --- a/src/autoscaler/metricsforwarder/cmd/metricsforwarder/metricsforwarder_test.go +++ b/src/autoscaler/metricsforwarder/cmd/metricsforwarder/metricsforwarder_test.go @@ -140,7 +140,7 @@ var _ = Describe("Metricsforwarder", func() { }) Context("when a request to query health comes", func() { It("returns with a 200", func() { - rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d/health", healthport)) + rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d", healthport)) Expect(err).NotTo(HaveOccurred()) Expect(rsp.StatusCode).To(Equal(http.StatusOK)) raw, _ := ioutil.ReadAll(rsp.Body) diff --git a/src/autoscaler/metricsgateway/cmd/metricsgateway/metricsgateway_test.go b/src/autoscaler/metricsgateway/cmd/metricsgateway/metricsgateway_test.go index 5b686962a..a4e717ae2 100644 --- a/src/autoscaler/metricsgateway/cmd/metricsgateway/metricsgateway_test.go +++ b/src/autoscaler/metricsgateway/cmd/metricsgateway/metricsgateway_test.go @@ -108,7 +108,7 @@ var _ = Describe("Metricsgateway", func() { Describe("when Health server is ready to serve RESTful API", func() { Context("when a request to query health comes", func() { It("returns with a 200", func() { - rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d/health", healthport)) + rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d", healthport)) Expect(err).NotTo(HaveOccurred()) Expect(rsp.StatusCode).To(Equal(http.StatusOK)) raw, _ := ioutil.ReadAll(rsp.Body) diff --git a/src/autoscaler/metricsserver/cmd/metricsserver/metricsserver_test.go b/src/autoscaler/metricsserver/cmd/metricsserver/metricsserver_test.go index 7463b5f49..dc944c61d 100644 --- a/src/autoscaler/metricsserver/cmd/metricsserver/metricsserver_test.go +++ b/src/autoscaler/metricsserver/cmd/metricsserver/metricsserver_test.go @@ -118,7 +118,7 @@ var _ = Describe("MetricsServer", func() { }) Context("when a request to query health comes", func() { It("returns with a 200", func() { - rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d/health", healthport)) + rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d", healthport)) Expect(err).NotTo(HaveOccurred()) Expect(rsp.StatusCode).To(Equal(http.StatusOK)) raw, _ := ioutil.ReadAll(rsp.Body) diff --git a/src/autoscaler/operator/cmd/operator/operator_test.go b/src/autoscaler/operator/cmd/operator/operator_test.go index b0938288c..17b799315 100644 --- a/src/autoscaler/operator/cmd/operator/operator_test.go +++ b/src/autoscaler/operator/cmd/operator/operator_test.go @@ -347,7 +347,7 @@ var _ = Describe("Operator", func() { Context("when a request to query health comes", func() { It("returns with a 200", func() { - rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d/health", healthport)) + rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d", healthport)) Expect(err).NotTo(HaveOccurred()) Expect(rsp.StatusCode).To(Equal(http.StatusOK)) raw, _ := ioutil.ReadAll(rsp.Body) diff --git a/src/autoscaler/scalingengine/cmd/scalingengine/scalingengine_test.go b/src/autoscaler/scalingengine/cmd/scalingengine/scalingengine_test.go index e5e684cb3..9ebf38a01 100644 --- a/src/autoscaler/scalingengine/cmd/scalingengine/scalingengine_test.go +++ b/src/autoscaler/scalingengine/cmd/scalingengine/scalingengine_test.go @@ -202,7 +202,7 @@ var _ = Describe("Main", func() { Context("when a request to query health comes", func() { It("returns with a 200", func() { - rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d/health", healthport)) + rsp, err := healthHttpClient.Get(fmt.Sprintf("http://127.0.0.1:%d", healthport)) Expect(err).NotTo(HaveOccurred()) Expect(rsp.StatusCode).To(Equal(http.StatusOK)) raw, _ := ioutil.ReadAll(rsp.Body) From 92b544f2e9c78219a0fac8d879537f6210936f1e Mon Sep 17 00:00:00 2001 From: zyjiaobj Date: Tue, 17 Sep 2019 10:21:22 +0800 Subject: [PATCH 15/16] fix parameter parse bug (#531) * fix parameter parse bug * support adjustment percentage * fix unit test for adjustment * enhance test cases for the bugfix * update test cases upon qiyang's comments --- .../policyvalidator/policy_json.schema.json | 2 +- .../policyvalidator/policy_validator_test.go | 59 +++++- .../api/publicapiserver/route_helper.go | 4 +- ...tegration_golangapi_eventgenerator_test.go | 98 ++++++++- ...gration_golangapi_metricscollector_test.go | 19 -- ...ntegration_golangapi_metricsserver_test.go | 195 ++++++++++++++++-- ...ntegration_golangapi_scalingengine_test.go | 120 ++++++++++- .../integration_golangapi_scheduler_test.go | 4 - 8 files changed, 437 insertions(+), 64 deletions(-) diff --git a/src/autoscaler/api/policyvalidator/policy_json.schema.json b/src/autoscaler/api/policyvalidator/policy_json.schema.json index 1b85ce821..ea020ca84 100644 --- a/src/autoscaler/api/policyvalidator/policy_json.schema.json +++ b/src/autoscaler/api/policyvalidator/policy_json.schema.json @@ -86,7 +86,7 @@ "type": "string", "title": "The Adjustment Schema", "description": "Magnitude of scaling in each step, +1 means scale up 1 Instance -2 means scale down 2 instances", - "pattern": "^[-+][1-9]+[0-9]*$" + "pattern": "^[-+][1-9]+[0-9]*%?$" } } } diff --git a/src/autoscaler/api/policyvalidator/policy_validator_test.go b/src/autoscaler/api/policyvalidator/policy_validator_test.go index b556cfeb1..29634851d 100644 --- a/src/autoscaler/api/policyvalidator/policy_validator_test.go +++ b/src/autoscaler/api/policyvalidator/policy_validator_test.go @@ -666,11 +666,68 @@ var _ = Describe("PolicyValidator", func() { Expect(errResult).To(Equal(&[]PolicyValidationErrors{ { Context: "(root).scaling_rules.0.adjustment", - Description: "Does not match pattern '^[-+][1-9]+[0-9]*$'", + Description: "Does not match pattern '^[-+][1-9]+[0-9]*%?$'", }, })) }) }) + + Context("when adjustment is number type", func() { + BeforeEach(func() { + policyString = `{ + "instance_max_count":4, + "instance_min_count":1, + "scaling_rules":[ + { + "metric_type":"memoryutil", + "breach_duration_secs":600, + "threshold":90, + "operator":">=", + "cool_down_secs":300, + "adjustment": "+1" + },{ + "metric_type":"memoryutil", + "breach_duration_secs":600, + "threshold":90, + "operator":"<=", + "cool_down_secs":300, + "adjustment": "-2" + }] + }` + }) + It("should succeed", func() { + Expect(valid).To(BeTrue()) + }) + }) + + Context("when adjustment is percentage type", func() { + BeforeEach(func() { + policyString = `{ + "instance_max_count":4, + "instance_min_count":1, + "scaling_rules":[ + { + "metric_type":"memoryutil", + "breach_duration_secs":600, + "threshold":90, + "operator":">=", + "cool_down_secs":300, + "adjustment": "+100%" + },{ + "metric_type":"memoryutil", + "breach_duration_secs":600, + "threshold":90, + "operator":"<=", + "cool_down_secs":300, + "adjustment": "-200%" + }] + }` + }) + It("should succeed", func() { + Expect(valid).To(BeTrue()) + }) + }) + Context("when breach_duration_secs is missing", func() { BeforeEach(func() { policyString = `{ diff --git a/src/autoscaler/api/publicapiserver/route_helper.go b/src/autoscaler/api/publicapiserver/route_helper.go index 36c30e726..d886dbcf4 100644 --- a/src/autoscaler/api/publicapiserver/route_helper.go +++ b/src/autoscaler/api/publicapiserver/route_helper.go @@ -76,8 +76,8 @@ func parseParameter(r *http.Request, vars map[string]string) (*url.Values, error return nil, fmt.Errorf("results-per-page must be greater than 0") } parameters := &url.Values{} - parameters.Add("start-time", startTime) - parameters.Add("end-time", endTime) + parameters.Add("start", startTime) + parameters.Add("end", endTime) parameters.Add("order", orderDirection) parameters.Add("page", page) parameters.Add("results-per-page", resultsPerPage) diff --git a/src/integration/integration_golangapi_eventgenerator_test.go b/src/integration/integration_golangapi_eventgenerator_test.go index 6140fda86..285b21901 100644 --- a/src/integration/integration_golangapi_eventgenerator_test.go +++ b/src/integration/integration_golangapi_eventgenerator_test.go @@ -50,7 +50,6 @@ var _ = Describe("Integration_GolangApi_EventGenerator", func() { fakeCCNOAAUAA.AllowUnhandledRequests = true }) It("should error with status code 500", func() { - By("check public api") checkPublicAPIResponseContentWithParameters(getAppAggregatedMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ "code": "Interal-Server-Error", "message": "Failed to check space developer permission", @@ -69,7 +68,6 @@ var _ = Describe("Integration_GolangApi_EventGenerator", func() { })) }) It("should error with status code 500", func() { - By("check public api") checkPublicAPIResponseContentWithParameters(getAppAggregatedMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ "code": "Interal-Server-Error", "message": "Failed to check space developer permission", @@ -94,7 +92,6 @@ var _ = Describe("Integration_GolangApi_EventGenerator", func() { fakeCCNOAAUAA.RouteToHandler("GET", "/userinfo", ghttp.RespondWithJSONEncoded(http.StatusUnauthorized, struct{}{})) }) It("should error with status code 401", func() { - By("check public api") checkPublicAPIResponseContentWithParameters(getAppAggregatedMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{ "code": "Unauthorized", @@ -112,7 +109,6 @@ var _ = Describe("Integration_GolangApi_EventGenerator", func() { })) }) It("should error with status code 401", func() { - By("check public api") checkPublicAPIResponseContentWithParameters(getAppAggregatedMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{ "code": "Unauthorized", @@ -127,7 +123,6 @@ var _ = Describe("Integration_GolangApi_EventGenerator", func() { }) It("should error with status code 500", func() { - By("check public api") checkPublicAPIResponseContentWithParameters(getAppAggregatedMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ "code": "Interal-Server-Error", "message": "Error retrieving metrics history from eventgenerator", @@ -196,7 +191,6 @@ var _ = Describe("Integration_GolangApi_EventGenerator", func() { }, }, } - By("check public api") checkAggregatedMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) By("get the 2nd page") @@ -224,7 +218,6 @@ var _ = Describe("Integration_GolangApi_EventGenerator", func() { }, }, } - By("check public api") checkAggregatedMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) By("get the 3rd page") @@ -244,7 +237,6 @@ var _ = Describe("Integration_GolangApi_EventGenerator", func() { }, }, } - By("check public api") checkAggregatedMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) By("the 4th page should be empty") @@ -256,10 +248,98 @@ var _ = Describe("Integration_GolangApi_EventGenerator", func() { PrevUrl: getAppAggregatedMetricUrl(appId, metricType, parameters, 3), Resources: []models.AppMetric{}, } - By("check public api") checkAggregatedMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) }) + It("should get the metrics in specified time scope", func() { + By("get the results from 555555") + parameters = map[string]string{"start-time": "555555", "order-direction": "asc", "page": "1", "results-per-page": "10"} + result := AppAggregatedMetricResult{ + TotalResults: 3, + TotalPages: 1, + Page: 1, + Resources: []models.AppMetric{ + models.AppMetric{ + AppId: appId, + MetricType: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 555555, + }, + models.AppMetric{ + AppId: appId, + MetricType: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 555555, + }, + models.AppMetric{ + AppId: appId, + MetricType: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 666666, + }, + }, + } + checkAggregatedMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("get the results to 444444") + parameters = map[string]string{"end-time": "444444", "order-direction": "asc", "page": "1", "results-per-page": "10"} + result = AppAggregatedMetricResult{ + TotalResults: 2, + TotalPages: 1, + Page: 1, + Resources: []models.AppMetric{ + models.AppMetric{ + AppId: appId, + MetricType: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 333333, + }, + models.AppMetric{ + AppId: appId, + MetricType: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 444444, + }, + }, + } + checkAggregatedMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + By("get the results from 444444 to 555555") + parameters = map[string]string{"start-time": "444444", "end-time": "555555", "order-direction": "asc", "page": "1", "results-per-page": "10"} + result = AppAggregatedMetricResult{ + TotalResults: 3, + TotalPages: 1, + Page: 1, + Resources: []models.AppMetric{ + models.AppMetric{ + AppId: appId, + MetricType: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 444444, + }, + models.AppMetric{ + AppId: appId, + MetricType: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 555555, + }, + models.AppMetric{ + AppId: appId, + MetricType: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 555555, + }, + }, + } + checkAggregatedMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + }) }) }) }) diff --git a/src/integration/integration_golangapi_metricscollector_test.go b/src/integration/integration_golangapi_metricscollector_test.go index b8d46650c..26549816a 100644 --- a/src/integration/integration_golangapi_metricscollector_test.go +++ b/src/integration/integration_golangapi_metricscollector_test.go @@ -55,7 +55,6 @@ var _ = Describe("Integration_GolangApi_MetricsCollector", func() { parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "asc", "page": "1", "results-per-page": "5"} }) It("should error with status code 500", func() { - By("check public api") checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ "code": "Interal-Server-Error", "message": "Failed to check space developer permission", @@ -76,7 +75,6 @@ var _ = Describe("Integration_GolangApi_MetricsCollector", func() { parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "asc", "page": "1", "results-per-page": "5"} }) It("should error with status code 500", func() { - By("check public api") checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ "code": "Interal-Server-Error", "message": "Failed to check space developer permission", @@ -103,7 +101,6 @@ var _ = Describe("Integration_GolangApi_MetricsCollector", func() { parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "asc", "page": "1", "results-per-page": "5"} }) It("should error with status code 401", func() { - By("check public api") checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{ "code": "Unauthorized", @@ -123,7 +120,6 @@ var _ = Describe("Integration_GolangApi_MetricsCollector", func() { parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "asc", "page": "1", "results-per-page": "5"} }) It("should error with status code 401", func() { - By("check public api") checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{ "code": "Unauthorized", @@ -139,12 +135,6 @@ var _ = Describe("Integration_GolangApi_MetricsCollector", func() { }) It("should error with status code 500", func() { - By("check internal api") - checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ - "code": "Interal-Server-Error", - "message": "Error retrieving metrics history from metricscollector", - }) - By("check public api") checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ "code": "Interal-Server-Error", "message": "Error retrieving metrics history from metricscollector", @@ -228,8 +218,6 @@ var _ = Describe("Integration_GolangApi_MetricsCollector", func() { }, }, } - - By("check public api") checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) By("get the 2nd page") @@ -261,7 +249,6 @@ var _ = Describe("Integration_GolangApi_MetricsCollector", func() { }, }, } - By("check public api") checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) By("get the 3rd page") @@ -283,7 +270,6 @@ var _ = Describe("Integration_GolangApi_MetricsCollector", func() { }, }, } - By("check public api") checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) By("the 4th page should be empty") @@ -295,7 +281,6 @@ var _ = Describe("Integration_GolangApi_MetricsCollector", func() { PrevUrl: getInstanceMetricsUrl(appId, metricType, parameters, 3), Resources: []models.AppInstanceMetric{}, } - By("check public api") checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) By("the 5th page should be empty") @@ -306,7 +291,6 @@ var _ = Describe("Integration_GolangApi_MetricsCollector", func() { Page: 5, Resources: []models.AppInstanceMetric{}, } - By("check public api") checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) }) }) @@ -339,8 +323,6 @@ var _ = Describe("Integration_GolangApi_MetricsCollector", func() { }, }, } - - By("check public api") checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) By("get the 2nd page") @@ -352,7 +334,6 @@ var _ = Describe("Integration_GolangApi_MetricsCollector", func() { PrevUrl: getInstanceMetricsUrlWithInstanceIndex(appId, metricType, parameters, 1), Resources: []models.AppInstanceMetric{}, } - By("check public api") checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) }) }) diff --git a/src/integration/integration_golangapi_metricsserver_test.go b/src/integration/integration_golangapi_metricsserver_test.go index a25308fa5..2c8a08dc1 100644 --- a/src/integration/integration_golangapi_metricsserver_test.go +++ b/src/integration/integration_golangapi_metricsserver_test.go @@ -52,7 +52,6 @@ var _ = Describe("Integration_GolangApi_MetricsServer", func() { parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "asc", "page": "1", "results-per-page": "5"} }) It("should error with status code 500", func() { - By("check public api") checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ "code": "Interal-Server-Error", "message": "Failed to check space developer permission", @@ -73,7 +72,6 @@ var _ = Describe("Integration_GolangApi_MetricsServer", func() { parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "asc", "page": "1", "results-per-page": "5"} }) It("should error with status code 500", func() { - By("check public api") checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ "code": "Interal-Server-Error", "message": "Failed to check space developer permission", @@ -100,7 +98,6 @@ var _ = Describe("Integration_GolangApi_MetricsServer", func() { parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "asc", "page": "1", "results-per-page": "5"} }) It("should error with status code 401", func() { - By("check public api") checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{ "code": "Unauthorized", @@ -120,7 +117,6 @@ var _ = Describe("Integration_GolangApi_MetricsServer", func() { parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "asc", "page": "1", "results-per-page": "5"} }) It("should error with status code 401", func() { - By("check public api") checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{ "code": "Unauthorized", @@ -136,12 +132,6 @@ var _ = Describe("Integration_GolangApi_MetricsServer", func() { }) It("should error with status code 500", func() { - By("check internal api") - checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ - "code": "Interal-Server-Error", - "message": "Error retrieving metrics history from metricscollector", - }) - By("check public api") checkPublicAPIResponseContentWithParameters(getAppInstanceMetrics, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ "code": "Interal-Server-Error", "message": "Error retrieving metrics history from metricscollector", @@ -225,8 +215,6 @@ var _ = Describe("Integration_GolangApi_MetricsServer", func() { }, }, } - - By("check public api") checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) By("get the 2nd page") @@ -258,7 +246,6 @@ var _ = Describe("Integration_GolangApi_MetricsServer", func() { }, }, } - By("check public api") checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) By("get the 3rd page") @@ -280,7 +267,6 @@ var _ = Describe("Integration_GolangApi_MetricsServer", func() { }, }, } - By("check public api") checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) By("the 4th page should be empty") @@ -292,7 +278,6 @@ var _ = Describe("Integration_GolangApi_MetricsServer", func() { PrevUrl: getInstanceMetricsUrl(appId, metricType, parameters, 3), Resources: []models.AppInstanceMetric{}, } - By("check public api") checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) By("the 5th page should be empty") @@ -303,7 +288,112 @@ var _ = Describe("Integration_GolangApi_MetricsServer", func() { Page: 5, Resources: []models.AppInstanceMetric{}, } - By("check public api") + checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + }) + It("should get the metrics of all instances in specified time scope", func() { + By("get the results from 555555") + parameters = map[string]string{"start-time": "555555", "order-direction": "asc", "page": "1", "results-per-page": "10"} + result := AppInstanceMetricResult{ + TotalResults: 3, + TotalPages: 1, + Page: 1, + Resources: []models.AppInstanceMetric{ + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 0, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 555555, + }, + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 1, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 555555, + }, + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 0, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 666666, + }, + }, + } + checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("get the results to 444444") + parameters = map[string]string{"end-time": "444444", "order-direction": "asc", "page": "1", "results-per-page": "10"} + result = AppInstanceMetricResult{ + TotalResults: 2, + TotalPages: 1, + Page: 1, + Resources: []models.AppInstanceMetric{ + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 0, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 333333, + }, + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 1, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 444444, + }, + }, + } + checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("get the results from 444444 to 555555") + parameters = map[string]string{"start-time": "444444", "end-time": "555555", "order-direction": "asc", "page": "1", "results-per-page": "10"} + result = AppInstanceMetricResult{ + TotalResults: 3, + TotalPages: 1, + Page: 1, + Resources: []models.AppInstanceMetric{ + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 1, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 444444, + }, + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 0, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 555555, + }, + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 1, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 555555, + }, + }, + } checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) }) }) @@ -336,8 +426,6 @@ var _ = Describe("Integration_GolangApi_MetricsServer", func() { }, }, } - - By("check public api") checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) By("get the 2nd page") @@ -349,7 +437,76 @@ var _ = Describe("Integration_GolangApi_MetricsServer", func() { PrevUrl: getInstanceMetricsUrlWithInstanceIndex(appId, metricType, parameters, 1), Resources: []models.AppInstanceMetric{}, } - By("check public api") + checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + }) + It("should get the metrics of the instance in specified time scope", func() { + By("get the results from 555555") + parameters = map[string]string{"instance-index": "1", "start-time": "555555", "order-direction": "asc", "page": "1", "results-per-page": "10"} + result := AppInstanceMetricResult{ + TotalResults: 1, + TotalPages: 1, + Page: 1, + Resources: []models.AppInstanceMetric{ + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 1, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 555555, + }, + }, + } + checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("get the results to 444444") + parameters = map[string]string{"instance-index": "1", "end-time": "444444", "order-direction": "asc", "page": "1", "results-per-page": "10"} + result = AppInstanceMetricResult{ + TotalResults: 1, + TotalPages: 1, + Page: 1, + Resources: []models.AppInstanceMetric{ + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 1, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 444444, + }, + }, + } + checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("get the results from 444444 to 555555") + parameters = map[string]string{"instance-index": "1", "start-time": "444444", "end-time": "555555", "order-direction": "asc", "page": "1", "results-per-page": "10"} + result = AppInstanceMetricResult{ + TotalResults: 2, + TotalPages: 1, + Page: 1, + Resources: []models.AppInstanceMetric{ + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 1, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 444444, + }, + models.AppInstanceMetric{ + AppId: appId, + InstanceIndex: 1, + CollectedAt: 111111, + Name: models.MetricNameMemoryUsed, + Unit: models.UnitMegaBytes, + Value: "123456", + Timestamp: 555555, + }, + }, + } checkAppInstanceMetricResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) }) }) diff --git a/src/integration/integration_golangapi_scalingengine_test.go b/src/integration/integration_golangapi_scalingengine_test.go index 1c003fc4e..0fa6d6d9a 100644 --- a/src/integration/integration_golangapi_scalingengine_test.go +++ b/src/integration/integration_golangapi_scalingengine_test.go @@ -50,7 +50,6 @@ var _ = Describe("Integration_GolangApi_ScalingEngine", func() { parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "desc", "page": "1", "results-per-page": "5"} }) It("should error with status code 500", func() { - By("check public api") checkPublicAPIResponseContentWithParameters(getScalingHistories, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ "code": "Interal-Server-Error", "message": "Failed to check space developer permission", @@ -71,7 +70,6 @@ var _ = Describe("Integration_GolangApi_ScalingEngine", func() { parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "desc", "page": "1", "results-per-page": "5"} }) It("should error with status code 500", func() { - By("check public api") checkPublicAPIResponseContentWithParameters(getScalingHistories, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ "code": "Interal-Server-Error", "message": "Failed to check space developer permission", @@ -99,7 +97,6 @@ var _ = Describe("Integration_GolangApi_ScalingEngine", func() { parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "desc", "page": "1", "results-per-page": "5"} }) It("should error with status code 401", func() { - By("check public api") checkPublicAPIResponseContentWithParameters(getScalingHistories, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{ "code": "Unauthorized", @@ -119,7 +116,6 @@ var _ = Describe("Integration_GolangApi_ScalingEngine", func() { parameters = map[string]string{"start-time": "1111", "end-time": "9999", "order-direction": "desc", "page": "1", "results-per-page": "5"} }) It("should error with status code 401", func() { - By("check public api") checkPublicAPIResponseContentWithParameters(getScalingHistories, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusUnauthorized, map[string]interface{}{ "code": "Unauthorized", @@ -135,7 +131,6 @@ var _ = Describe("Integration_GolangApi_ScalingEngine", func() { }) It("should error with status code 500", func() { - By("check public api") checkPublicAPIResponseContentWithParameters(getScalingHistories, components.Ports[GolangAPIServer], pathVariables, parameters, http.StatusInternalServerError, map[string]interface{}{ "message": "Error retrieving scaling history from scaling engine", "code": "Interal-Server-Error", @@ -212,7 +207,6 @@ var _ = Describe("Integration_GolangApi_ScalingEngine", func() { }, }, } - By("check public api") checkScalingHistoryResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) By("get the 2nd page") @@ -248,7 +242,6 @@ var _ = Describe("Integration_GolangApi_ScalingEngine", func() { }, }, } - By("check public api") checkScalingHistoryResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) By("get the 3rd page") @@ -272,7 +265,6 @@ var _ = Describe("Integration_GolangApi_ScalingEngine", func() { }, }, } - By("check public api") checkScalingHistoryResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) By("the 4th page should be empty") @@ -284,7 +276,117 @@ var _ = Describe("Integration_GolangApi_ScalingEngine", func() { PrevUrl: getScalingHistoriesUrl(appId, parameters, 3), Resources: []models.AppScalingHistory{}, } - By("check public api") + checkScalingHistoryResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + }) + It("should get the scaling histories in specified time scope", func() { + By("get the results from 555555") + parameters = map[string]string{"start-time": "555555", "order-direction": "desc", "page": "1", "results-per-page": "10"} + result := ScalingHistoryResult{ + TotalResults: 2, + TotalPages: 1, + Page: 1, + Resources: []models.AppScalingHistory{ + models.AppScalingHistory{ + AppId: appId, + Timestamp: 666666, + ScalingType: models.ScalingTypeDynamic, + Status: models.ScalingStatusSucceeded, + OldInstances: 2, + NewInstances: 4, + Reason: "a reason", + Message: "a message", + Error: "", + }, + models.AppScalingHistory{ + AppId: appId, + Timestamp: 555555, + ScalingType: models.ScalingTypeDynamic, + Status: models.ScalingStatusSucceeded, + OldInstances: 2, + NewInstances: 4, + Reason: "a reason", + Message: "a message", + Error: "", + }, + }, + } + checkScalingHistoryResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("get the results to 333333") + parameters = map[string]string{"end-time": "333333", "order-direction": "desc", "page": "1", "results-per-page": "10"} + result = ScalingHistoryResult{ + TotalResults: 2, + TotalPages: 1, + Page: 1, + Resources: []models.AppScalingHistory{ + models.AppScalingHistory{ + AppId: appId, + Timestamp: 333333, + ScalingType: models.ScalingTypeDynamic, + Status: models.ScalingStatusSucceeded, + OldInstances: 2, + NewInstances: 4, + Reason: "a reason", + Message: "a message", + Error: "", + }, + models.AppScalingHistory{ + AppId: appId, + Timestamp: 222222, + ScalingType: models.ScalingTypeDynamic, + Status: models.ScalingStatusSucceeded, + OldInstances: 2, + NewInstances: 4, + Reason: "a reason", + Message: "a message", + Error: "", + }, + }, + } + checkScalingHistoryResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) + + By("get the results from 333333 to 555555") + parameters = map[string]string{"start-time": "333333", "end-time": "555555", "order-direction": "asc", "page": "1", "results-per-page": "10"} + result = ScalingHistoryResult{ + TotalResults: 3, + TotalPages: 1, + Page: 1, + Resources: []models.AppScalingHistory{ + models.AppScalingHistory{ + AppId: appId, + Timestamp: 333333, + ScalingType: models.ScalingTypeDynamic, + Status: models.ScalingStatusSucceeded, + OldInstances: 2, + NewInstances: 4, + Reason: "a reason", + Message: "a message", + Error: "", + }, + models.AppScalingHistory{ + AppId: appId, + Timestamp: 444444, + ScalingType: models.ScalingTypeDynamic, + Status: models.ScalingStatusSucceeded, + OldInstances: 2, + NewInstances: 4, + Reason: "a reason", + Message: "a message", + Error: "", + }, + models.AppScalingHistory{ + AppId: appId, + Timestamp: 555555, + ScalingType: models.ScalingTypeDynamic, + Status: models.ScalingStatusSucceeded, + OldInstances: 2, + NewInstances: 4, + Reason: "a reason", + Message: "a message", + Error: "", + }, + }, + } checkScalingHistoryResult(components.Ports[GolangAPIServer], pathVariables, parameters, result) }) diff --git a/src/integration/integration_golangapi_scheduler_test.go b/src/integration/integration_golangapi_scheduler_test.go index 2a65e1241..5d1840309 100644 --- a/src/integration/integration_golangapi_scheduler_test.go +++ b/src/integration/integration_golangapi_scheduler_test.go @@ -67,7 +67,6 @@ var _ = Describe("Integration_GolangApi_Scheduler", func() { }) Context("Create policy", func() { It("should error with status code 500", func() { - By("check public api") policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") doAttachPolicy(appId, policyStr, http.StatusInternalServerError, components.Ports[GolangAPIServer], httpClientForPublicApi) checkApiServerStatus(appId, http.StatusInternalServerError, components.Ports[GolangAPIServer], httpClientForPublicApi) @@ -99,7 +98,6 @@ var _ = Describe("Integration_GolangApi_Scheduler", func() { }) Context("Create policy", func() { It("should error with status code 500", func() { - By("check public api") policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") doAttachPolicy(appId, policyStr, http.StatusInternalServerError, components.Ports[GolangAPIServer], httpClientForPublicApi) checkApiServerStatus(appId, http.StatusInternalServerError, components.Ports[GolangAPIServer], httpClientForPublicApi) @@ -138,7 +136,6 @@ var _ = Describe("Integration_GolangApi_Scheduler", func() { }) Context("Create policy", func() { It("should error with status code 401", func() { - By("check public api") policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") doAttachPolicy(appId, policyStr, http.StatusUnauthorized, components.Ports[GolangAPIServer], httpClientForPublicApi) checkApiServerStatus(appId, http.StatusUnauthorized, components.Ports[GolangAPIServer], httpClientForPublicApi) @@ -169,7 +166,6 @@ var _ = Describe("Integration_GolangApi_Scheduler", func() { }) Context("Create policy", func() { It("should error with status code 401", func() { - By("check public api") policyStr = readPolicyFromFile("fakePolicyWithSchedule.json") doAttachPolicy(appId, policyStr, http.StatusUnauthorized, components.Ports[GolangAPIServer], httpClientForPublicApi) checkApiServerStatus(appId, http.StatusUnauthorized, components.Ports[GolangAPIServer], httpClientForPublicApi) From 8f059adac8fb4ae059b799d1c4df696de6ef916a Mon Sep 17 00:00:00 2001 From: zyjiaobj Date: Wed, 18 Sep 2019 10:06:57 +0800 Subject: [PATCH 16/16] fix issues detected in source code scan Q3-2019 --- api/lib/oauth/oauth.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/lib/oauth/oauth.js b/api/lib/oauth/oauth.js index ce5a86895..fac7e8aa9 100644 --- a/api/lib/oauth/oauth.js +++ b/api/lib/oauth/oauth.js @@ -171,7 +171,7 @@ module.exports = function(settings) { }; request(options, function(error, response, body) { if (error) { - logger.error("Failed to check user token via UAA", { "userToken": userToken, "http-options": options, "error": error }); + logger.error("Failed to check user token via UAA", { "error": error }); error.statusCode = HttpStatus.INTERNAL_SERVER_ERROR; callback(error, null); } else { @@ -181,7 +181,7 @@ module.exports = function(settings) { var errorObj = { "statusCode": response.statusCode }; - logger.error("Failed to check user token via UAA", { "userToken": userToken, "http-options": options, "error": errorObj, "body": body }); + logger.error("Failed to check user token via UAA", { "error": errorObj, "body": body }); callback(errorObj, null); } }