Fixes #27325 Stitch entity for which target of relationship has changed
Signed-off-by: Jordan Slott <jordan.slott@twosigma.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
Fixed an issue where entities would not be marked for restitching if only the target of a relationship changed.
|
||||
@@ -464,6 +464,111 @@ describe('DefaultCatalogProcessingEngine', () => {
|
||||
await engine.stop();
|
||||
});
|
||||
|
||||
it('should stitch both the previous and new sources when relation target changes', async () => {
|
||||
const engine = new DefaultCatalogProcessingEngine({
|
||||
config: new ConfigReader({}),
|
||||
logger: mockServices.logger.mock(),
|
||||
processingDatabase: db,
|
||||
knex: {} as any,
|
||||
orchestrator: orchestrator,
|
||||
stitcher: stitcher,
|
||||
createHash: () => hash,
|
||||
pollingIntervalMs: 100,
|
||||
});
|
||||
|
||||
db.transaction.mockImplementation(cb => cb((() => {}) as any));
|
||||
|
||||
const entity = {
|
||||
apiVersion: '1',
|
||||
kind: 'k',
|
||||
metadata: { name: 'me', namespace: 'ns' },
|
||||
};
|
||||
const processableEntity = {
|
||||
entityRef: 'foo',
|
||||
id: '1',
|
||||
unprocessedEntity: entity,
|
||||
resultHash: '',
|
||||
state: [] as any,
|
||||
nextUpdateAt: DateTime.now(),
|
||||
lastDiscoveryAt: DateTime.now(),
|
||||
};
|
||||
|
||||
db.listParents.mockResolvedValue({ entityRefs: [] });
|
||||
db.getProcessableEntities
|
||||
.mockResolvedValueOnce({
|
||||
items: [processableEntity],
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
items: [processableEntity],
|
||||
});
|
||||
db.updateProcessedEntity
|
||||
.mockImplementationOnce(async () => ({
|
||||
previous: { relations: [] },
|
||||
}))
|
||||
.mockImplementationOnce(async () => ({
|
||||
previous: {
|
||||
relations: [
|
||||
{
|
||||
originating_entity_id: '',
|
||||
type: 't',
|
||||
source_entity_ref: 'k:ns/other1',
|
||||
target_entity_ref: 'k:ns/me',
|
||||
},
|
||||
],
|
||||
},
|
||||
}));
|
||||
|
||||
orchestrator.process
|
||||
.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
completedEntity: entity,
|
||||
relations: [
|
||||
{
|
||||
type: 't',
|
||||
source: { kind: 'k', namespace: 'ns', name: 'other1' },
|
||||
target: { kind: 'k', namespace: 'ns', name: 'me' },
|
||||
},
|
||||
],
|
||||
errors: [],
|
||||
deferredEntities: [],
|
||||
state: {},
|
||||
refreshKeys: [],
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
ok: true,
|
||||
completedEntity: entity,
|
||||
// change just the target of the relationship to a new entity,
|
||||
// leaving the source and relation type the same.
|
||||
// see: https://github.com/backstage/backstage/issues/27325
|
||||
relations: [
|
||||
{
|
||||
type: 't',
|
||||
source: { kind: 'k', namespace: 'ns', name: 'other1' },
|
||||
target: { kind: 'k', namespace: 'ns', name: 'newtarget' },
|
||||
},
|
||||
],
|
||||
errors: [],
|
||||
deferredEntities: [],
|
||||
state: {},
|
||||
refreshKeys: [],
|
||||
});
|
||||
|
||||
await engine.start();
|
||||
await waitForExpect(() => {
|
||||
expect(stitcher.stitch).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
expect([...stitcher.stitch.mock.calls[0][0].entityRefs!]).toEqual(
|
||||
expect.arrayContaining(['k:ns/me', 'k:ns/other1']),
|
||||
);
|
||||
// As a result of switching the relationship for source other1 to
|
||||
// a new target entity, the other1 relationship source must be
|
||||
// restitched.
|
||||
expect([...stitcher.stitch.mock.calls[1][0].entityRefs!]).toEqual(
|
||||
expect.arrayContaining(['k:ns/me', 'k:ns/other1']),
|
||||
);
|
||||
await engine.stop();
|
||||
});
|
||||
|
||||
it('should not stitch sources entities when relations are the same', async () => {
|
||||
const engine = new DefaultCatalogProcessingEngine({
|
||||
config: new ConfigReader({}),
|
||||
|
||||
@@ -295,7 +295,7 @@ export class DefaultCatalogProcessingEngine {
|
||||
});
|
||||
oldRelationSources = new Map(
|
||||
previous.relations.map(r => [
|
||||
`${r.source_entity_ref}:${r.type}`,
|
||||
`${r.source_entity_ref}:${r.type}->${r.target_entity_ref}`,
|
||||
r.source_entity_ref,
|
||||
]),
|
||||
);
|
||||
@@ -304,7 +304,11 @@ export class DefaultCatalogProcessingEngine {
|
||||
const newRelationSources = new Map<string, string>(
|
||||
result.relations.map(relation => {
|
||||
const sourceEntityRef = stringifyEntityRef(relation.source);
|
||||
return [`${sourceEntityRef}:${relation.type}`, sourceEntityRef];
|
||||
const targetEntityRef = stringifyEntityRef(relation.target);
|
||||
return [
|
||||
`${sourceEntityRef}:${relation.type}->${targetEntityRef}`,
|
||||
sourceEntityRef,
|
||||
];
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user