Notebook Objects cannot be created with CouchDB enabled (#4425)

* added null check
* added test coverage for exception that caused bug

Co-authored-by: Andrew Henry <akhenry@gmail.com>
This commit is contained in:
Scott Bell 2021-11-15 21:55:04 +01:00 committed by GitHub
parent 53f5fdabe5
commit 8ef3869325
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 52 additions and 65 deletions

View File

@ -370,11 +370,13 @@ class CouchObjectProvider {
} }
return () => { return () => {
this.observers[keyString] = this.observers[keyString].filter(observer => observer !== callback); if (this.observers[keyString]) {
if (this.observers[keyString].length === 0) { this.observers[keyString] = this.observers[keyString].filter(observer => observer !== callback);
delete this.observers[keyString]; if (this.observers[keyString].length === 0) {
if (Object.keys(this.observers).length === 0 && this.isObservingObjectChanges()) { delete this.observers[keyString];
this.stopObservingObjectChanges(); if (Object.keys(this.observers).length === 0 && this.isObservingObjectChanges()) {
this.stopObservingObjectChanges();
}
} }
} }
}; };

View File

@ -41,13 +41,12 @@ describe('the plugin', () => {
namespace: '', namespace: '',
key: 'some-value' key: 'some-value'
}, },
type: 'mock-type', type: 'notebook',
modified: 0 modified: 0
}; };
options = { options = {
url: testPath, url: testPath,
filter: {}, filter: {}
disableObserve: true
}; };
openmct = createOpenMct(); openmct = createOpenMct();
@ -66,7 +65,7 @@ describe('the plugin', () => {
openmct.install(new CouchPlugin(options)); openmct.install(new CouchPlugin(options));
openmct.types.addType('mock-type', {creatable: true}); openmct.types.addType('notebook', {creatable: true});
openmct.on('start', done); openmct.on('start', done);
openmct.startHeadless(); openmct.startHeadless();
@ -98,33 +97,26 @@ describe('the plugin', () => {
fetch.and.returnValue(mockPromise); fetch.and.returnValue(mockPromise);
}); });
it('gets an object', () => { it('gets an object', async () => {
return openmct.objects.get(mockDomainObject.identifier).then((result) => { const result = await openmct.objects.get(mockDomainObject.identifier);
expect(result.identifier.key).toEqual(mockDomainObject.identifier.key); expect(result.identifier.key).toEqual(mockDomainObject.identifier.key);
});
}); });
it('creates an object', () => { it('creates an object', async () => {
return openmct.objects.save(mockDomainObject).then((result) => { const result = await openmct.objects.save(mockDomainObject);
expect(provider.create).toHaveBeenCalled(); expect(provider.create).toHaveBeenCalled();
expect(result).toBeTrue(); expect(result).toBeTrue();
});
}); });
it('updates an object', (done) => { it('updates an object', async () => {
return openmct.objects.save(mockDomainObject).then((result) => { const result = await openmct.objects.save(mockDomainObject);
expect(result).toBeTrue(); expect(result).toBeTrue();
expect(provider.create).toHaveBeenCalled(); expect(provider.create).toHaveBeenCalled();
//Set modified timestamp it detects a change and persists the updated model.
//Set modified timestamp it detects a change and persists the updated model. mockDomainObject.modified = Date.now();
mockDomainObject.modified = Date.now(); const updatedResult = await openmct.objects.save(mockDomainObject);
expect(updatedResult).toBeTrue();
return openmct.objects.save(mockDomainObject).then((updatedResult) => { expect(provider.update).toHaveBeenCalled();
expect(updatedResult).toBeTrue();
expect(provider.update).toHaveBeenCalled();
done();
});
});
}); });
}); });
describe('batches requests', () => { describe('batches requests', () => {
@ -140,7 +132,7 @@ describe('the plugin', () => {
}); });
fetch.and.returnValue(mockPromise); fetch.and.returnValue(mockPromise);
}); });
it('for multiple simultaneous gets', () => { it('for multiple simultaneous gets', async () => {
const objectIds = [ const objectIds = [
{ {
namespace: '', namespace: '',
@ -154,37 +146,32 @@ describe('the plugin', () => {
} }
]; ];
const getAllObjects = Promise.all( await Promise.all(
objectIds.map((identifier) => objectIds.map((identifier) =>
openmct.objects.get(identifier) openmct.objects.get(identifier)
)); )
);
return getAllObjects.then(() => { const requestUrl = fetch.calls.mostRecent().args[0];
const requestUrl = fetch.calls.mostRecent().args[0]; const requestMethod = fetch.calls.mostRecent().args[1].method;
const requestMethod = fetch.calls.mostRecent().args[1].method; expect(fetch).toHaveBeenCalledTimes(1);
expect(requestUrl.includes('_all_docs')).toBeTrue();
expect(fetch).toHaveBeenCalledTimes(1); expect(requestMethod).toEqual('POST');
expect(requestUrl.includes('_all_docs')).toBeTrue();
expect(requestMethod).toEqual('POST');
});
}); });
it('but not for single gets', () => { it('but not for single gets', async () => {
const objectId = { const objectId = {
namespace: '', namespace: '',
key: 'object-1' key: 'object-1'
}; };
const getObject = openmct.objects.get(objectId); await openmct.objects.get(objectId);
const requestUrl = fetch.calls.mostRecent().args[0];
const requestMethod = fetch.calls.mostRecent().args[1].method;
return getObject.then(() => { expect(fetch).toHaveBeenCalledTimes(1);
const requestUrl = fetch.calls.mostRecent().args[0]; expect(requestUrl.endsWith(`${objectId.key}`)).toBeTrue();
const requestMethod = fetch.calls.mostRecent().args[1].method; expect(requestMethod).toEqual('GET');
expect(fetch).toHaveBeenCalledTimes(1);
expect(requestUrl.endsWith(`${objectId.key}`)).toBeTrue();
expect(requestMethod).toEqual('GET');
});
}); });
}); });
describe('implements server-side search', () => { describe('implements server-side search', () => {
@ -207,22 +194,20 @@ describe('the plugin', () => {
fetch.and.returnValue(mockPromise); fetch.and.returnValue(mockPromise);
}); });
it("using Couch's 'find' endpoint", () => { it("using Couch's 'find' endpoint", async () => {
return Promise.all(openmct.objects.search('test')).then(() => { await Promise.all(openmct.objects.search('test'));
const requestUrl = fetch.calls.mostRecent().args[0]; const requestUrl = fetch.calls.mostRecent().args[0];
expect(fetch).toHaveBeenCalled(); expect(fetch).toHaveBeenCalled();
expect(requestUrl.endsWith('_find')).toBeTrue(); expect(requestUrl.endsWith('_find')).toBeTrue();
});
}); });
it("and supports search by object name", () => { it("and supports search by object name", async () => {
return Promise.all(openmct.objects.search('test')).then(() => { await Promise.all(openmct.objects.search('test'));
const requestPayload = JSON.parse(fetch.calls.mostRecent().args[1].body); const requestPayload = JSON.parse(fetch.calls.mostRecent().args[1].body);
expect(requestPayload).toBeDefined(); expect(requestPayload).toBeDefined();
expect(requestPayload.selector.model.name.$regex).toEqual('(?i)test'); expect(requestPayload.selector.model.name.$regex).toEqual('(?i)test');
});
}); });
}); });