From 705258c8b8d91c5aabb6c5be94e627313e622420 Mon Sep 17 00:00:00 2001 From: VoigtS Date: Tue, 17 Dec 2024 15:55:54 +0100 Subject: [PATCH 1/3] Add test cases to prevent future API breaks on AZ separated changes --- internal/api/api_test.go | 28 +++++++++++++++ .../fixtures/cluster-get-az-separated.json | 33 +++++++++++++++++ .../fixtures/domain-list-az-separated.json | 36 +++++++++++++++++++ .../fixtures/project-list-az-separated.json | 34 ++++++++++++++++++ .../api/fixtures/start-data-az-separated.sql | 13 +++++++ internal/reports/cluster.go | 3 +- internal/reports/domain.go | 1 + internal/reports/project.go | 3 +- 8 files changed, 147 insertions(+), 4 deletions(-) create mode 100644 internal/api/fixtures/cluster-get-az-separated.json create mode 100644 internal/api/fixtures/domain-list-az-separated.json create mode 100644 internal/api/fixtures/project-list-az-separated.json create mode 100644 internal/api/fixtures/start-data-az-separated.sql diff --git a/internal/api/api_test.go b/internal/api/api_test.go index a959212f..f9a27f4f 100644 --- a/internal/api/api_test.go +++ b/internal/api/api_test.go @@ -1250,3 +1250,31 @@ func (j JSONThatUnmarshalsInto) AssertResponseBody(t *testing.T, requestInfo str } return true } + +func Test_SeparatedToplogyOperations(t *testing.T) { + // This test structure ensures that the consumable limes APIs do not break with the introduction (or further changes) of the az separated toplogy. + s := setupTest(t, "fixtures/start-data-az-separated.sql") + assert.HTTPRequest{ + Method: "GET", + Path: "/v1/clusters/current", + Header: map[string]string{"X-Limes-V2-API-Preview": "per-az"}, + ExpectStatus: 200, + ExpectBody: assert.JSONFixtureFile("fixtures/cluster-get-az-separated.json"), + }.Check(t, s.Handler) + + assert.HTTPRequest{ + Method: "GET", + Path: "/v1/domains", + Header: map[string]string{"X-Limes-V2-API-Preview": "per-az"}, + ExpectStatus: 200, + ExpectBody: assert.JSONFixtureFile("./fixtures/domain-list-az-separated.json"), + }.Check(t, s.Handler) + + assert.HTTPRequest{ + Method: "GET", + Path: "/v1/domains/uuid-for-germany/projects", + Header: map[string]string{"X-Limes-V2-API-Preview": "per-az"}, + ExpectStatus: 200, + ExpectBody: assert.JSONFixtureFile("./fixtures/project-list-az-separated.json"), + }.Check(t, s.Handler) +} diff --git a/internal/api/fixtures/cluster-get-az-separated.json b/internal/api/fixtures/cluster-get-az-separated.json new file mode 100644 index 000000000..14d20e5f --- /dev/null +++ b/internal/api/fixtures/cluster-get-az-separated.json @@ -0,0 +1,33 @@ +{ + "cluster": { + "id": "current", + "services": [ + { + "type": "shared", + "area": "shared", + "resources": [ + { + "name": "capacity_portion", + "unit": "B", + "category": "portion", + "per_az": { + "az-one": { + "capacity": 0, + "projects_usage": 1, + "uncommitted_usage": 1 + }, + "az-two": { + "capacity": 0, + "projects_usage": 1, + "uncommitted_usage": 1 + } + }, + "usage": 2 + } + ], + "max_scraped_at": 22, + "min_scraped_at": 22 + } + ] + } +} diff --git a/internal/api/fixtures/domain-list-az-separated.json b/internal/api/fixtures/domain-list-az-separated.json new file mode 100644 index 000000000..a98fb88e --- /dev/null +++ b/internal/api/fixtures/domain-list-az-separated.json @@ -0,0 +1,36 @@ +{ + "domains": [ + { + "id": "uuid-for-germany", + "name": "germany", + "services": [ + { + "type": "shared", + "area": "shared", + "resources": [ + { + "name": "capacity_portion", + "unit": "B", + "category": "portion", + "per_az": { + "az-one": { + "quota": 5, + "usage": 1, + "uncommitted_usage": 1 + }, + "az-two": { + "quota": 5, + "usage": 1, + "uncommitted_usage": 1 + } + }, + "usage": 2 + } + ], + "max_scraped_at": 22, + "min_scraped_at": 22 + } + ] + } + ] +} diff --git a/internal/api/fixtures/project-list-az-separated.json b/internal/api/fixtures/project-list-az-separated.json new file mode 100644 index 000000000..5df6c684 --- /dev/null +++ b/internal/api/fixtures/project-list-az-separated.json @@ -0,0 +1,34 @@ +{ + "projects": [ + { + "id": "uuid-for-berlin", + "name": "berlin", + "parent_id": "uuid-for-germany", + "services": [ + { + "type": "shared", + "area": "shared", + "resources": [ + { + "name": "capacity_portion", + "unit": "B", + "category": "portion", + "per_az": { + "az-one": { + "quota": 5, + "usage": 1 + }, + "az-two": { + "quota": 5, + "usage": 1 + } + }, + "usage": 2 + } + ], + "scraped_at": 22 + } + ] + } + ] +} diff --git a/internal/api/fixtures/start-data-az-separated.sql b/internal/api/fixtures/start-data-az-separated.sql new file mode 100644 index 000000000..20ef4636 --- /dev/null +++ b/internal/api/fixtures/start-data-az-separated.sql @@ -0,0 +1,13 @@ +CREATE OR REPLACE FUNCTION unix(i integer) RETURNS timestamp AS $$ SELECT TO_TIMESTAMP(i) AT TIME ZONE 'Etc/UTC' $$ LANGUAGE SQL; + +INSERT INTO domains (id, name, uuid) VALUES (1, 'germany', 'uuid-for-germany'); + +INSERT INTO projects (id, domain_id, name, uuid, parent_uuid) VALUES (1, 1, 'berlin', 'uuid-for-berlin', 'uuid-for-germany'); + +INSERT INTO project_services (id, project_id, type, scraped_at, rates_scraped_at, checked_at, rates_checked_at) VALUES (1, 1, 'shared', UNIX(22), UNIX(23), UNIX(22), UNIX(23)); + +INSERT INTO project_resources (id, service_id, name, quota, backend_quota) VALUES (1, 1, 'capacity_portion', NULL, NULL); + +-- AZ separated resource does not include any az. +INSERT INTO project_az_resources (id, resource_id, az, quota, usage, physical_usage, subresources) VALUES (1, 1, 'az-one', 5, 1, NULL, ''); +INSERT INTO project_az_resources (id, resource_id, az, quota, usage, physical_usage, subresources) VALUES (2, 1, 'az-two', 5, 1, NULL, ''); diff --git a/internal/reports/cluster.go b/internal/reports/cluster.go index 5c73e260..5eef5dc0 100644 --- a/internal/reports/cluster.go +++ b/internal/reports/cluster.go @@ -372,8 +372,7 @@ func GetClusterResources(cluster *core.Cluster, now time.Time, dbi db.Interface, // zero and there are other AZs if len(resource.PerAZ) >= 2 { capaInAny := resource.PerAZ[limes.AvailabilityZoneAny] - // TODO: implement a proper fix and create a test case - // AZSeparateToplogy does not contain ANY AZ. + // AZSeparatedToplogy does not provide the "any" AZ. if capaInAny == nil { continue } diff --git a/internal/reports/domain.go b/internal/reports/domain.go index fd55ca8c..9e2c5fec 100644 --- a/internal/reports/domain.go +++ b/internal/reports/domain.go @@ -317,6 +317,7 @@ func GetDomains(cluster *core.Cluster, domainID *db.DomainID, now time.Time, dbi for _, resReport := range srvReport.Resources { if len(resReport.PerAZ) >= 2 { reportInAny := resReport.PerAZ[limes.AvailabilityZoneAny] + // AZSeparatedToplogy does not provide the "any" AZ. if reportInAny == nil { continue } diff --git a/internal/reports/project.go b/internal/reports/project.go index 55662d1a..a01dc1bd 100644 --- a/internal/reports/project.go +++ b/internal/reports/project.go @@ -401,8 +401,7 @@ func finalizeProjectResourceReport(projectReport *limesresources.ProjectReport, for _, resReport := range srvReport.Resources { if len(resReport.PerAZ) >= 2 { reportInAny := resReport.PerAZ[limes.AvailabilityZoneAny] - // TODO: implement a proper fix and isolate a test case - // AZSeparatedToplogy does not provide the any AZ. + // AZSeparatedToplogy does not provide the "any" AZ. if reportInAny == nil { continue } From 556376ef1e61555b29b0315e09584534ca5c18e4 Mon Sep 17 00:00:00 2001 From: VoigtS Date: Tue, 17 Dec 2024 16:02:50 +0100 Subject: [PATCH 2/3] Fix typos --- internal/api/api_test.go | 4 ++-- internal/collector/scrape_test.go | 2 +- internal/reports/cluster.go | 2 +- internal/reports/domain.go | 2 +- internal/reports/project.go | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/api/api_test.go b/internal/api/api_test.go index f9a27f4f..b1571517 100644 --- a/internal/api/api_test.go +++ b/internal/api/api_test.go @@ -1251,8 +1251,8 @@ func (j JSONThatUnmarshalsInto) AssertResponseBody(t *testing.T, requestInfo str return true } -func Test_SeparatedToplogyOperations(t *testing.T) { - // This test structure ensures that the consumable limes APIs do not break with the introduction (or further changes) of the az separated toplogy. +func Test_SeparatedTopologyOperations(t *testing.T) { + // This test structure ensures that the consumable limes APIs do not break with the introduction (or further changes) of the az separated topology. s := setupTest(t, "fixtures/start-data-az-separated.sql") assert.HTTPRequest{ Method: "GET", diff --git a/internal/collector/scrape_test.go b/internal/collector/scrape_test.go index 10f9a7b3..9ecc7a23 100644 --- a/internal/collector/scrape_test.go +++ b/internal/collector/scrape_test.go @@ -750,7 +750,7 @@ func Test_TopologyScrapes(t *testing.T) { mustFailT(t, job.ProcessOne(s.Ctx, withLabel), errors.New("during resource scrape of project germany/berlin: service: unittest, resource: capacity: scrape with topology type: az-separated returned AZs: [unknown]\nservice: unittest, resource: things: scrape with topology type: az-separated returned AZs: [unknown]")) s.Clock.StepBy(scrapeInterval) - // negative: empty toplogy should be treated as FlatResourceTopology + // negative: empty topology should be treated as FlatResourceTopology plugin.LiquidServiceInfo.Resources = map[liquid.ResourceName]liquid.ResourceInfo{"things": {Topology: liquid.FlatResourceTopology}} plugin.ReportedAZs = map[liquid.AvailabilityZone]struct{}{"az-one": {}} mustFailT(t, job.ProcessOne(s.Ctx, withLabel), errors.New("during resource scrape of project germany/dresden: service: unittest, resource: things: scrape with topology type: flat returned AZs: [az-one]")) diff --git a/internal/reports/cluster.go b/internal/reports/cluster.go index 5eef5dc0..70ec3b88 100644 --- a/internal/reports/cluster.go +++ b/internal/reports/cluster.go @@ -372,7 +372,7 @@ func GetClusterResources(cluster *core.Cluster, now time.Time, dbi db.Interface, // zero and there are other AZs if len(resource.PerAZ) >= 2 { capaInAny := resource.PerAZ[limes.AvailabilityZoneAny] - // AZSeparatedToplogy does not provide the "any" AZ. + // AZSeparatedTopology does not provide the "any" AZ. if capaInAny == nil { continue } diff --git a/internal/reports/domain.go b/internal/reports/domain.go index 9e2c5fec..e061434d 100644 --- a/internal/reports/domain.go +++ b/internal/reports/domain.go @@ -317,7 +317,7 @@ func GetDomains(cluster *core.Cluster, domainID *db.DomainID, now time.Time, dbi for _, resReport := range srvReport.Resources { if len(resReport.PerAZ) >= 2 { reportInAny := resReport.PerAZ[limes.AvailabilityZoneAny] - // AZSeparatedToplogy does not provide the "any" AZ. + // AZSeparatedTopology does not provide the "any" AZ. if reportInAny == nil { continue } diff --git a/internal/reports/project.go b/internal/reports/project.go index a01dc1bd..e3e6b07a 100644 --- a/internal/reports/project.go +++ b/internal/reports/project.go @@ -401,7 +401,7 @@ func finalizeProjectResourceReport(projectReport *limesresources.ProjectReport, for _, resReport := range srvReport.Resources { if len(resReport.PerAZ) >= 2 { reportInAny := resReport.PerAZ[limes.AvailabilityZoneAny] - // AZSeparatedToplogy does not provide the "any" AZ. + // AZSeparatedTopology does not provide the "any" AZ. if reportInAny == nil { continue } From be3962a325c805cd8b336eb6227f744da2fbd3fa Mon Sep 17 00:00:00 2001 From: VoigtS Date: Tue, 17 Dec 2024 16:09:31 +0100 Subject: [PATCH 3/3] Add backend_quota to fixture file --- internal/api/fixtures/start-data-az-separated.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/api/fixtures/start-data-az-separated.sql b/internal/api/fixtures/start-data-az-separated.sql index 20ef4636..9876b155 100644 --- a/internal/api/fixtures/start-data-az-separated.sql +++ b/internal/api/fixtures/start-data-az-separated.sql @@ -9,5 +9,5 @@ INSERT INTO project_services (id, project_id, type, scraped_at, rates_scraped_at INSERT INTO project_resources (id, service_id, name, quota, backend_quota) VALUES (1, 1, 'capacity_portion', NULL, NULL); -- AZ separated resource does not include any az. -INSERT INTO project_az_resources (id, resource_id, az, quota, usage, physical_usage, subresources) VALUES (1, 1, 'az-one', 5, 1, NULL, ''); -INSERT INTO project_az_resources (id, resource_id, az, quota, usage, physical_usage, subresources) VALUES (2, 1, 'az-two', 5, 1, NULL, ''); +INSERT INTO project_az_resources (id, resource_id, az, backend_quota, quota, usage, physical_usage, subresources) VALUES (1, 1, 'az-one', 5, 5, 1, NULL, ''); +INSERT INTO project_az_resources (id, resource_id, az, backend_quota, quota, usage, physical_usage, subresources) VALUES (2, 1, 'az-two', 5, 5, 1, NULL, '');