catalog-backend: integration tests for raw response + fix raw json stream

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2024-12-12 14:34:16 +01:00
parent d706bb5b34
commit 31e2ca8d18
3 changed files with 76 additions and 28 deletions
@@ -860,7 +860,7 @@ describe('createRouter readonly disabled', () => {
});
});
describe('createRouter readonly enabled', () => {
describe('createRouter readonly and raw json enabled', () => {
let entitiesCatalog: jest.Mocked<EntitiesCatalog>;
let app: express.Express;
let locationService: jest.Mocked<LocationService>;
@@ -883,6 +883,7 @@ describe('createRouter readonly enabled', () => {
getLocationByEntity: jest.fn(),
};
const router = await createRouter({
enableRawJson: true,
entitiesCatalog,
locationService,
logger: mockServices.logger.mock(),
@@ -910,7 +911,7 @@ describe('createRouter readonly enabled', () => {
];
entitiesCatalog.queryEntities.mockResolvedValueOnce({
items: { type: 'object', entities: [entities[0]] },
items: { type: 'raw', entities: [JSON.stringify(entities[0])] },
pageInfo: {},
totalItems: 1,
});
+7 -11
View File
@@ -192,17 +192,13 @@ export function createEntityArrayJsonStream(
}
if (response.type === 'raw') {
let result = true;
let needsDrain = false;
for (const item of response.entities) {
if (firstSend) {
result ||= res.write('[');
firstSend = false;
} else {
result ||= res.write(',');
}
result ||= res.write(item);
const prefix = firstSend ? '[' : ',';
firstSend = false;
needsDrain ||= !res.write(prefix + item, 'utf8');
}
return result;
return !needsDrain;
}
let data: string;
@@ -215,13 +211,13 @@ export function createEntityArrayJsonStream(
}
firstSend = false;
return res.write(data);
return res.write(data, 'utf8');
},
complete() {
if (firstSend) {
res.json([]);
} else {
res.end(prettyPrint ? '\n]' : ']');
res.end(prettyPrint ? '\n]' : ']', 'utf8');
}
completed = true;
},
@@ -30,7 +30,6 @@ import {
processingResult,
} from '@backstage/plugin-catalog-node';
import { PermissionEvaluator } from '@backstage/plugin-permission-common';
import { JsonObject } from '@backstage/types';
import { createHash } from 'crypto';
import { Knex } from 'knex';
import { EntitiesCatalog } from '../catalog/types';
@@ -199,7 +198,7 @@ class TestHarness {
readonly #proxyProgressTracker: ProxyProgressTracker;
static async create(options?: {
config?: JsonObject;
enableRawJson?: boolean;
logger?: LoggerService;
db?: Knex;
permissions?: PermissionEvaluator;
@@ -209,21 +208,19 @@ class TestHarness {
emit: CatalogProcessorEmit,
): Promise<Entity>;
}) {
const config = new ConfigReader(
options?.config ?? {
backend: {
database: {
client: 'better-sqlite3',
connection: ':memory:',
},
},
catalog: {
stitchingStrategy: {
mode: 'immediate',
},
const config = new ConfigReader({
backend: {
database: {
client: 'better-sqlite3',
connection: ':memory:',
},
},
);
catalog: {
stitchingStrategy: {
mode: 'immediate',
},
},
});
const logger = options?.logger ?? mockServices.logger.mock();
const db =
options?.db ??
@@ -280,6 +277,7 @@ class TestHarness {
database: db,
logger,
stitcher,
enableRawJson: options?.enableRawJson,
});
const proxyProgressTracker = new ProxyProgressTracker(
new NoopProgressTracker(),
@@ -787,4 +785,57 @@ describe('Catalog Backend Integration', () => {
],
});
});
it('should return valid responses in raw JSON mode', async () => {
const harness = await TestHarness.create({
enableRawJson: true,
});
const entityA = {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: {
name: 'a',
annotations: {
'backstage.io/managed-by-location': 'url:.',
'backstage.io/managed-by-origin-location': 'url:.',
},
},
};
const entityB = {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: {
name: 'b',
annotations: {
'backstage.io/managed-by-location': 'url:.',
'backstage.io/managed-by-origin-location': 'url:.',
},
},
};
await harness.setInputEntities([entityA, entityB]);
await expect(harness.process()).resolves.toEqual({});
await expect(harness.getOutputEntities()).resolves.toEqual({
'component:default/a': {
...entityA,
metadata: {
...entityA.metadata,
etag: expect.any(String),
uid: expect.any(String),
},
relations: [],
},
'component:default/b': {
...entityB,
metadata: {
...entityB.metadata,
etag: expect.any(String),
uid: expect.any(String),
},
relations: [],
},
});
});
});