Better handling of persistence errors (#5576)

* conflict errors in particular
This commit is contained in:
Andrew Henry 2022-07-29 14:29:34 -07:00 committed by GitHub
parent 60f20c64d5
commit 22924f18fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 9 deletions

View File

@ -230,6 +230,7 @@ export default class ObjectAPI {
return result;
}).catch((result) => {
console.warn(`Failed to retrieve ${keystring}:`, result);
this.openmct.notifications.error(`Failed to retrieve object ${keystring}`);
delete this.cache[keystring];
@ -387,7 +388,13 @@ export default class ObjectAPI {
}
}
return result;
return result.catch((error) => {
if (error instanceof this.errors.Conflict) {
this.openmct.notifications.error(`Conflict detected while saving ${this.makeKeyString(domainObject.identifier)}`);
}
throw error;
});
}
/**

View File

@ -7,6 +7,7 @@ describe("The Object API", () => {
let openmct = {};
let mockDomainObject;
const TEST_NAMESPACE = "test-namespace";
const TEST_KEY = "test-key";
const FIFTEEN_MINUTES = 15 * 60 * 1000;
beforeEach((done) => {
@ -22,7 +23,7 @@ describe("The Object API", () => {
mockDomainObject = {
identifier: {
namespace: TEST_NAMESPACE,
key: "test-key"
key: TEST_KEY
},
name: "test object",
type: "test-type"
@ -84,6 +85,31 @@ describe("The Object API", () => {
expect(mockProvider.create).not.toHaveBeenCalled();
expect(mockProvider.update).not.toHaveBeenCalled();
});
describe("Shows a notification on persistence conflict", () => {
beforeEach(() => {
openmct.notifications.error = jasmine.createSpy('error');
});
it("on create", () => {
mockProvider.create.and.returnValue(Promise.reject(new openmct.objects.errors.Conflict("Test Conflict error")));
return objectAPI.save(mockDomainObject).catch(() => {
expect(openmct.notifications.error).toHaveBeenCalledWith(`Conflict detected while saving ${TEST_NAMESPACE}:${TEST_KEY}`);
});
});
it("on update", () => {
mockProvider.update.and.returnValue(Promise.reject(new openmct.objects.errors.Conflict("Test Conflict error")));
mockDomainObject.persisted = Date.now() - FIFTEEN_MINUTES;
mockDomainObject.modified = Date.now();
return objectAPI.save(mockDomainObject).catch(() => {
expect(openmct.notifications.error).toHaveBeenCalledWith(`Conflict detected while saving ${TEST_NAMESPACE}:${TEST_KEY}`);
});
});
});
});
});
@ -138,21 +164,33 @@ describe("The Object API", () => {
});
it("Caches multiple requests for the same object", () => {
const promises = [];
expect(mockProvider.get.calls.count()).toBe(0);
objectAPI.get(mockDomainObject.identifier);
promises.push(objectAPI.get(mockDomainObject.identifier));
expect(mockProvider.get.calls.count()).toBe(1);
objectAPI.get(mockDomainObject.identifier);
promises.push(objectAPI.get(mockDomainObject.identifier));
expect(mockProvider.get.calls.count()).toBe(1);
return Promise.all(promises);
});
it("applies any applicable interceptors", () => {
expect(mockDomainObject.changed).toBeUndefined();
objectAPI.get(mockDomainObject.identifier).then((object) => {
return objectAPI.get(mockDomainObject.identifier).then((object) => {
expect(object.changed).toBeTrue();
expect(object.alsoChanged).toBeTrue();
expect(object.shouldNotBeChanged).toBeUndefined();
});
});
it("displays a notification in the event of an error", () => {
mockProvider.get.and.returnValue(Promise.reject());
return objectAPI.get(mockDomainObject.identifier).catch(() => {
expect(openmct.notifications.error).toHaveBeenCalledWith(`Failed to retrieve object ${TEST_NAMESPACE}:${TEST_KEY}`);
});
});
});
});
@ -168,7 +206,7 @@ describe("The Object API", () => {
testObject = {
identifier: {
namespace: TEST_NAMESPACE,
key: 'test-key'
key: TEST_KEY
},
name: 'test object',
type: 'notebook',
@ -195,6 +233,8 @@ describe("The Object API", () => {
"observeObjectChanges"
]);
mockProvider.get.and.returnValue(Promise.resolve(testObject));
mockProvider.create.and.returnValue(Promise.resolve(true));
mockProvider.update.and.returnValue(Promise.resolve(true));
mockProvider.observeObjectChanges.and.callFake(() => {
callbacks[0](updatedTestObject);
callbacks.splice(0, 1);

View File

@ -217,9 +217,11 @@ class CouchObjectProvider {
this.indicator.setIndicatorToState(DISCONNECTED);
console.error(error.message);
throw new Error(`CouchDB Error - No response"`);
}
} else {
console.error(error.message);
console.error(error.message);
throw error;
}
}
}
@ -653,7 +655,6 @@ class CouchObjectProvider {
let document = new CouchDocument(key, queued.model);
document.metadata.created = Date.now();
this.request(key, "PUT", document).then((response) => {
console.log('create check response', key);
this.#checkResponse(response, queued.intermediateResponse, key);
}).catch(error => {
queued.intermediateResponse.reject(error);