mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-20 16:42:56 +00:00
297 lines
8.6 KiB
TypeScript
297 lines
8.6 KiB
TypeScript
/*
|
|
* Copyright (C) 2018-2021 StApps
|
|
* This program is free software: you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
* Software Foundation, version 3.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
/* eslint-disable @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-explicit-any, unicorn/no-thenable */
|
|
import {TestBed} from '@angular/core/testing';
|
|
import {Client} from '@openstapps/api/lib/client';
|
|
import {
|
|
SCDish,
|
|
SCMessage,
|
|
SCMultiSearchRequest,
|
|
SCSaveableThing,
|
|
SCSearchQuery,
|
|
SCSearchResponse,
|
|
SCSearchValueFilter,
|
|
SCThingOriginType,
|
|
SCThingType,
|
|
} from '@openstapps/core';
|
|
import {sampleThingsMap} from '../../_helpers/data/sample-things';
|
|
import {StorageProvider} from '../storage/storage.provider';
|
|
import {DataModule} from './data.module';
|
|
import {DataProvider, DataScope} from './data.provider';
|
|
import {StAppsWebHttpClient} from './stapps-web-http-client.provider';
|
|
|
|
describe('DataProvider', () => {
|
|
let dataProvider: DataProvider;
|
|
let storageProvider: StorageProvider;
|
|
const sampleThing: SCMessage = sampleThingsMap.message[0] as SCMessage;
|
|
const sampleResponse: SCSearchResponse = {
|
|
data: sampleThingsMap.dish as SCDish[],
|
|
facets: [
|
|
{
|
|
buckets: [],
|
|
field: 'foo',
|
|
},
|
|
],
|
|
pagination: {
|
|
count: 0,
|
|
offset: 0,
|
|
total: 0,
|
|
},
|
|
stats: {
|
|
time: 123,
|
|
},
|
|
};
|
|
const sampleFilter: SCSearchValueFilter = {
|
|
arguments: {
|
|
field: 'type',
|
|
value: 'dish',
|
|
},
|
|
type: 'value',
|
|
};
|
|
const sampleQuery: SCSearchQuery = {
|
|
filter: sampleFilter,
|
|
};
|
|
|
|
const sampleSavable: SCSaveableThing = {
|
|
data: sampleThing,
|
|
name: sampleThing.name,
|
|
origin: {
|
|
created: new Date().toISOString(),
|
|
type: SCThingOriginType.User,
|
|
},
|
|
type: SCThingType.Message,
|
|
uid: sampleThing.uid,
|
|
};
|
|
|
|
const fakeStorage = new Map([
|
|
['foo', 'Bar'],
|
|
['bar', {foo: 'BarFoo'} as any],
|
|
]);
|
|
|
|
beforeEach(async () => {
|
|
TestBed.configureTestingModule({
|
|
imports: [DataModule],
|
|
providers: [DataProvider, StAppsWebHttpClient],
|
|
});
|
|
storageProvider = TestBed.inject(StorageProvider);
|
|
dataProvider = TestBed.inject(DataProvider);
|
|
});
|
|
|
|
it('should generate data key', async () => {
|
|
dataProvider.storagePrefix = 'foo.data';
|
|
|
|
expect(dataProvider.getDataKey('123')).toBe('foo.data.123');
|
|
});
|
|
|
|
it('should provide backend data items using search query', async () => {
|
|
spyOn(Client.prototype as any, 'search').and.callFake(() => {
|
|
return {
|
|
then: (callback: any) => {
|
|
return callback(sampleResponse);
|
|
},
|
|
};
|
|
});
|
|
const response = await dataProvider.search(sampleQuery);
|
|
|
|
expect(response).toEqual(sampleResponse);
|
|
});
|
|
|
|
it('should provide backend data items using multi search query', async () => {
|
|
spyOn(Client.prototype as any, 'multiSearch').and.callFake(() => ({
|
|
then: (callback: any) => {
|
|
return callback({
|
|
a: sampleResponse,
|
|
});
|
|
},
|
|
}));
|
|
const response = await dataProvider.multiSearch({a: sampleQuery});
|
|
|
|
expect(response).toEqual({a: sampleResponse});
|
|
});
|
|
|
|
it('should partition search requests correctly', async () => {
|
|
const request = {
|
|
a: 'a',
|
|
b: 'b',
|
|
c: 'c',
|
|
d: 'd',
|
|
e: 'e',
|
|
} as SCMultiSearchRequest; // and response...
|
|
const requestCheck = Object.assign({}, request);
|
|
const responseShould = {
|
|
a: 'A',
|
|
b: 'B',
|
|
c: 'C',
|
|
d: 'D',
|
|
e: 'E',
|
|
};
|
|
|
|
dataProvider.backendQueriesLimit = 2;
|
|
spyOn(Client.prototype as any, 'multiSearch').and.callFake(
|
|
(request_: SCMultiSearchRequest) => ({
|
|
then: (callback: any) => {
|
|
let i = 0;
|
|
for (const key in request_) {
|
|
if (request_.hasOwnProperty(key)) {
|
|
i++;
|
|
|
|
expect(requestCheck[key]).not.toBeNull();
|
|
expect(requestCheck[key]).toEqual(request_[key]);
|
|
|
|
// @ts-expect-error is not null
|
|
// eslint-disable-next-line unicorn/no-null
|
|
requestCheck[key] = null;
|
|
// @ts-expect-error is a string for test purposes
|
|
request_[key] = request_[key].toUpperCase();
|
|
}
|
|
}
|
|
expect(i).toBeLessThanOrEqual(dataProvider.backendQueriesLimit);
|
|
|
|
return callback(request_);
|
|
},
|
|
}),
|
|
);
|
|
const response = await dataProvider.multiSearch(request);
|
|
|
|
// @ts-expect-error same type
|
|
expect(response).toEqual(responseShould);
|
|
});
|
|
|
|
it('should put an data item into the local database (storage)', async () => {
|
|
let providedThing: SCSaveableThing;
|
|
spyOn(storageProvider, 'put' as any).and.callFake(
|
|
(_id: any, thing: any) => {
|
|
providedThing = thing;
|
|
providedThing.origin.created = sampleSavable.origin.created;
|
|
},
|
|
);
|
|
|
|
expect(storageProvider.put).not.toHaveBeenCalled();
|
|
expect(providedThing!).not.toBeDefined();
|
|
|
|
await dataProvider.put(sampleThing);
|
|
|
|
expect(providedThing!).toBeDefined();
|
|
expect(providedThing!).toEqual(sampleSavable);
|
|
});
|
|
|
|
it('should correctly set and get single data item from the local database (storage)', async () => {
|
|
spyOn(storageProvider, 'get').and.returnValue(
|
|
(async () => sampleSavable)(),
|
|
);
|
|
|
|
expect(storageProvider.get).not.toHaveBeenCalled();
|
|
|
|
const providedThing = await dataProvider.get(
|
|
sampleThing.uid,
|
|
DataScope.Local,
|
|
);
|
|
|
|
expect(storageProvider.get).toHaveBeenCalledWith(
|
|
dataProvider.getDataKey(sampleThing.uid),
|
|
);
|
|
expect(providedThing).toEqual(sampleSavable);
|
|
});
|
|
|
|
it('should provide all data items from the local database (storage)', async () => {
|
|
const fakeStorage = new Map([
|
|
['foo', 'Bar'],
|
|
['bar', {foo: 'BarFoo'} as any],
|
|
]);
|
|
spyOn(storageProvider, 'search').and.callFake(async () => {
|
|
return fakeStorage;
|
|
});
|
|
|
|
const result = await dataProvider.getAll();
|
|
|
|
expect([...result.keys()].sort()).toEqual([...fakeStorage.keys()].sort());
|
|
expect([...result.values()].sort()).toEqual(
|
|
[...fakeStorage.values()].sort(),
|
|
);
|
|
});
|
|
|
|
it('should provide single data from the backend', async () => {
|
|
spyOn(Client.prototype, 'getThing' as any).and.callFake(() => {
|
|
return {
|
|
then: (callback: any) => {
|
|
return callback(sampleThing);
|
|
},
|
|
};
|
|
});
|
|
|
|
expect(Client.prototype.getThing).not.toHaveBeenCalled();
|
|
|
|
const providedThing = await dataProvider.get(
|
|
sampleThing.uid,
|
|
DataScope.Remote,
|
|
);
|
|
|
|
expect(Client.prototype.getThing).toHaveBeenCalledWith(sampleThing.uid);
|
|
expect(providedThing).toBe(sampleThing);
|
|
});
|
|
|
|
it('should get an item from both local and remote database', async () => {
|
|
spyOn(Client.prototype, 'getThing' as any).and.callFake(() => {
|
|
return {
|
|
then: (callback: any) => {
|
|
return callback(sampleThing);
|
|
},
|
|
};
|
|
});
|
|
spyOn(storageProvider, 'get' as any).and.callFake(() => {
|
|
return {
|
|
then: (callback: any) => {
|
|
return callback(sampleSavable);
|
|
},
|
|
};
|
|
});
|
|
const result = await dataProvider.get(sampleThing.uid);
|
|
|
|
expect(result.get(DataScope.Local)).toEqual(sampleSavable);
|
|
expect(result.get(DataScope.Remote)).toEqual(sampleThing);
|
|
});
|
|
|
|
it('should properly delete a data item from the local database (storage)', async () => {
|
|
spyOn(storageProvider, 'delete');
|
|
|
|
await dataProvider.delete(sampleThing.uid);
|
|
|
|
expect(storageProvider.delete).toHaveBeenCalledWith(
|
|
dataProvider.getDataKey(sampleThing.uid),
|
|
);
|
|
});
|
|
|
|
it('should properly delete all the data items from the local database (storage)', async () => {
|
|
spyOn(storageProvider, 'delete');
|
|
spyOn(storageProvider, 'search').and.callFake(async () => {
|
|
return fakeStorage;
|
|
});
|
|
await dataProvider.deleteAll();
|
|
|
|
expect(storageProvider.delete).toHaveBeenCalledWith('foo', 'bar');
|
|
});
|
|
|
|
it('should properly check if a data item has already been saved', async () => {
|
|
spyOn(storageProvider, 'has').and.callFake(async storageKey => {
|
|
return (async () => {
|
|
return dataProvider.getDataKey(sampleThing.uid) === storageKey;
|
|
})();
|
|
});
|
|
|
|
expect(await dataProvider.isSaved('some-uuid')).toBeFalsy();
|
|
expect(await dataProvider.isSaved(sampleThing.uid)).toBeTruthy();
|
|
});
|
|
});
|