Skip to content

Commit 2d44cf7

Browse files
committed
Simplify DatabaseMetricValuesStore
Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
1 parent 8cbbec4 commit 2d44cf7

File tree

3 files changed

+167
-34
lines changed

3 files changed

+167
-34
lines changed
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
* Copyright Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import {
18+
mockServices,
19+
TestDatabaseId,
20+
TestDatabases,
21+
} from '@backstage/backend-test-utils';
22+
import { DatabaseMetricValuesStore } from './DatabaseMetricValuesStore';
23+
import { DbMetricValue } from './MetricValuesStore';
24+
import { migrate } from './migration';
25+
26+
const metricValues: Omit<DbMetricValue, 'id'>[] = [
27+
{
28+
catalog_entity_ref: 'component:default/test-service',
29+
metric_id: 'github.metric1',
30+
value: 41,
31+
timestamp: new Date('2023-01-01T00:00:00Z'),
32+
error_message: undefined,
33+
},
34+
{
35+
catalog_entity_ref: 'component:default/another-service',
36+
metric_id: 'github.metric1',
37+
value: 25,
38+
timestamp: new Date('2023-01-01T00:00:00Z'),
39+
error_message: undefined,
40+
},
41+
{
42+
catalog_entity_ref: 'component:default/another-service',
43+
metric_id: 'github.metric2',
44+
value: undefined,
45+
timestamp: new Date('2023-01-01T00:00:00Z'),
46+
error_message: 'Failed to fetch metric',
47+
},
48+
];
49+
50+
describe('DatabaseMetricValuesStore', () => {
51+
const databases = TestDatabases.create({
52+
ids: ['POSTGRES_13', 'SQLITE_3'],
53+
});
54+
55+
async function createDatabase(databaseId: TestDatabaseId) {
56+
const knex = await databases.init(databaseId);
57+
const mockDatabaseService = mockServices.database.mock({
58+
getClient: async () => knex,
59+
migrations: { skip: false },
60+
});
61+
62+
await migrate(mockDatabaseService);
63+
return {
64+
knex,
65+
db: new DatabaseMetricValuesStore(knex),
66+
};
67+
}
68+
69+
describe('createMetricValues', () => {
70+
it.each(databases.eachSupportedId())(
71+
'should successfully insert metric values - %p',
72+
async databaseId => {
73+
const { knex, db } = await createDatabase(databaseId);
74+
75+
await expect(
76+
db.createMetricValues(metricValues),
77+
).resolves.not.toThrow();
78+
79+
const insertedValues = await knex('metric_values').select('*');
80+
expect(insertedValues).toHaveLength(3);
81+
expect(insertedValues[0].catalog_entity_ref).toBe(
82+
'component:default/test-service',
83+
);
84+
expect(insertedValues[0].metric_id).toBe('github.metric1');
85+
expect(insertedValues[0].value).toBe(41);
86+
expect(insertedValues[0].error_message).toBe(null);
87+
expect(insertedValues[1].value).toBe(25);
88+
expect(insertedValues[2].metric_id).toBe('github.metric2');
89+
expect(insertedValues[2].value).toBe(null);
90+
expect(insertedValues[2].error_message).toBe('Failed to fetch metric');
91+
},
92+
);
93+
94+
describe('readLatestEntityMetricValues', () => {
95+
it.each(databases.eachSupportedId())(
96+
'should return latest metric values for entity and metrics - %p',
97+
async databaseId => {
98+
const { knex, db } = await createDatabase(databaseId);
99+
100+
const baseTime = new Date('2023-01-01T00:00:00Z');
101+
const laterTime = new Date('2023-01-01T01:00:00Z');
102+
103+
await knex('metric_values').insert([
104+
{
105+
...metricValues[0],
106+
timestamp: baseTime, // older time
107+
},
108+
{
109+
...metricValues[1],
110+
timestamp: laterTime, // newer time, value should be returned
111+
},
112+
{
113+
...metricValues[2],
114+
timestamp: laterTime, // newer time, different entity
115+
},
116+
{
117+
catalog_entity_ref: 'component:default/test-service',
118+
metric_id: 'github.metric2',
119+
value: undefined,
120+
timestamp: baseTime,
121+
error_message: 'Failed to fetch metric',
122+
},
123+
]);
124+
125+
const result = await db.readLatestEntityMetricValues(
126+
'component:default/test-service',
127+
['github.metric1', 'github.metric2'],
128+
);
129+
130+
expect(result).toHaveLength(2);
131+
132+
const metric1Result = result.find(
133+
r => r.metric_id === 'github.metric1',
134+
);
135+
const metric2Result = result.find(
136+
r => r.metric_id === 'github.metric2',
137+
);
138+
139+
expect(metric1Result).toBeDefined();
140+
expect(metric1Result!.value).toBe(41);
141+
expect(metric1Result!.catalog_entity_ref).toBe(
142+
'component:default/test-service',
143+
);
144+
145+
expect(metric2Result).toBeDefined();
146+
expect(metric2Result!.value).toBe(null);
147+
expect(metric2Result!.catalog_entity_ref).toBe(
148+
'component:default/test-service',
149+
);
150+
},
151+
);
152+
});
153+
});
154+
});

workspaces/scorecard/plugins/scorecard-backend/src/database/DatabaseMetricValuesStore.ts

Lines changed: 12 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,20 @@
1515
*/
1616

1717
import { Knex } from 'knex';
18-
import { LoggerService } from '@backstage/backend-plugin-api';
1918
import { DbMetricValue, MetricValuesStore } from './MetricValuesStore';
2019

2120
export class DatabaseMetricValuesStore implements MetricValuesStore {
22-
private readonly knex: Knex;
23-
private readonly logger: LoggerService;
2421
private readonly tableName = 'metric_values';
2522

26-
constructor(options: { knex: Knex; logger: LoggerService }) {
27-
this.knex = options.knex;
28-
this.logger = options.logger;
29-
}
23+
constructor(private readonly knex: Knex<any, any[]>) {}
3024

3125
/**
3226
* Insert multiple metric values in a batch
3327
*/
3428
async createMetricValues(
3529
metricValues: Omit<DbMetricValue, 'id'>[],
3630
): Promise<void> {
37-
try {
38-
await this.knex(this.tableName).insert(metricValues);
39-
} catch (error) {
40-
this.logger.error(`Failed to insert metric values batch: ${error}`);
41-
throw error;
42-
}
31+
await this.knex(this.tableName).insert(metricValues);
4332
}
4433

4534
/**
@@ -49,22 +38,15 @@ export class DatabaseMetricValuesStore implements MetricValuesStore {
4938
catalog_entity_ref: string,
5039
metric_ids: string[],
5140
): Promise<DbMetricValue[]> {
52-
try {
53-
const result = await this.knex(this.tableName)
54-
.select('*')
55-
.whereIn(
56-
'id',
57-
this.knex(this.tableName)
58-
.max('id')
59-
.whereIn('metric_id', metric_ids)
60-
.where('catalog_entity_ref', catalog_entity_ref)
61-
.groupBy('metric_id'),
62-
);
63-
64-
return result;
65-
} catch (error) {
66-
this.logger.error(`Failed to get latest metric values: ${error}`);
67-
throw error;
68-
}
41+
return await this.knex(this.tableName)
42+
.select('*')
43+
.whereIn(
44+
'id',
45+
this.knex(this.tableName)
46+
.max('id')
47+
.whereIn('metric_id', metric_ids)
48+
.where('catalog_entity_ref', catalog_entity_ref)
49+
.groupBy('metric_id'),
50+
);
6951
}
7052
}

workspaces/scorecard/plugins/scorecard-backend/src/plugin.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,7 @@ export const scorecardPlugin = createBackendPlugin({
8888
await migrate(database);
8989

9090
const knex = await database.getClient();
91-
const metricValuesStore = new DatabaseMetricValuesStore({
92-
knex,
93-
logger,
94-
});
91+
const metricValuesStore = new DatabaseMetricValuesStore(knex);
9592

9693
const catalogMetricService = new CatalogMetricService({
9794
catalog,

0 commit comments

Comments
 (0)