From 840cab000095004ff14c63a537084973383113f6 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 26 May 2024 21:14:20 +0200 Subject: [PATCH] events-backend: add integration tests for postgres Signed-off-by: Patrik Oldsberg --- .../src/service/EventsPlugin.test.ts | 287 ++++++++++-------- 1 file changed, 159 insertions(+), 128 deletions(-) diff --git a/plugins/events-backend/src/service/EventsPlugin.test.ts b/plugins/events-backend/src/service/EventsPlugin.test.ts index 21be572a20..e73e636d24 100644 --- a/plugins/events-backend/src/service/EventsPlugin.test.ts +++ b/plugins/events-backend/src/service/EventsPlugin.test.ts @@ -21,6 +21,8 @@ import { createServiceFactory, } from '@backstage/backend-plugin-api'; import { + TestDatabaseId, + TestDatabases, mockCredentials, mockServices, startTestBackend, @@ -100,149 +102,178 @@ describe('eventsPlugin', () => { }); describe('event bus', () => { - it('should be possible to publish events as a service', async () => { - const { server } = await startTestBackend({ - features: [eventsPlugin()], - }); - - await request(server) - .post('/api/events/bus/v1/events') - .set('authorization', mockCredentials.none.header()) - .send({ event: { topic: 'test', payload: { n: 1 } } }) - .expect(401); - - await request(server) - .post('/api/events/bus/v1/events') - .set('authorization', mockCredentials.user.header()) - .send({ event: { topic: 'test', payload: { n: 1 } } }) - .expect(403); - - await request(server) - .post('/api/events/bus/v1/events') - .set('authorization', mockCredentials.service.header()) - .send({ event: { topic: 'test', payload: { n: 1 } } }) - .expect(204); // 204, since there are no subscribers + const databases = TestDatabases.create({ + ids: ['SQLITE_3', 'POSTGRES_9', 'POSTGRES_13', 'POSTGRES_16'], }); - it('should be possible to subscribe as a service and receive an event', async () => { - const { server } = await startTestBackend({ - features: [eventsPlugin()], - }); + async function mockKnexFactory(databaseId: TestDatabaseId) { + const knex = await databases.init(databaseId); + return mockServices.database.mock({ + getClient: async () => knex, + }).factory; + } - await request(server) - .put('/api/events/bus/v1/subscriptions/tester') - .set('authorization', mockCredentials.none.header()) - .send({ topics: ['test'] }) - .expect(401); + it.each(databases.eachSupportedId())( + 'should be possible to publish events as a service, %p', + async databaseId => { + const backend = await startTestBackend({ + features: [eventsPlugin(), await mockKnexFactory(databaseId)], + }); + const { server } = backend; - await request(server) - .put('/api/events/bus/v1/subscriptions/tester') - .set('authorization', mockCredentials.user.header()) - .send({ topics: ['test'] }) - .expect(403); + await request(server) + .post('/api/events/bus/v1/events') + .set('authorization', mockCredentials.none.header()) + .send({ event: { topic: 'test', payload: { n: 1 } } }) + .expect(401); - await request(server) - .put('/api/events/bus/v1/subscriptions/tester') - .set('authorization', mockCredentials.service.header()) - .send({ topics: ['test'] }) - .expect(201); + await request(server) + .post('/api/events/bus/v1/events') + .set('authorization', mockCredentials.user.header()) + .send({ event: { topic: 'test', payload: { n: 1 } } }) + .expect(403); - await request(server) - .get('/api/events/bus/v1/subscriptions/tester/events') - .set('authorization', mockCredentials.none.header()) - .send({ topics: ['test'] }) - .expect(401); + await request(server) + .post('/api/events/bus/v1/events') + .set('authorization', mockCredentials.service.header()) + .send({ event: { topic: 'test', payload: { n: 1 } } }) + .expect(204); // 204, since there are no subscribers - await request(server) - .get('/api/events/bus/v1/subscriptions/tester/events') - .set('authorization', mockCredentials.user.header()) - .send({ topics: ['test'] }) - .expect(403); + await backend.stop(); + }, + ); - await request(server) - .post('/api/events/bus/v1/events') - .set('authorization', mockCredentials.service.header()) - .send({ event: { topic: 'test', payload: { n: 1 } } }) - .expect(201); // 201, since there is a subscriber + it.each(databases.eachSupportedId())( + 'should be possible to subscribe as a service and receive an event, %p', + async databaseId => { + const backend = await startTestBackend({ + features: [eventsPlugin(), await mockKnexFactory(databaseId)], + }); + const { server } = backend; - await request(server) - .get('/api/events/bus/v1/subscriptions/tester/events') - .set('authorization', mockCredentials.service.header()) - .send({ topics: ['test'] }) - .expect(200, { + await request(server) + .put('/api/events/bus/v1/subscriptions/tester') + .set('authorization', mockCredentials.none.header()) + .send({ topics: ['test'] }) + .expect(401); + + await request(server) + .put('/api/events/bus/v1/subscriptions/tester') + .set('authorization', mockCredentials.user.header()) + .send({ topics: ['test'] }) + .expect(403); + + await request(server) + .put('/api/events/bus/v1/subscriptions/tester') + .set('authorization', mockCredentials.service.header()) + .send({ topics: ['test'] }) + .expect(201); + + await request(server) + .get('/api/events/bus/v1/subscriptions/tester/events') + .set('authorization', mockCredentials.none.header()) + .send({ topics: ['test'] }) + .expect(401); + + await request(server) + .get('/api/events/bus/v1/subscriptions/tester/events') + .set('authorization', mockCredentials.user.header()) + .send({ topics: ['test'] }) + .expect(403); + + await request(server) + .post('/api/events/bus/v1/events') + .set('authorization', mockCredentials.service.header()) + .send({ event: { topic: 'test', payload: { n: 1 } } }) + .expect(201); // 201, since there is a subscriber + + await request(server) + .get('/api/events/bus/v1/subscriptions/tester/events') + .set('authorization', mockCredentials.service.header()) + .send({ topics: ['test'] }) + .expect(200, { + events: [{ topic: 'test', payload: { n: 1 } }], + }); + + await backend.stop(); + }, + ); + + it.each(databases.eachSupportedId())( + 'should only send an event for each subscriber once, %p', + async databaseId => { + const backend = await startTestBackend({ + features: [eventsPlugin(), await mockKnexFactory(databaseId)], + }); + const { server } = backend; + + // 2 subscribers + await request(server) + .put('/api/events/bus/v1/subscriptions/tester-1') + .set('authorization', mockCredentials.service.header()) + .send({ topics: ['test'] }) + .expect(201); + await request(server) + .put('/api/events/bus/v1/subscriptions/tester-2') + .set('authorization', mockCredentials.service.header()) + .send({ topics: ['test'] }) + .expect(201); + + // A single event + await request(server) + .post('/api/events/bus/v1/events') + .set('authorization', mockCredentials.service.header()) + .send({ event: { topic: 'test', payload: { n: 1 } } }) + .expect(201); + + // Single client for subscriber 1 gets the event + await request(server) + .get('/api/events/bus/v1/subscriptions/tester-1/events') + .set('authorization', mockCredentials.service.header()) + .send({ topics: ['test'] }) + .expect(200, { + events: [{ topic: 'test', payload: { n: 1 } }], + }); + + // Two clients for subscriber 2, only one gets the event + const res1 = request(server) + .get('/api/events/bus/v1/subscriptions/tester-2/events') + .set('authorization', mockCredentials.service.header()) + .send({ topics: ['test'] }); + const res2 = request(server) + .get('/api/events/bus/v1/subscriptions/tester-2/events') + .set('authorization', mockCredentials.service.header()) + .send({ topics: ['test'] }); + + const res = await Promise.race([res1, res2]); + expect(res.status).toBe(200); + expect(res.body).toEqual({ events: [{ topic: 'test', payload: { n: 1 } }], }); - }); - }); - it('should only send an event for each subscriber once', async () => { - const { server } = await startTestBackend({ - features: [eventsPlugin()], - }); + // Post another event, which triggers the other client to return + await request(server) + .post('/api/events/bus/v1/events') + .set('authorization', mockCredentials.service.header()) + .send({ event: { topic: 'test', payload: { n: 2 } } }) + .expect(201); - // 2 subscribers - await request(server) - .put('/api/events/bus/v1/subscriptions/tester-1') - .set('authorization', mockCredentials.service.header()) - .send({ topics: ['test'] }) - .expect(201); - await request(server) - .put('/api/events/bus/v1/subscriptions/tester-2') - .set('authorization', mockCredentials.service.header()) - .send({ topics: ['test'] }) - .expect(201); + const otherRes = await Promise.all([res1, res2]).then(rs => + rs.find(r => r !== res), + ); + expect(otherRes?.status).toBe(202); - // A single event - await request(server) - .post('/api/events/bus/v1/events') - .set('authorization', mockCredentials.service.header()) - .send({ event: { topic: 'test', payload: { n: 1 } } }) - .expect(201); + // Reading subscriber 2 should now return the second event only + await request(server) + .get('/api/events/bus/v1/subscriptions/tester-2/events') + .set('authorization', mockCredentials.service.header()) + .send({ topics: ['test'] }) + .expect(200, { + events: [{ topic: 'test', payload: { n: 2 } }], + }); - // Single client for subscriber 1 gets the event - await request(server) - .get('/api/events/bus/v1/subscriptions/tester-1/events') - .set('authorization', mockCredentials.service.header()) - .send({ topics: ['test'] }) - .expect(200, { - events: [{ topic: 'test', payload: { n: 1 } }], - }); - - // Two clients for subscriber 2, only one gets the event - const res1 = request(server) - .get('/api/events/bus/v1/subscriptions/tester-2/events') - .set('authorization', mockCredentials.service.header()) - .send({ topics: ['test'] }); - const res2 = request(server) - .get('/api/events/bus/v1/subscriptions/tester-2/events') - .set('authorization', mockCredentials.service.header()) - .send({ topics: ['test'] }); - - const res = await Promise.race([res1, res2]); - expect(res.status).toBe(200); - expect(res.body).toEqual({ - events: [{ topic: 'test', payload: { n: 1 } }], - }); - - // Post another event, which triggers the other client to return - await request(server) - .post('/api/events/bus/v1/events') - .set('authorization', mockCredentials.service.header()) - .send({ event: { topic: 'test', payload: { n: 2 } } }) - .expect(201); - - const otherRes = await Promise.all([res1, res2]).then(rs => - rs.find(r => r !== res), + await backend.stop(); + }, ); - expect(otherRes?.status).toBe(202); - - // Reading subscriber 2 should now return the second event only - await request(server) - .get('/api/events/bus/v1/subscriptions/tester-2/events') - .set('authorization', mockCredentials.service.header()) - .send({ topics: ['test'] }) - .expect(200, { - events: [{ topic: 'test', payload: { n: 2 } }], - }); }); });