From cbaa469633f8aa2bdc1319f1a19e87b881ed6025 Mon Sep 17 00:00:00 2001 From: geigerj0 <112163019+geigerj0@users.noreply.github.com> Date: Wed, 24 Apr 2024 11:16:57 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=95=B5=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/acceptance/app/dynamic_policy_test.go | 6 +- .../eventgenerator/client/log_cache_client.go | 2 +- .../client/log_cache_client_test.go | 238 +++++++++++++++--- 3 files changed, 212 insertions(+), 34 deletions(-) diff --git a/src/acceptance/app/dynamic_policy_test.go b/src/acceptance/app/dynamic_policy_test.go index 18f8f45be7..0fce9d37ea 100644 --- a/src/acceptance/app/dynamic_policy_test.go +++ b/src/acceptance/app/dynamic_policy_test.go @@ -217,12 +217,13 @@ var _ = Describe("AutoScaler dynamic policy", func() { Context("when throughput is less than scaling in threshold", func() { BeforeEach(func() { - policy = GenerateDynamicScaleInPolicy(1, 2, "throughput", 100) + policy = GenerateDynamicScaleInPolicy(1, 2, "throughput", 30) initialInstanceCount = 2 }) JustBeforeEach(func() { - ticker = time.NewTicker(10 * time.Second) + // simulate ongoing ~1 requests per second + ticker = time.NewTicker(1 * time.Second) go func(chan bool) { defer GinkgoRecover() for { @@ -241,7 +242,6 @@ var _ = Describe("AutoScaler dynamic policy", func() { WaitForNInstancesRunning(appGUID, 1, 5*time.Minute) }) }) - }) // To check existing aggregated cpu metrics do: cf asm APP_NAME cpu diff --git a/src/autoscaler/eventgenerator/client/log_cache_client.go b/src/autoscaler/eventgenerator/client/log_cache_client.go index 6a384e7474..dee7a9cc5a 100644 --- a/src/autoscaler/eventgenerator/client/log_cache_client.go +++ b/src/autoscaler/eventgenerator/client/log_cache_client.go @@ -140,7 +140,7 @@ func (c *LogCacheClient) GetMetrics(appId string, metricType string, startTime t // return empty metrics if there are no samples, this usually happens in case there were no recent http-requests towards the application if len(vector.GetSamples()) <= 0 { - return c.emptyAppInstanceMetrics(appId, models.MetricNameThroughput, models.UnitRPS, now) + return c.emptyAppInstanceMetrics(appId, metricType, metricTypeUnit, now) } // convert result into autoscaler metric model diff --git a/src/autoscaler/eventgenerator/client/log_cache_client_test.go b/src/autoscaler/eventgenerator/client/log_cache_client_test.go index 7a4f1ebb24..21271c53be 100644 --- a/src/autoscaler/eventgenerator/client/log_cache_client_test.go +++ b/src/autoscaler/eventgenerator/client/log_cache_client_test.go @@ -233,49 +233,227 @@ var _ = Describe("LogCacheClient", func() { }) }) + When("errors occur reading via PromQL API", func() { + When("PromQL call fails", func() { + It("returns an error", func() { + fakeGoLogCacheReader.PromQLReturns(nil, errors.New("fail")) + _, err := logCacheClient.GetMetrics("app-id", "throughput", startTime, endTime) + Expect(err).To(HaveOccurred()) + }) + }) + + When("PromQL result is not a vector", func() { + It("returns an error", func() { + fakeGoLogCacheReader.PromQLReturns(nil, nil) + _, err := logCacheClient.GetMetrics("app-id", "throughput", startTime, endTime) + Expect(err).To(HaveOccurred()) + }) + }) + + When("sample does not contain instance_id", func() { + It("returns an error", func() { + fakeGoLogCacheReader.PromQLReturns(&logcache_v1.PromQL_InstantQueryResult{ + Result: &logcache_v1.PromQL_InstantQueryResult_Vector{ + Vector: &logcache_v1.PromQL_Vector{ + Samples: []*logcache_v1.PromQL_Sample{ + { + Metric: map[string]string{ + // "instance_id": "0", is missing here + }, + }, + }, + }, + }, + }, nil) + _, err := logCacheClient.GetMetrics("app-id", "throughput", startTime, endTime) + Expect(err).To(HaveOccurred()) + }) + }) + + When("instance_id can not be parsed to uint", func() { + It("returns an error", func() { + fakeGoLogCacheReader.PromQLReturns(&logcache_v1.PromQL_InstantQueryResult{ + Result: &logcache_v1.PromQL_InstantQueryResult_Vector{ + Vector: &logcache_v1.PromQL_Vector{ + Samples: []*logcache_v1.PromQL_Sample{ + { + Metric: map[string]string{ + "instance_id": "iam-no-uint", + }, + }, + }, + }, + }, + }, nil) + _, err := logCacheClient.GetMetrics("app-id", "throughput", startTime, endTime) + Expect(err).To(HaveOccurred()) + }) + }) + + When("sample does not contain a point", func() { + It("returns an error", func() { + fakeGoLogCacheReader.PromQLReturns(&logcache_v1.PromQL_InstantQueryResult{ + Result: &logcache_v1.PromQL_InstantQueryResult_Vector{ + Vector: &logcache_v1.PromQL_Vector{ + Samples: []*logcache_v1.PromQL_Sample{ + { + Metric: map[string]string{ + "instance_id": "0", + }, + }, + }, + }, + }, + }, nil) + _, err := logCacheClient.GetMetrics("app-id", "throughput", startTime, endTime) + Expect(err).To(HaveOccurred()) + }) + }) + }) + When("reading throughput metrics", func() { - It("should work", func() { - fakeGoLogCacheReader.PromQLReturns(&logcache_v1.PromQL_InstantQueryResult{ - Result: &logcache_v1.PromQL_InstantQueryResult_Vector{ - Vector: &logcache_v1.PromQL_Vector{ - Samples: []*logcache_v1.PromQL_Sample{ - { - Metric: map[string]string{ - "instance_id": "0", + When("PromQL API returns a vector with no samples", func() { + It("returns empty metrics", func() { + fakeGoLogCacheReader.PromQLReturns(&logcache_v1.PromQL_InstantQueryResult{ + Result: &logcache_v1.PromQL_InstantQueryResult_Vector{ + Vector: &logcache_v1.PromQL_Vector{}, + }, + }, nil) + + metrics, err := logCacheClient.GetMetrics("app-id", "throughput", startTime, endTime) + + Expect(err).To(Not(HaveOccurred())) + Expect(metrics).To(HaveLen(1)) + + Expect(metrics[0].AppId).To(Equal("app-id")) + Expect(metrics[0].InstanceIndex).To(Equal(uint32(0))) + Expect(metrics[0].Name).To(Equal("throughput")) + Expect(metrics[0].Unit).To(Equal("rps")) + Expect(metrics[0].Value).To(Equal("0")) + }) + }) + + When("promql api returns a vector with samples", func() { + It("returns metrics ", func() { + fakeEnvelopeProcessor.GetCollectionIntervalReturns(40 * time.Second) + fakeGoLogCacheReader.PromQLReturns(&logcache_v1.PromQL_InstantQueryResult{ + Result: &logcache_v1.PromQL_InstantQueryResult_Vector{ + Vector: &logcache_v1.PromQL_Vector{ + Samples: []*logcache_v1.PromQL_Sample{ + { + Metric: map[string]string{ + "instance_id": "0", + }, + Point: &logcache_v1.PromQL_Point{ + Value: 123, + }, }, - Point: &logcache_v1.PromQL_Point{ - Value: 123, + { + Metric: map[string]string{ + "instance_id": "1", + }, + Point: &logcache_v1.PromQL_Point{ + Value: 321, + }, }, }, - { - Metric: map[string]string{ - "instance_id": "1", + }, + }, + }, nil) + + metrics, err := logCacheClient.GetMetrics("app-id", "throughput", startTime, endTime) + + _, query, _ := fakeGoLogCacheReader.PromQLArgsForCall(0) + Expect(query).To(Equal("sum by (instance_id) (count_over_time(http{source_id='app-id'}[40s])) / 40")) + + Expect(err).To(Not(HaveOccurred())) + Expect(metrics).To(HaveLen(2)) + + Expect(metrics[0].AppId).To(Equal("app-id")) + Expect(metrics[0].InstanceIndex).To(Equal(uint32(0))) + Expect(metrics[0].Name).To(Equal("throughput")) + Expect(metrics[0].Unit).To(Equal("rps")) + Expect(metrics[0].Value).To(Equal("123")) + + Expect(metrics[1].AppId).To(Equal("app-id")) + Expect(metrics[1].InstanceIndex).To(Equal(uint32(1))) + Expect(metrics[1].Name).To(Equal("throughput")) + Expect(metrics[1].Unit).To(Equal("rps")) + Expect(metrics[1].Value).To(Equal("321")) + }) + }) + }) + + When("reading responsetime metrics", func() { + When("PromQL API returns a vector with no samples", func() { + It("returns empty metrics", func() { + fakeGoLogCacheReader.PromQLReturns(&logcache_v1.PromQL_InstantQueryResult{ + Result: &logcache_v1.PromQL_InstantQueryResult_Vector{ + Vector: &logcache_v1.PromQL_Vector{}, + }, + }, nil) + + metrics, err := logCacheClient.GetMetrics("app-id", "responsetime", startTime, endTime) + + Expect(err).To(Not(HaveOccurred())) + Expect(metrics).To(HaveLen(1)) + + Expect(metrics[0].AppId).To(Equal("app-id")) + Expect(metrics[0].InstanceIndex).To(Equal(uint32(0))) + Expect(metrics[0].Name).To(Equal("responsetime")) + Expect(metrics[0].Unit).To(Equal("ms")) + Expect(metrics[0].Value).To(Equal("0")) + }) + }) + + When("promql api returns a vector with samples", func() { + It("reads from PromQL API ", func() { + fakeEnvelopeProcessor.GetCollectionIntervalReturns(40 * time.Second) + fakeGoLogCacheReader.PromQLReturns(&logcache_v1.PromQL_InstantQueryResult{ + Result: &logcache_v1.PromQL_InstantQueryResult_Vector{ + Vector: &logcache_v1.PromQL_Vector{ + Samples: []*logcache_v1.PromQL_Sample{ + { + Metric: map[string]string{ + "instance_id": "0", + }, + Point: &logcache_v1.PromQL_Point{ + Value: 200, + }, }, - Point: &logcache_v1.PromQL_Point{ - Value: 321, + { + Metric: map[string]string{ + "instance_id": "1", + }, + Point: &logcache_v1.PromQL_Point{ + Value: 300, + }, }, }, }, }, - }, - }, nil) + }, nil) + + metrics, err := logCacheClient.GetMetrics("app-id", "responsetime", startTime, endTime) - metrics, err := logCacheClient.GetMetrics("app-id", "throughput", startTime, endTime) + _, query, _ := fakeGoLogCacheReader.PromQLArgsForCall(0) + Expect(query).To(Equal("avg by (instance_id) (max_over_time(http{source_id='app-id'}[40s])) / (1000 * 1000)")) - Expect(err).To(Not(HaveOccurred())) - Expect(metrics).To(HaveLen(2)) + Expect(err).To(Not(HaveOccurred())) + Expect(metrics).To(HaveLen(2)) - Expect(metrics[0].AppId).To(Equal("app-id")) - Expect(metrics[0].InstanceIndex).To(Equal(uint32(0))) - Expect(metrics[0].Name).To(Equal("throughput")) - Expect(metrics[0].Unit).To(Equal("rps")) - Expect(metrics[0].Value).To(Equal("123")) + Expect(metrics[0].AppId).To(Equal("app-id")) + Expect(metrics[0].InstanceIndex).To(Equal(uint32(0))) + Expect(metrics[0].Name).To(Equal("responsetime")) + Expect(metrics[0].Unit).To(Equal("ms")) + Expect(metrics[0].Value).To(Equal("200")) - Expect(metrics[1].AppId).To(Equal("app-id")) - Expect(metrics[1].InstanceIndex).To(Equal(uint32(1))) - Expect(metrics[1].Name).To(Equal("throughput")) - Expect(metrics[1].Unit).To(Equal("rps")) - Expect(metrics[1].Value).To(Equal("321")) + Expect(metrics[1].AppId).To(Equal("app-id")) + Expect(metrics[1].InstanceIndex).To(Equal(uint32(1))) + Expect(metrics[1].Name).To(Equal("responsetime")) + Expect(metrics[1].Unit).To(Equal("ms")) + Expect(metrics[1].Value).To(Equal("300")) + }) }) })