Ironed out issues with creation endpoints and ID mappings.

editsong
Sander Vocke 5 years ago
parent 44ebc7b15d
commit 299342824c
  1. 2
      .vscode/launch.json
  2. 92
      server/test/integration/flows/ResourceFlow.ts
  3. 2
      server/test/reference_model/DBReferenceModel.ts

@ -10,7 +10,7 @@
"name": "Jasmine Tests with SQLite",
"env": {
"MUDBASE_DB_CONFIG": "{\"client\": \"sqlite3\", \"connection\": \":memory:\"}",
"TEST_RANDOM_SEED": "0.15844"
"TEST_RANDOM_SEED": "0.61658"
},
"program": "${workspaceFolder}/server/node_modules/jasmine-ts/lib/index",
"args": [

@ -113,7 +113,8 @@ function transformActionIDs(action: DBAction, mappings: IDMappings, rng: any) {
for (const [_, value] of Object.entries(mapping)) {
highest = Math.max(value, highest);
}
return highest + 1 + Math.floor(rng() * 100);
let r = highest + 1 + Math.floor(rng() * 100);
return r;
}
switch (r.type) {
@ -124,6 +125,25 @@ function transformActionIDs(action: DBAction, mappings: IDMappings, rng: any) {
track.albumId = track.albumId ? doMap(track.albumId, mappings.albums) : null;
break;
}
case DBActionType.CreateArtist: {
let artist = r.payload as ArtistWithRefsWithId;
artist.tagIds.forEach((id: number) => doMap(id, mappings.tags));
artist.albumIds.forEach((id: number) => doMap(id, mappings.albums));
artist.trackIds.forEach((id: number) => doMap(id, mappings.tracks));
break;
}
case DBActionType.CreateAlbum: {
let album = r.payload as AlbumWithRefsWithId;
album.tagIds.forEach((id: number) => doMap(id, mappings.tags));
album.artistIds.forEach((id: number) => doMap(id, mappings.artists));
album.trackIds.forEach((id: number) => doMap(id, mappings.tracks));
break;
}
case DBActionType.CreateTag: {
let tag = r.payload as TagWithRefsWithId;
tag.parentId = tag.parentId ? doMap(tag.parentId, mappings.tags) : null;
break;
}
case DBActionType.DeleteTrack: {
r.payload = mappings.tracks[r.payload];
break;
@ -156,6 +176,12 @@ describe('Randomized model-based DB back-end tests', () => {
let refState: ReferenceDatabase | undefined = undefined;
let realState: ReferenceDatabase | undefined = undefined;
// As we perform operations, the real DB and reference model may assign
// different new IDs to new objects. We need to maintain mappings in order
// to keep the operations consistent (e.g. when we make references to)
// existing objects along the way.
let idMappingsRefToReal: IDMappings | undefined = undefined;
try {
// Create a reference DB.
let refDB: ReferenceDatabase = _.cloneDeep(sampleDB);
@ -166,19 +192,14 @@ describe('Randomized model-based DB back-end tests', () => {
await helpers.login(req, "someone@email.com", "password1A!", 200);
// Import the starting DB.
let importResponse: DBImportResponse = (await helpers.importDB(req, refDB[1])).body;
// As we perform operations, the real DB and reference model may assign
// different new IDs to new objects. We need to maintain mappings in order
// to keep the operations consistent (e.g. when we make references to)
// existing objects along the way.
let idMappingsRefToReal: IDMappings = importResponse;
idMappingsRefToReal = importResponse;
// Check that we are starting from an equal situation
refState = normalizeDB(refDB);
realState = normalizeDB({
refState = refDB;
realState = {
[1]: (await helpers.getExport(req)).body,
});
expect(realState).to.deep.equal(refState);
};
expect(normalizeDB(realState)).to.deep.equal(normalizeDB(refState));
// Create a random number generator to use throughout the test.
let rng = seedrandom(seed);
@ -235,7 +256,7 @@ describe('Randomized model-based DB back-end tests', () => {
},
createTagParams: {
linkParent: new Map<boolean | 'nonexistent', number>([[false, 0.45], [true, 0.45], ['nonexistent', 0.1]]),
},
deleteTrackParams: {
validTrack: new Map([[false, 0.2], [true, 0.8]])
@ -262,10 +283,16 @@ describe('Randomized model-based DB back-end tests', () => {
let { response: realResponse, status: realStatus } = await applyRealDBAction(realAction, req);
// If this was an object creation action, we need to update the mappings.
if (refAction.type === DBActionType.CreateTrack) {
let refId = refResponse.id;
let realId = realResponse.id;
idMappingsRefToReal.tracks[refId] = realId;
if (refStatus === 200 && realStatus === 200) {
if (refAction.type === DBActionType.CreateTrack) {
idMappingsRefToReal.tracks[refResponse.id] = realResponse.id;
} else if (refAction.type === DBActionType.CreateAlbum) {
idMappingsRefToReal.albums[refResponse.id] = realResponse.id;
} else if (refAction.type === DBActionType.CreateArtist) {
idMappingsRefToReal.artists[refResponse.id] = realResponse.id;
} else if (refAction.type === DBActionType.CreateTag) {
idMappingsRefToReal.tags[refResponse.id] = realResponse.id;
}
}
// Compare the response and status.
@ -273,33 +300,42 @@ describe('Randomized model-based DB back-end tests', () => {
expect(normalizeResponse(realResponse)).to.deep.equal(normalizeResponse(refResponse));
// Compare the database state after the action.
refState = normalizeDB(refDB);
realState = normalizeDB({
let newRefState = refDB;
let newRealState = {
[1]: (await helpers.getExport(req)).body,
});
expect(realState).to.deep.equal(refState);
};
expect(normalizeDB(newRealState)).to.deep.equal(normalizeDB(newRefState));
realState = newRealState;
refState = newRefState;
}
} catch (e) {
// When catching a comparison error, add and dump various states to files for debugging.
e.actionTrace = actionTrace;
e.startingDB = normalizeDB(sampleDB);
e.lastRefDB = refState;
e.lastRealDB = realState;
e.testSeed = seed;
e.idMappingsRefToReal = idMappingsRefToReal;
if (e.actual && e.expected) {
e.realDBDump = tmp.tmpNameSync();
e.refDBDump = tmp.tmpNameSync();
e.actionTraceDump = tmp.tmpNameSync();
e.startingDBDump = tmp.tmpNameSync();
fs.writeFileSync(e.realDBDump, stringify(realState, { space: ' ' }));
fs.writeFileSync(e.refDBDump, stringify(refState, { space: ' ' }));
let basename = tmp.tmpNameSync();
e.actionTraceDump = basename + "_actiontrace";
e.startingDBDump = basename + "_startingDB";
e.lastRefDBDump = basename + "_lastRefDB";
e.lastRealDBDump = basename + "_lastRealDB";
e.idMappingsRefToRealDump = basename + "_idMappings";
fs.writeFileSync(e.actionTraceDump, stringify(e.actionTrace, { space: ' ' }));
fs.writeFileSync(e.startingDBDump, stringify(e.startingDB, { space: ' ' }));
fs.writeFileSync(e.lastRefDBDump, stringify(e.lastRefDB, { space: ' ' }));
fs.writeFileSync(e.lastRealDBDump, stringify(e.lastRealDB, { space: ' ' }));
fs.writeFileSync(e.idMappingsRefToRealDump, stringify(e.idMappingsRefToReal, { space: ' ' }));
console.log(
"A comparison error occurred. Wrote compared values to temporary files for debugging:\n"
+ ` actual: ${e.realDBDump}\n`
+ ` expected: ${e.refDBDump}\n`
+ ` DB action trace: ${e.actionTraceDump}\n`
+ ` Starting DB: ${e.startingDBDump}\n`
+ ` Reference DB before last action: ${e.lastRefDBDump}\n`
+ ` Real DB before last action: ${e.lastRealDBDump}\n`
+ ` ID Mappings from ref to real DB: ${e.idMappingsRefToRealDump}\n`
+ ` TEST_RANDOM_SEED: ${seed}`
);
}

@ -135,7 +135,7 @@ export function createTag(userId: number, tag: PostTagRequest, db: ReferenceData
userId,
tag,
'tags',
[],
[{ field: 'parentId', otherObjectType: 'tags' }],
[],
db
);

Loading…
Cancel
Save