mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-21 17:12:43 +00:00
refactor: move api to monorepo
This commit is contained in:
466
packages/api/test/connector-client.spec.ts
Normal file
466
packages/api/test/connector-client.spec.ts
Normal file
@@ -0,0 +1,466 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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/>.
|
||||
*/
|
||||
import {asyncPool} from '@krlwlfrt/async-pool/lib/async-pool';
|
||||
import {
|
||||
isThing,
|
||||
SCBulkAddResponse,
|
||||
SCBulkAddRoute,
|
||||
SCBulkDoneResponse,
|
||||
SCBulkDoneRoute,
|
||||
SCBulkResponse,
|
||||
SCBulkRoute,
|
||||
SCMessage,
|
||||
SCThingOriginType,
|
||||
SCThingType,
|
||||
SCThingUpdateResponse,
|
||||
SCThingUpdateRoute,
|
||||
SCThingWithoutReferences,
|
||||
} from '@openstapps/core';
|
||||
import chai from 'chai';
|
||||
import {expect} from 'chai';
|
||||
import chaiAsPromised from 'chai-as-promised';
|
||||
import chaiSpies from 'chai-spies';
|
||||
import clone = require('rfdc');
|
||||
import {readdir, readFile} from 'fs';
|
||||
import {suite, test} from '@testdeck/mocha';
|
||||
import moment from 'moment';
|
||||
import {join, resolve} from 'path';
|
||||
import traverse from 'traverse';
|
||||
import {promisify} from 'util';
|
||||
import {ConnectorClient} from '../src/connector-client';
|
||||
import {EmptyBulkError, NamespaceNotDefinedError} from '../src/errors';
|
||||
import {HttpClient} from '../src/http-client';
|
||||
import {HttpClientRequest, HttpClientResponse} from '../src/http-client-interface';
|
||||
|
||||
chai.should();
|
||||
chai.use(chaiSpies);
|
||||
chai.use(chaiAsPromised);
|
||||
|
||||
const sandbox = chai.spy.sandbox();
|
||||
|
||||
const bulkAddRoute = new SCBulkAddRoute();
|
||||
const bulkDoneRoute = new SCBulkDoneRoute();
|
||||
const bulkRoute = new SCBulkRoute();
|
||||
const thingUpdateRoute = new SCThingUpdateRoute();
|
||||
|
||||
const readdirPromisified = promisify(readdir);
|
||||
const readFilePromisified = promisify(readFile);
|
||||
|
||||
const httpClient = new HttpClient();
|
||||
|
||||
/**
|
||||
* Check if something contains things
|
||||
*
|
||||
* @param thing Thing to check
|
||||
*/
|
||||
function doesContainThings<T extends SCThingWithoutReferences>(thing: T): boolean {
|
||||
/* tslint:disable-next-line:only-arrow-functions */
|
||||
return traverse(thing).reduce(function (sum, item) {
|
||||
if (this.isRoot) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return sum || (item === null) ? false : isThing(item);
|
||||
}, false);
|
||||
}
|
||||
|
||||
@suite()
|
||||
export class ConnectorClientSpec {
|
||||
async after() {
|
||||
sandbox.restore();
|
||||
}
|
||||
|
||||
@test
|
||||
async bulk() {
|
||||
sandbox.on(httpClient, 'request', async (): Promise<HttpClientResponse<SCBulkResponse>> => {
|
||||
return {
|
||||
body: {
|
||||
expiration: moment().add(1800, 'seconds').format(),
|
||||
source: 'foo',
|
||||
state: 'in progress',
|
||||
type: SCThingType.Message,
|
||||
uid: 'foo',
|
||||
},
|
||||
headers: {},
|
||||
statusCode: bulkRoute.statusCodeSuccess,
|
||||
};
|
||||
});
|
||||
|
||||
expect(httpClient.request).not.to.have.been.called();
|
||||
|
||||
const connectorClient = new ConnectorClient(httpClient, 'http://localhost');
|
||||
await connectorClient.bulk(SCThingType.Message, 'foo', 1800);
|
||||
|
||||
expect(httpClient.request).to.have.been.first.called.with({
|
||||
body: {
|
||||
expiration: moment().add(1800, 'seconds').format(),
|
||||
source: 'foo',
|
||||
type: SCThingType.Message,
|
||||
},
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
method: bulkRoute.method,
|
||||
url: new URL('http://localhost' + bulkRoute.getUrlPath()),
|
||||
});
|
||||
}
|
||||
|
||||
@test
|
||||
async bulkWithoutTimeout() {
|
||||
sandbox.on(httpClient, 'request', async (): Promise<HttpClientResponse<SCBulkResponse>> => {
|
||||
return {
|
||||
body: {
|
||||
expiration: moment().add(3600, 'seconds').format(),
|
||||
source: 'foo',
|
||||
state: 'in progress',
|
||||
type: SCThingType.Message,
|
||||
uid: 'foo',
|
||||
},
|
||||
headers: {},
|
||||
statusCode: bulkRoute.statusCodeSuccess,
|
||||
};
|
||||
});
|
||||
|
||||
expect(httpClient.request).not.to.have.been.called();
|
||||
|
||||
const connectorClient = new ConnectorClient(httpClient, 'http://localhost');
|
||||
await connectorClient.bulk(SCThingType.Message, 'foo');
|
||||
|
||||
expect(httpClient.request).to.have.been.first.called.with({
|
||||
body: {
|
||||
expiration: moment().add(3600, 'seconds').format(),
|
||||
source: 'foo',
|
||||
type: SCThingType.Message,
|
||||
},
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
method: bulkRoute.method,
|
||||
url: new URL('http://localhost' + bulkRoute.getUrlPath()),
|
||||
});
|
||||
}
|
||||
|
||||
@test
|
||||
async index() {
|
||||
const messages: SCMessage[] = [
|
||||
{
|
||||
audiences: [
|
||||
'employees',
|
||||
],
|
||||
categories: [
|
||||
'news'
|
||||
],
|
||||
messageBody: 'Lorem ipsum.',
|
||||
name: 'foo',
|
||||
origin: {
|
||||
indexed: 'foo',
|
||||
name: 'foo',
|
||||
type: SCThingOriginType.Remote,
|
||||
},
|
||||
type: SCThingType.Message,
|
||||
uid: 'foo',
|
||||
},
|
||||
{
|
||||
audiences: [
|
||||
'employees',
|
||||
],
|
||||
categories: [
|
||||
'news'
|
||||
],
|
||||
messageBody: 'Lorem ipsum.',
|
||||
name: 'foo',
|
||||
origin: {
|
||||
indexed: 'foo',
|
||||
name: 'foo',
|
||||
type: SCThingOriginType.Remote,
|
||||
},
|
||||
type: SCThingType.Message,
|
||||
uid: 'bar',
|
||||
},
|
||||
];
|
||||
|
||||
type responses = SCBulkResponse | SCBulkAddResponse | SCBulkDoneResponse;
|
||||
|
||||
sandbox.on(httpClient, 'request', async (request: HttpClientRequest)
|
||||
: Promise<HttpClientResponse<responses>> => {
|
||||
if (request.url.toString() === new URL('http://localhost' + bulkRoute.getUrlPath()).toString()) {
|
||||
return {
|
||||
body: {
|
||||
expiration: moment().add(3600, 'seconds').format(),
|
||||
source: 'copy',
|
||||
state: 'in progress',
|
||||
type: SCThingType.Message,
|
||||
uid: 'foo',
|
||||
},
|
||||
headers: {},
|
||||
statusCode: bulkRoute.statusCodeSuccess,
|
||||
};
|
||||
} else if (request.url.toString() === new URL('http://localhost' + bulkAddRoute.getUrlPath({
|
||||
UID: 'foo',
|
||||
})).toString()) {
|
||||
return {
|
||||
body: {},
|
||||
headers: {},
|
||||
statusCode: bulkAddRoute.statusCodeSuccess,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
body: {},
|
||||
headers: {},
|
||||
statusCode: bulkDoneRoute.statusCodeSuccess,
|
||||
};
|
||||
});
|
||||
|
||||
const connectorClient = new ConnectorClient(httpClient, 'http://localhost');
|
||||
await connectorClient.index(messages, 'copy');
|
||||
|
||||
expect(httpClient.request).to.have.been.first.called.with({
|
||||
body: {
|
||||
expiration: moment().add(3600, 'seconds').format(),
|
||||
source: 'copy',
|
||||
type: SCThingType.Message,
|
||||
},
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
method: bulkRoute.method,
|
||||
url: new URL('http://localhost' + bulkRoute.getUrlPath()),
|
||||
});
|
||||
}
|
||||
|
||||
@test
|
||||
async indexFails() {
|
||||
const connectorClient = new ConnectorClient(httpClient, 'http://localhost');
|
||||
return connectorClient.index([]).should.be.rejectedWith(EmptyBulkError);
|
||||
}
|
||||
|
||||
@test
|
||||
async indexWithoutSource() {
|
||||
const messages: SCMessage[] = [
|
||||
{
|
||||
audiences: [
|
||||
'employees',
|
||||
],
|
||||
categories: [
|
||||
'news'
|
||||
],
|
||||
messageBody: 'Lorem ipsum.',
|
||||
name: 'foo',
|
||||
origin: {
|
||||
indexed: 'foo',
|
||||
name: 'foo',
|
||||
type: SCThingOriginType.Remote,
|
||||
},
|
||||
type: SCThingType.Message,
|
||||
uid: 'foo',
|
||||
},
|
||||
{
|
||||
audiences: [
|
||||
'employees',
|
||||
],
|
||||
categories: [
|
||||
'news'
|
||||
],
|
||||
messageBody: 'Lorem ipsum.',
|
||||
name: 'foo',
|
||||
origin: {
|
||||
indexed: 'foo',
|
||||
name: 'foo',
|
||||
type: SCThingOriginType.Remote,
|
||||
},
|
||||
type: SCThingType.Message,
|
||||
uid: 'bar',
|
||||
},
|
||||
];
|
||||
|
||||
type responses = SCBulkResponse | SCBulkAddResponse | SCBulkDoneResponse;
|
||||
|
||||
sandbox.on(httpClient, 'request', async (request: HttpClientRequest)
|
||||
: Promise<HttpClientResponse<responses>> => {
|
||||
if (request.url.toString() === new URL('http://localhost' + bulkRoute.getUrlPath()).toString()) {
|
||||
return {
|
||||
body: {
|
||||
expiration: moment().add(3600, 'seconds').format(),
|
||||
source: 'stapps-api',
|
||||
state: 'in progress',
|
||||
type: SCThingType.Message,
|
||||
uid: 'foo',
|
||||
},
|
||||
headers: {},
|
||||
statusCode: bulkRoute.statusCodeSuccess,
|
||||
};
|
||||
} else if (request.url.toString() === new URL('http://localhost' + bulkAddRoute.getUrlPath({
|
||||
UID: 'foo',
|
||||
})).toString()) {
|
||||
return {
|
||||
body: {},
|
||||
headers: {},
|
||||
statusCode: bulkAddRoute.statusCodeSuccess,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
body: {},
|
||||
headers: {},
|
||||
statusCode: bulkDoneRoute.statusCodeSuccess,
|
||||
};
|
||||
});
|
||||
|
||||
const connectorClient = new ConnectorClient(httpClient, 'http://localhost');
|
||||
await connectorClient.index(messages);
|
||||
|
||||
expect(httpClient.request).to.have.been.first.called.with({
|
||||
body: {
|
||||
expiration: moment().add(3600, 'seconds').format(),
|
||||
source: 'stapps-api',
|
||||
type: SCThingType.Message,
|
||||
},
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
method: bulkRoute.method,
|
||||
url: new URL('http://localhost' + bulkRoute.getUrlPath()),
|
||||
});
|
||||
}
|
||||
|
||||
@test
|
||||
makeUuid() {
|
||||
const uuid = ConnectorClient.makeUUID('foo', 'b-tu');
|
||||
|
||||
expect(uuid).to.be.equal('abad271e-d9e9-5802-b7bc-96d8a647b451');
|
||||
expect(ConnectorClient.makeUUID('bar', 'b-tu')).not.to.be.equal(uuid);
|
||||
expect(ConnectorClient.makeUUID('foo', 'f-u')).not.to.be.equal(uuid);
|
||||
}
|
||||
|
||||
@test
|
||||
makeUuidFails() {
|
||||
expect(() => {
|
||||
ConnectorClient.makeUUID('foo', 'b-u');
|
||||
}).to.throw(NamespaceNotDefinedError);
|
||||
}
|
||||
|
||||
@test
|
||||
async removeReferences() {
|
||||
const pathToTestFiles = resolve(
|
||||
__dirname,
|
||||
'..',
|
||||
'node_modules',
|
||||
'@openstapps',
|
||||
'core',
|
||||
'test',
|
||||
'resources',
|
||||
'indexable'
|
||||
);
|
||||
|
||||
const testFiles = await readdirPromisified(pathToTestFiles);
|
||||
|
||||
const testInstances = await asyncPool(5, testFiles, async (testFile) => {
|
||||
const buffer = await readFilePromisified(join(pathToTestFiles, testFile));
|
||||
const content = JSON.parse(buffer.toString());
|
||||
|
||||
return content.instance;
|
||||
});
|
||||
|
||||
for (const testInstance of testInstances) {
|
||||
|
||||
const checkInstance = clone()(testInstance);
|
||||
const testInstanceWithoutReferences = ConnectorClient.removeReferences(testInstance);
|
||||
|
||||
expect(doesContainThings(testInstanceWithoutReferences)).to.be
|
||||
.equal(false, JSON.stringify(
|
||||
[testInstance, testInstanceWithoutReferences],
|
||||
null,
|
||||
2,
|
||||
));
|
||||
expect((testInstanceWithoutReferences as any).origin).to.be
|
||||
.equal(undefined, JSON.stringify(
|
||||
[testInstance, testInstanceWithoutReferences],
|
||||
null,
|
||||
2,
|
||||
));
|
||||
expect(testInstance).to.be.deep
|
||||
.equal(checkInstance,
|
||||
'Removing the references of a thing could have side effects because no deep copy is used');
|
||||
}
|
||||
}
|
||||
|
||||
@test
|
||||
async removeUndefinedProperties() {
|
||||
const objectWithUndefinedProperties = {value: 'foo',
|
||||
novalue: undefined,
|
||||
nested: {
|
||||
value: 'foo',
|
||||
novalue: undefined},
|
||||
};
|
||||
const objectWithoutUndefinedProperties = {value: 'foo',
|
||||
nested: {
|
||||
value: 'foo'},
|
||||
};
|
||||
ConnectorClient.removeUndefinedProperties(objectWithUndefinedProperties);
|
||||
|
||||
expect(objectWithUndefinedProperties).to.deep.equal(objectWithoutUndefinedProperties, JSON.stringify(
|
||||
[objectWithUndefinedProperties, objectWithoutUndefinedProperties],
|
||||
null,
|
||||
2,
|
||||
));
|
||||
}
|
||||
|
||||
@test
|
||||
async update() {
|
||||
const message: SCMessage = {
|
||||
audiences: [
|
||||
'employees',
|
||||
],
|
||||
categories: [
|
||||
'news'
|
||||
],
|
||||
messageBody: 'Lorem ipsum.',
|
||||
name: 'foo',
|
||||
origin: {
|
||||
indexed: 'foo',
|
||||
name: 'foo',
|
||||
type: SCThingOriginType.Remote,
|
||||
},
|
||||
type: SCThingType.Message,
|
||||
uid: 'foo',
|
||||
};
|
||||
|
||||
sandbox.on(httpClient, 'request', async (): Promise<HttpClientResponse<SCThingUpdateResponse>> => {
|
||||
return {
|
||||
body: {},
|
||||
headers: {},
|
||||
statusCode: thingUpdateRoute.statusCodeSuccess,
|
||||
};
|
||||
});
|
||||
|
||||
expect(httpClient.request).not.to.have.been.called();
|
||||
|
||||
const connectorClient = new ConnectorClient(httpClient, 'http://localhost');
|
||||
await connectorClient.update(message);
|
||||
|
||||
expect(httpClient.request).to.have.been.called.with({
|
||||
body: message,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
method: thingUpdateRoute.method,
|
||||
url: new URL('http://localhost' + thingUpdateRoute.getUrlPath({
|
||||
TYPE: SCThingType.Message,
|
||||
UID: 'foo',
|
||||
})),
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user