fix: tests

This commit is contained in:
2023-05-31 15:05:41 +02:00
parent 0d60b8bfad
commit 68400f2480
29 changed files with 647 additions and 272 deletions

View File

@@ -24,10 +24,11 @@ import {expect} from 'chai';
import {bulk, DEFAULT_TEST_TIMEOUT} from '../common.js';
import {testApp} from '../tests-setup.js';
import {readFile} from 'fs/promises';
import {v4} from 'uuid';
const book = JSON.parse(
await readFile('node_modules/@openstapps/core/test/resources/indexable/Book.1.json', 'utf8'),
);
await readFile('node_modules/@openstapps/core/test/resources/indexable/Book.2.json', 'utf8'),
).instance;
describe('Bulk routes', async function () {
// increase timeout for the suite
@@ -60,7 +61,7 @@ describe('Bulk routes', async function () {
it('should return (throw) error if a bulk with the provided UID cannot be found when adding to a bulk', async function () {
await testApp.post(bulkRoute.urlPath).set('Content-Type', 'application/json').send(request);
const bulkAddRouteUrlPath = bulkAddRoute.urlPath.toLocaleLowerCase().replace(':uid', 'a-wrong-uid');
const bulkAddRouteUrlPath = bulkAddRoute.urlPath.toLocaleLowerCase().replace(':uid', v4());
const {status} = await testApp
.post(bulkAddRouteUrlPath)
@@ -75,10 +76,10 @@ describe('Bulk routes', async function () {
.post(bulkRoute.urlPath)
.set('Content-Type', 'application/json')
.send(request);
const bulkAddRouteurlPath = bulkAddRoute.urlPath.toLocaleLowerCase().replace(':uid', response.body.uid);
const bulkAddRouteUrlPath = bulkAddRoute.urlPath.toLocaleLowerCase().replace(':uid', response.body.uid);
const {status, body} = await testApp
.post(bulkAddRouteurlPath)
.post(bulkAddRouteUrlPath)
.set('Content-Type', 'application/json')
.send(book);
@@ -88,10 +89,10 @@ describe('Bulk routes', async function () {
it('should return (throw) error if a bulk with the provided UID cannot be found when closing a bulk (done)', async function () {
await testApp.post(bulkRoute.urlPath).set('Content-Type', 'application/json').send(request);
const bulkDoneRouteurlPath = bulkDoneRoute.urlPath.toLocaleLowerCase().replace(':uid', 'a-wrong-uid');
const bulkDoneRouteUrlPath = bulkDoneRoute.urlPath.toLocaleLowerCase().replace(':uid', 'a-wrong-uid');
const {status} = await testApp
.post(bulkDoneRouteurlPath)
.post(bulkDoneRouteUrlPath)
.set('Content-Type', 'application/json')
.send({});

View File

@@ -24,7 +24,7 @@ use(chaiAsPromised);
const book = JSON.parse(
await readFile('node_modules/@openstapps/core/test/resources/indexable/Book.1.json', 'utf8'),
);
).instance;
describe('Thing update route', async function () {
// increase timeout for the suite

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {AggregateName, AggregationsMultiTermsBucket} from '@elastic/elasticsearch/lib/api/types';
import {AggregateName, AggregationsMultiTermsBucket} from '@elastic/elasticsearch/lib/api/types.js';
import {SCFacet, SCThingType} from '@openstapps/core';
import {expect} from 'chai';
import {parseAggregations} from '../../../src/storage/elasticsearch/aggregations.js';

View File

@@ -15,13 +15,8 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Client, Diagnostic} from '@elastic/elasticsearch';
import Indices from '@elastic/elasticsearch/lib/api/api/indices';
import {
CreateResponse,
SearchHit,
SearchResponse,
SortCombinations,
} from '@elastic/elasticsearch/lib/api/types';
import Indices from '@elastic/elasticsearch/lib/api/api/indices.js';
import {CreateResponse, SearchHit, SearchResponse} from '@elastic/elasticsearch/lib/api/types.js';
import {
SCBook,
SCBulkResponse,
@@ -36,27 +31,25 @@ import {expect, use} from 'chai';
import chaiAsPromised from 'chai-as-promised';
import {beforeEach} from 'mocha';
import mockedEnv from 'mocked-env';
import {
ACTIVE_INDICES_ALIAS,
INACTIVE_INDICES_ALIAS,
parseIndexName,
} from '../../../src/storage/elasticsearch/util.js';
import * as queryModule from '../../../src/storage/elasticsearch/query/query.js';
import * as sortModule from '../../../src/storage/elasticsearch/query/sort.js';
import sinon, {SinonStub} from 'sinon';
import {getIndexUID, getThingIndexName, INDEX_UID_LENGTH} from '../../../src/storage/elasticsearch/util.js';
import * as utilModule from '../../../src/storage/elasticsearch/util.js';
import {removeInvalidAliasChars} from '../../../src/storage/elasticsearch/util/alias.js';
import {configFile} from '../../../src/common.js';
import {MailQueue} from '../../../src/notification/mail-queue.js';
import {aggregations} from '../../../src/storage/elasticsearch/templating.js';
import {Elasticsearch} from '../../../src/storage/elasticsearch/elasticsearch.js';
import * as Monitoring from '../../../src/storage/elasticsearch/monitoring.js';
import * as templating from '../../../src/storage/elasticsearch/templating.js';
import {bulk, DEFAULT_TEST_TIMEOUT, getTransport, getIndex} from '../../common.js';
import fs from 'fs';
import {backendConfig} from '../../../src/config.js';
import {readFile} from 'fs/promises';
import {
ACTIVE_INDICES_ALIAS,
getIndexUID,
getThingIndexName,
INACTIVE_INDICES_ALIAS,
INDEX_UID_LENGTH,
parseIndexName,
} from '../../../src/storage/elasticsearch/util/index.js';
import cron from 'node-cron';
import {query} from './query.js';
use(chaiAsPromised);
@@ -115,7 +108,7 @@ describe('Elasticsearch', function () {
describe('getAliasMap', function () {
it('should fail after retries', async function () {
const es = new Elasticsearch(configFile);
const es = new Elasticsearch(backendConfig);
sandbox.stub(es.client.indices, 'getAlias').throws();
await expect(es.init({maxRetries: 1, retryInterval: 10})).to.be.rejected;
});
@@ -283,17 +276,24 @@ describe('Elasticsearch', function () {
...backendConfig.internal,
monitoring: {
actions: [],
watchers: [],
watchers: [
{
triggers: [{executionTime: 'daily', name: 'trigger'}],
name: 'watcher',
actions: [],
query: {},
conditions: [],
},
],
},
},
};
const monitoringSetUpStub = sandbox.stub(Monitoring, 'setUp');
const cronSetupStub = sandbox.stub(cron, 'schedule');
const es = new Elasticsearch(config, new MailQueue(getTransport(false) as unknown as SMTP));
es.init();
expect(monitoringSetUpStub.called).to.be.true;
expect(cronSetupStub.called).to.be.true;
});
});
@@ -308,14 +308,14 @@ describe('Elasticsearch', function () {
beforeEach(function () {
sandbox
.stub(Indices.prototype, 'getAlias')
.stub(Indices.default.prototype, 'getAlias')
.resolves({[oldIndex]: {aliases: {[SCThingType.Book]: {}}}} as any);
sandbox.stub(Indices.prototype, 'putTemplate').resolves({} as any);
createStub = sandbox.stub(Indices.prototype, 'create').resolves({} as any);
deleteStub = sandbox.stub(Indices.prototype, 'delete').resolves({} as any);
refreshStub = sandbox.stub(Indices.prototype, 'refresh').resolves({} as any);
updateAliasesStub = sandbox.stub(Indices.prototype, 'updateAliases').resolves({} as any);
es = new Elasticsearch(configFile);
sandbox.stub(Indices.default.prototype, 'putTemplate').resolves({} as any);
createStub = sandbox.stub(Indices.default.prototype, 'create').resolves({} as any);
deleteStub = sandbox.stub(Indices.default.prototype, 'delete').resolves({} as any);
refreshStub = sandbox.stub(Indices.default.prototype, 'refresh').resolves({} as any);
updateAliasesStub = sandbox.stub(Indices.default.prototype, 'updateAliases').resolves({} as any);
es = new Elasticsearch(backendConfig);
});
afterEach(function () {
@@ -329,21 +329,18 @@ describe('Elasticsearch', function () {
it('should reject (throw an error) if the index name is not valid', async function () {
sandbox.createStubInstance(Client, {});
sandbox.stub(utilModule, 'getThingIndexName').returns(`invalid_${getIndex}`);
const invalidBulk = {...bulk, source: '%#$^'};
await es.init();
return expect(es.bulkCreated(bulk)).to.be.rejectedWith('Index');
return expect(es.bulkCreated(invalidBulk)).to.be.rejectedWith('Index');
});
it('should create a new index', async function () {
const index = getIndex();
sandbox.stub(utilModule, 'getThingIndexName').returns(index);
const putTemplateStub = sandbox.stub(templating, 'putTemplate');
sandbox.stub(es, 'prepareBulkWrite').resolves(index);
await es.init();
await es.bulkCreated(bulk);
expect(putTemplateStub.called).to.be.true;
expect(createStub.calledWith({index, aliases: {[INACTIVE_INDICES_ALIAS]: {}}})).to.be.true;
});
});
@@ -354,7 +351,7 @@ describe('Elasticsearch', function () {
sandbox.restore();
});
it('should cleanup index in case of the expired bulk for bulk whose index is not in use', async function () {
sandbox.stub(utilModule, 'getThingIndexName').returns(getIndex());
sandbox.stub(es, 'prepareBulkWrite').resolves(getIndex());
await es.init();
await es.bulkExpired({...bulk, state: 'in progress'});
@@ -363,7 +360,7 @@ describe('Elasticsearch', function () {
});
it('should not cleanup index in case of the expired bulk for bulk whose index is in use', async function () {
sandbox.stub(utilModule, 'getThingIndexName').returns(getIndex());
sandbox.stub(es, 'prepareBulkWrite').resolves(getIndex());
await es.init();
await es.bulkExpired({...bulk, state: 'done'});
@@ -378,11 +375,11 @@ describe('Elasticsearch', function () {
});
it('should reject if the index name is not valid', async function () {
sandbox.stub(utilModule, 'getThingIndexName').returns(`invalid_${getIndex()}`);
const invalidBulk = {...bulk, source: '%#$^'};
sandbox.createStubInstance(Client, {});
await es.init();
return expect(es.bulkUpdated(bulk)).to.be.rejectedWith('Index');
return expect(es.bulkUpdated(invalidBulk)).to.be.rejectedWith('Index');
});
it("should refuse to finalize bulk if index doesn't exist", async function () {
@@ -411,10 +408,8 @@ describe('Elasticsearch', function () {
remove_index: {index: oldIndex},
},
];
sandbox.stub(utilModule, 'getThingIndexName').returns(index);
sandbox.stub(templating, 'putTemplate');
sandbox.stub(es, 'prepareBulkWrite').resolves(index);
await es.init();
await es.bulkUpdated(bulk);
expect(refreshStub.calledWith({index, allow_no_indices: false})).to.be.true;
@@ -467,7 +462,7 @@ describe('Elasticsearch', function () {
});
beforeEach(function () {
sandbox.stub(Indices.prototype, 'getAlias').resolves({} as any);
sandbox.stub(Indices.default.prototype, 'getAlias').resolves({} as any);
});
afterEach(function () {
@@ -483,7 +478,7 @@ describe('Elasticsearch', function () {
_source: message as SCMessage,
};
sandbox.stub(es.client, 'search').resolves(searchResponse<SCMessage>(object));
sandbox.stub(utilModule, 'getThingIndexName').returns(index);
sandbox.stub(es, 'prepareBulkWrite').resolves(index);
await es.init();
return expect(es.post(object._source!, bulk)).to.be.rejectedWith('UID conflict');
@@ -609,7 +604,7 @@ describe('Elasticsearch', function () {
};
let searchStub: sinon.SinonStub;
before(function () {
es = new Elasticsearch(configFile);
es = new Elasticsearch(backendConfig);
});
beforeEach(function () {
searchStub = sandbox.stub(es.client, 'search').resolves(fakeSearchResponse);
@@ -680,18 +675,14 @@ describe('Elasticsearch', function () {
},
},
};
const fakeResponse = {foo: 'bar'} as SortCombinations;
const fakeBuildSortResponse = [fakeResponse];
// @ts-expect-error not assignable
sandbox.stub(queryModule, 'buildQuery').returns(fakeResponse);
sandbox.stub(sortModule, 'buildSort').returns(fakeBuildSortResponse);
await es.search(parameters);
sandbox.assert.calledWithMatch(searchStub, {
expect(searchStub.firstCall.firstArg).to.be.deep.equal({
aggs: aggregations,
query: fakeResponse,
sort: fakeBuildSortResponse,
query,
allow_no_indices: true,
sort: [{'name.sort': 'desc'}],
from: parameters.from,
index: ACTIVE_INDICES_ALIAS,
size: parameters.size,

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Client} from '@elastic/elasticsearch';
import {SearchResponse} from '@elastic/elasticsearch/lib/api/types';
import {SearchResponse} from '@elastic/elasticsearch/lib/api/types.js';
import {
SCMonitoringConfiguration,
SCMonitoringLogAction,

View File

@@ -31,7 +31,7 @@ import {buildQuery} from '../../../src/storage/elasticsearch/query/query.js';
import {buildSort} from '../../../src/storage/elasticsearch/query/sort.js';
import {ElasticsearchConfig} from '../../../src/storage/elasticsearch/types/elasticsearch-config.js';
import {QueryDslSpecificQueryContainer} from '../../../src/storage/elasticsearch/types/util.js';
import {SortCombinations} from '@elastic/elasticsearch/lib/api/types';
import {SortCombinations} from '@elastic/elasticsearch/lib/api/types.js';
import {backendConfig} from '../../../src/config.js';
describe('Query', function () {

View File

@@ -0,0 +1,386 @@
import {QueryDslQueryContainer} from '@elastic/elasticsearch/lib/api/types.js';
export const query: QueryDslQueryContainer = {
function_score: {
functions: [
{
filter: {
term: {
type: 'academic event',
},
},
weight: 1,
},
{
filter: {
bool: {
must: [
{
term: {
type: 'academic event',
},
},
{
term: {
'academicTerms.acronym.raw': 'SS 2023',
},
},
],
should: [],
},
},
weight: 1.1,
},
{
filter: {
bool: {
must: [
{
term: {
type: 'academic event',
},
},
{
term: {
'academicTerms.acronym.raw': 'WS 2022/23',
},
},
],
should: [],
},
},
weight: 1.05,
},
{
filter: {
bool: {
must: [
{
term: {
type: 'academic event',
},
},
{
term: {
'academicTerms.acronym.raw': 'SoSe 2023',
},
},
],
should: [],
},
},
weight: 1.1,
},
{
filter: {
bool: {
must: [
{
term: {
type: 'academic event',
},
},
{
term: {
'academicTerms.acronym.raw': 'WiSe 2022/23',
},
},
],
should: [],
},
},
weight: 1.05,
},
{
filter: {
term: {
type: 'academic event',
},
},
weight: 1,
},
{
filter: {
bool: {
must: [
{
term: {
type: 'academic event',
},
},
{
term: {
'categories.raw': 'course',
},
},
],
should: [],
},
},
weight: 1.08,
},
{
filter: {
bool: {
must: [
{
term: {
type: 'academic event',
},
},
{
term: {
'categories.raw': 'integrated course',
},
},
],
should: [],
},
},
weight: 1.08,
},
{
filter: {
bool: {
must: [
{
term: {
type: 'academic event',
},
},
{
term: {
'categories.raw': 'introductory class',
},
},
],
should: [],
},
},
weight: 1.05,
},
{
filter: {
bool: {
must: [
{
term: {
type: 'academic event',
},
},
{
term: {
'categories.raw': 'lecture',
},
},
],
should: [],
},
},
weight: 1.1,
},
{
filter: {
bool: {
must: [
{
term: {
type: 'academic event',
},
},
{
term: {
'categories.raw': 'seminar',
},
},
],
should: [],
},
},
weight: 1.01,
},
{
filter: {
bool: {
must: [
{
term: {
type: 'academic event',
},
},
{
term: {
'categories.raw': 'tutorial',
},
},
],
should: [],
},
},
weight: 1.05,
},
{
filter: {
term: {
type: 'building',
},
},
weight: 1.6,
},
{
filter: {
term: {
type: 'point of interest',
},
},
weight: 1,
},
{
filter: {
bool: {
must: [
{
term: {
type: 'point of interest',
},
},
{
term: {
'categories.raw': 'cafe',
},
},
],
should: [],
},
},
weight: 1.1,
},
{
filter: {
bool: {
must: [
{
term: {
type: 'point of interest',
},
},
{
term: {
'categories.raw': 'learn',
},
},
],
should: [],
},
},
weight: 1.1,
},
{
filter: {
bool: {
must: [
{
term: {
type: 'point of interest',
},
},
{
term: {
'categories.raw': 'library',
},
},
],
should: [],
},
},
weight: 1.2,
},
{
filter: {
bool: {
must: [
{
term: {
type: 'point of interest',
},
},
{
term: {
'categories.raw': 'restaurant',
},
},
],
should: [],
},
},
weight: 1.1,
},
{
filter: {
term: {
type: 'dish',
},
},
weight: 1,
},
{
filter: {
bool: {
must: [
{
term: {
type: 'dish',
},
},
{
term: {
'categories.raw': 'main dish',
},
},
],
should: [],
},
},
weight: 2,
},
],
query: {
bool: {
minimum_should_match: 0,
must: [
{
dis_max: {
boost: 1.2,
queries: [
{
match: {
name: {
boost: 1.3,
fuzziness: 'AUTO',
query: 'mathematics',
},
},
},
{
query_string: {
default_field: 'name',
minimum_should_match: '75%',
query: 'mathematics',
},
},
],
tie_breaker: 0,
},
},
{
term: {
'type.raw': 'academic event',
},
},
],
should: [],
},
},
score_mode: 'multiply',
},
};