/* * Copyright (C) 2020 StApps * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ import {SCThingType} from '@openstapps/core'; import * as mapping from '@openstapps/core-tools/lib/mapping'; import {ElasticsearchTemplateCollection} from '@openstapps/core-tools/lib/mappings/mapping-definitions'; import {Logger} from '@openstapps/logger'; import {AggregationSchema} from '../../../src/storage/elasticsearch/common'; import {checkESTemplate, refreshAllTemplates} from '../../../src/storage/elasticsearch/templating'; import sinon from "sinon"; import * as path from 'path'; import * as common from '@openstapps/core-tools/lib/common'; import {expect} from 'chai'; import fs from 'fs'; import fsExtra from 'fs-extra'; import {Client} from '@elastic/elasticsearch'; describe('templating', function () { describe('checkESTemplate', function () { const sandbox = sinon.createSandbox(); let fakeMap: { aggregations: AggregationSchema, errors: string[], mappings: ElasticsearchTemplateCollection }; beforeEach(function () { fakeMap = { aggregations: { '@all': { aggs: { type: { terms: { field: 'type.raw', size: 1000 } } }, filter: { match_all: {} } }, }, errors: [], mappings: { 'template_dish': { mappings: { dish: { // @ts-ignore just mock the mapping foo: 'mapping' } }, settings: { analysis: { ducet_sort: { filter: [ 'german_phonebook' ], tokenizer: 'keyword', type: 'custom' }, search_german: { filter: [ 'lowercase', 'german_stop', 'german_stemmer' ], tokenizer: 'stapps_ngram', type: 'custom' } }, max_result_window: 30000, }, template: 'stapps_dish*' }, 'template_book': { mappings: { book: { // @ts-ignore just mock the mapping foo: 'mapping' } }, settings: { analysis: { ducet_sort: { filter: [ 'german_phonebook' ], tokenizer: 'keyword', type: 'custom' }, search_german: { filter: [ 'lowercase', 'german_stop', 'german_stemmer' ], tokenizer: 'stapps_ngram', type: 'custom' } }, max_result_window: 30000, }, template: 'stapps_book*' } } } }); afterEach(function () { sandbox.restore(); }); it('should write new templates when "force update" is true', async function () { sandbox.stub(Logger, 'error').resolves(); sandbox.stub(fs, 'existsSync').returns(true); sandbox.stub(common, 'getProjectReflection'); let caughtData: any = []; const writeFileSyncStub = sandbox.stub(fs, 'writeFileSync'); sandbox.stub(path, 'resolve').returns('/foo/bar'); sandbox.stub(mapping, 'generateTemplate').returns(fakeMap); checkESTemplate(true); expect(writeFileSyncStub.callCount).to.be.gt(0); for (let i = 0; i < writeFileSyncStub.callCount; i++) { caughtData.push(writeFileSyncStub.getCall(i).args[1]); } expect(caughtData).to.be.eql([ JSON.stringify(fakeMap.mappings['template_dish'], null, 2), JSON.stringify(fakeMap.mappings['template_book'], null, 2), JSON.stringify(fakeMap.aggregations), ]); }); it('should not write new templates when "force update" is false', async function () { sandbox.stub(Logger, 'error').resolves(); sandbox.stub(fs, 'existsSync').returns(true); sandbox.stub(common, 'getProjectReflection'); const writeFileSyncStub = sandbox.stub(fs, 'writeFileSync'); sandbox.stub(path, 'resolve').returns('/foo/bar'); sandbox.stub(mapping, 'generateTemplate').returns(fakeMap); checkESTemplate(false); expect(writeFileSyncStub.called).to.be.false; }); it('should terminate if there are errors in the map', async function () { const processExitStub = sandbox.stub(process, 'exit'); const fakeMapWithErrors = { ...fakeMap, errors: ['Foo Error'] }; sandbox.stub(Logger, 'error').resolves(); sandbox.stub(fs, 'existsSync').returns(true); sandbox.stub(common, 'getProjectReflection'); sandbox.stub(fs, 'writeFileSync'); sandbox.stub(path, 'resolve').returns('/foo/bar'); sandbox.stub(mapping, 'generateTemplate').returns(fakeMapWithErrors); checkESTemplate(true); expect(processExitStub.called).to.be.true; }); }); describe('refreshAllTemplates', async function () { const sandbox = sinon.createSandbox(); const client = { indices: { putTemplate: (_template: any) => { } } } after(function () { sandbox.restore(); }); it('should put templates for all types', async function () { const clientPutTemplateStub = sandbox.stub(client.indices, 'putTemplate'); sandbox.stub(fsExtra, 'readFile').resolves(Buffer.from('{"foo": "file content"}', 'utf8')); await refreshAllTemplates(client as Client); for (const type of Object.values(SCThingType)) { sinon.assert.calledWith(clientPutTemplateStub, { body: {foo: 'file content'}, name: `template_${type.split(' ').join('_')}` }) } }); }); });