@eeacms/volto-globalsearch 2.1.2 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -20
- package/DEVELOP.md +19 -17
- package/README.md +33 -19
- package/docker-compose.yml +1 -1
- package/jest-addon.config.js +11 -4
- package/locales/bg/LC_MESSAGES/volto.po +7 -7
- package/locales/cs/LC_MESSAGES/volto.po +7 -7
- package/locales/de/LC_MESSAGES/volto.po +7 -7
- package/locales/en/LC_MESSAGES/volto.po +7 -7
- package/locales/es/LC_MESSAGES/volto.po +7 -7
- package/locales/et/LC_MESSAGES/volto.po +7 -7
- package/locales/fi/LC_MESSAGES/volto.po +7 -7
- package/locales/fr/LC_MESSAGES/volto.po +7 -7
- package/locales/ga/LC_MESSAGES/volto.po +7 -7
- package/locales/hr/LC_MESSAGES/volto.po +7 -7
- package/locales/hu/LC_MESSAGES/volto.po +7 -7
- package/locales/it/LC_MESSAGES/volto.po +7 -7
- package/locales/lt/LC_MESSAGES/volto.po +7 -7
- package/locales/nl/LC_MESSAGES/volto.po +7 -7
- package/locales/pl/LC_MESSAGES/volto.po +7 -7
- package/locales/pt/LC_MESSAGES/volto.po +7 -7
- package/locales/ro/LC_MESSAGES/volto.po +7 -7
- package/locales/sl/LC_MESSAGES/volto.po +7 -7
- package/locales/volto.pot +9 -9
- package/package.json +2 -1
- package/src/components/MasonryLandingPage.test.jsx +1 -1
- package/src/config/clusters.test.js +221 -0
- package/src/config/filters.test.js +67 -0
- package/src/config/healthcheck.js +10 -60
- package/src/config/healthcheck.test.js +18 -13
- package/src/config/healthcheck_queries/failed_scheduled_atempts_since_last_started.json +1 -2
- package/src/config/healthcheck_queries/last_scheduled_started_indexing.json +1 -2
- package/src/config/healthcheck_queries/last_sync_task_since_last_start.json +1 -2
- package/src/config/healthcheck_queries/latest_tasks_for_site.json +1 -2
- package/src/config/healthcheck_queries/started_or_finished_site_since_last_started.json +1 -2
- package/src/config/index.test.js +1 -1
- package/src/config/query.test.js +64 -0
- package/src/config/vocabulary.test.js +92 -0
- package/src/index.test.js +74 -0
- package/src/utils.test.js +1 -1
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
2
|
+
|
|
3
|
+
import config, {
|
|
4
|
+
clusters,
|
|
5
|
+
clusterIcons,
|
|
6
|
+
typesForClustersOptionsFilter,
|
|
7
|
+
} from './clusters';
|
|
8
|
+
|
|
9
|
+
// Mock static image imports
|
|
10
|
+
jest.mock('../static/website-logo.png', () => 'website-logo.png', {
|
|
11
|
+
virtual: true,
|
|
12
|
+
});
|
|
13
|
+
jest.mock('../static/eea-logo.svg', () => 'eea-logo.svg', { virtual: true });
|
|
14
|
+
jest.mock('../static/ias-logo.png', () => 'ias-logo.png', { virtual: true });
|
|
15
|
+
jest.mock('../static/bise-logo.png', () => 'bise-logo.png', { virtual: true });
|
|
16
|
+
jest.mock('../static/wise-logo.png', () => 'wise-logo.png', { virtual: true });
|
|
17
|
+
jest.mock('../static/energy-logo.png', () => 'energy-logo.png', {
|
|
18
|
+
virtual: true,
|
|
19
|
+
});
|
|
20
|
+
jest.mock('../static/water-logo.png', () => 'water-logo.png', {
|
|
21
|
+
virtual: true,
|
|
22
|
+
});
|
|
23
|
+
jest.mock('../static/forest-logo.png', () => 'forest-logo.png', {
|
|
24
|
+
virtual: true,
|
|
25
|
+
});
|
|
26
|
+
jest.mock('../static/industry-logo.png', () => 'industry-logo.png', {
|
|
27
|
+
virtual: true,
|
|
28
|
+
});
|
|
29
|
+
jest.mock('../static/climate-adapt-logo.png', () => 'climate-adapt-logo.png', {
|
|
30
|
+
virtual: true,
|
|
31
|
+
});
|
|
32
|
+
jest.mock('../static/eionet-logo.png', () => 'eionet-logo.png', {
|
|
33
|
+
virtual: true,
|
|
34
|
+
});
|
|
35
|
+
jest.mock('../static/etc-atni.png', () => 'etc-atni.png', { virtual: true });
|
|
36
|
+
jest.mock('../static/etc-bd.jpg', () => 'etc-bd.jpg', { virtual: true });
|
|
37
|
+
jest.mock('../static/etc-cca.jpeg', () => 'etc-cca.jpeg', { virtual: true });
|
|
38
|
+
jest.mock('../static/etc-cme.png', () => 'etc-cme.png', { virtual: true });
|
|
39
|
+
jest.mock('../static/etc-icm.jpg', () => 'etc-icm.jpg', { virtual: true });
|
|
40
|
+
jest.mock('../static/etc-uls.png', () => 'etc-uls.png', { virtual: true });
|
|
41
|
+
jest.mock('../static/etc-wmge.png', () => 'etc-wmge.png', { virtual: true });
|
|
42
|
+
jest.mock('../static/cab-logo.png', () => 'cab-logo.png', { virtual: true });
|
|
43
|
+
jest.mock(
|
|
44
|
+
'../static/copernicus_insitu_logo.svg',
|
|
45
|
+
() => 'copernicus_insitu_logo.svg',
|
|
46
|
+
{ virtual: true },
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
describe('clusters configuration', () => {
|
|
50
|
+
describe('clusters object', () => {
|
|
51
|
+
it('should export clusters object', () => {
|
|
52
|
+
expect(clusters).toBeDefined();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should have name property', () => {
|
|
56
|
+
expect(clusters.name).toBe('op_cluster');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should have field property', () => {
|
|
60
|
+
expect(clusters.field).toBe('objectProvides');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should have clusters array', () => {
|
|
64
|
+
expect(clusters.clusters).toBeDefined();
|
|
65
|
+
expect(Array.isArray(clusters.clusters)).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should have News cluster', () => {
|
|
69
|
+
const newsCluster = clusters.clusters.find((c) => c.name === 'News');
|
|
70
|
+
expect(newsCluster).toBeDefined();
|
|
71
|
+
expect(newsCluster.values).toContain('News');
|
|
72
|
+
expect(newsCluster.values).toContain('Article');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should have Publications cluster', () => {
|
|
76
|
+
const pubCluster = clusters.clusters.find(
|
|
77
|
+
(c) => c.name === 'Publications',
|
|
78
|
+
);
|
|
79
|
+
expect(pubCluster).toBeDefined();
|
|
80
|
+
expect(pubCluster.values).toContain('Report');
|
|
81
|
+
expect(pubCluster.values).toContain('Indicator');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should have Maps and charts cluster', () => {
|
|
85
|
+
const mapsCluster = clusters.clusters.find(
|
|
86
|
+
(c) => c.name === 'Maps and charts',
|
|
87
|
+
);
|
|
88
|
+
expect(mapsCluster).toBeDefined();
|
|
89
|
+
expect(mapsCluster.values).toContain('Dashboard');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should have Data cluster', () => {
|
|
93
|
+
const dataCluster = clusters.clusters.find((c) => c.name === 'Data');
|
|
94
|
+
expect(dataCluster).toBeDefined();
|
|
95
|
+
expect(dataCluster.values).toContain('Data set');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should have Others cluster', () => {
|
|
99
|
+
const othersCluster = clusters.clusters.find((c) => c.name === 'Others');
|
|
100
|
+
expect(othersCluster).toBeDefined();
|
|
101
|
+
expect(othersCluster.values).toContain('Webpage');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('each cluster should have defaultResultView', () => {
|
|
105
|
+
clusters.clusters.forEach((cluster) => {
|
|
106
|
+
expect(cluster.defaultResultView).toBeDefined();
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('clusterIcons', () => {
|
|
112
|
+
it('should export clusterIcons', () => {
|
|
113
|
+
expect(clusterIcons).toBeDefined();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should have fallback icon', () => {
|
|
117
|
+
expect(clusterIcons.fallback).toBeDefined();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should have News icon mapping', () => {
|
|
121
|
+
expect(clusterIcons.News).toBeDefined();
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
describe('config', () => {
|
|
126
|
+
it('should export default config', () => {
|
|
127
|
+
expect(config).toBeDefined();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should have icons configuration', () => {
|
|
131
|
+
expect(config.icons).toBeDefined();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('should have Content types icons', () => {
|
|
135
|
+
expect(config.icons['Content types']).toBeDefined();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should have Sources icons', () => {
|
|
139
|
+
expect(config.icons.Sources).toBeDefined();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should have contentSectionsParams', () => {
|
|
143
|
+
expect(config.contentSectionsParams).toBeDefined();
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('should have contentSectionsParams.enable set to true', () => {
|
|
147
|
+
expect(config.contentSectionsParams.enable).toBe(true);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('should have contentSectionsParams.sectionFacetsField', () => {
|
|
151
|
+
expect(config.contentSectionsParams.sectionFacetsField).toBe(
|
|
152
|
+
'op_cluster',
|
|
153
|
+
);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('should have clusterMapping in contentSectionsParams', () => {
|
|
157
|
+
expect(config.contentSectionsParams.clusterMapping).toBeDefined();
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe('typesForClustersOptionsFilter', () => {
|
|
162
|
+
const mockOptions = [
|
|
163
|
+
{ value: 'News' },
|
|
164
|
+
{ value: 'Article' },
|
|
165
|
+
{ value: 'Report' },
|
|
166
|
+
{ value: 'Dashboard' },
|
|
167
|
+
{ value: 'Data set' },
|
|
168
|
+
];
|
|
169
|
+
|
|
170
|
+
it('should return all options when no cluster filter is active', () => {
|
|
171
|
+
const filters = [];
|
|
172
|
+
const result = typesForClustersOptionsFilter(mockOptions, filters);
|
|
173
|
+
expect(result).toEqual(mockOptions);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('should return all options when filters is undefined', () => {
|
|
177
|
+
const result = typesForClustersOptionsFilter(mockOptions, undefined);
|
|
178
|
+
expect(result).toEqual(mockOptions);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('should filter options for News cluster', () => {
|
|
182
|
+
const filters = [{ field: 'op_cluster', values: ['News'] }];
|
|
183
|
+
const result = typesForClustersOptionsFilter(mockOptions, filters);
|
|
184
|
+
|
|
185
|
+
expect(result).toContainEqual({ value: 'News' });
|
|
186
|
+
expect(result).toContainEqual({ value: 'Article' });
|
|
187
|
+
expect(result).not.toContainEqual({ value: 'Report' });
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('should filter options for Publications cluster', () => {
|
|
191
|
+
const filters = [{ field: 'op_cluster', values: ['Publications'] }];
|
|
192
|
+
const result = typesForClustersOptionsFilter(mockOptions, filters);
|
|
193
|
+
|
|
194
|
+
expect(result).toContainEqual({ value: 'Report' });
|
|
195
|
+
expect(result).not.toContainEqual({ value: 'News' });
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('should filter options for Data cluster', () => {
|
|
199
|
+
const filters = [{ field: 'op_cluster', values: ['Data'] }];
|
|
200
|
+
const result = typesForClustersOptionsFilter(mockOptions, filters);
|
|
201
|
+
|
|
202
|
+
expect(result).toContainEqual({ value: 'Data set' });
|
|
203
|
+
expect(result).not.toContainEqual({ value: 'News' });
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('should filter options for Maps and charts cluster', () => {
|
|
207
|
+
const filters = [{ field: 'op_cluster', values: ['Maps and charts'] }];
|
|
208
|
+
const result = typesForClustersOptionsFilter(mockOptions, filters);
|
|
209
|
+
|
|
210
|
+
expect(result).toContainEqual({ value: 'Dashboard' });
|
|
211
|
+
expect(result).not.toContainEqual({ value: 'News' });
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('should return empty array when no options match the cluster', () => {
|
|
215
|
+
const filters = [{ field: 'op_cluster', values: ['NonExistent'] }];
|
|
216
|
+
const result = typesForClustersOptionsFilter(mockOptions, filters);
|
|
217
|
+
|
|
218
|
+
expect(result).toEqual([]);
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import filters from './filters';
|
|
2
|
+
import '@testing-library/jest-dom';
|
|
3
|
+
|
|
4
|
+
describe('filters configuration', () => {
|
|
5
|
+
it('should export filters object', () => {
|
|
6
|
+
expect(filters).toBeDefined();
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('should have permanentFilters array', () => {
|
|
10
|
+
expect(filters.permanentFilters).toBeDefined();
|
|
11
|
+
expect(Array.isArray(filters.permanentFilters)).toBe(true);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should have published workflow state filter', () => {
|
|
15
|
+
const workflowFilter = filters.permanentFilters.find(
|
|
16
|
+
(f) => f.term && f.term.hasWorkflowState === 'published',
|
|
17
|
+
);
|
|
18
|
+
expect(workflowFilter).toBeDefined();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should have constantScore filter function', () => {
|
|
22
|
+
const constantScoreFilter = filters.permanentFilters.find(
|
|
23
|
+
(f) => typeof f === 'function' && f.id === 'constantScore',
|
|
24
|
+
);
|
|
25
|
+
expect(constantScoreFilter).toBeDefined();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('constantScore filter should return correct structure', () => {
|
|
29
|
+
const constantScoreFilter = filters.permanentFilters.find(
|
|
30
|
+
(f) => typeof f === 'function' && f.id === 'constantScore',
|
|
31
|
+
);
|
|
32
|
+
const result = constantScoreFilter();
|
|
33
|
+
|
|
34
|
+
expect(result.constant_score).toBeDefined();
|
|
35
|
+
expect(result.constant_score.filter).toBeDefined();
|
|
36
|
+
expect(result.constant_score.filter.bool).toBeDefined();
|
|
37
|
+
expect(result.constant_score.filter.bool.should).toBeDefined();
|
|
38
|
+
expect(Array.isArray(result.constant_score.filter.bool.should)).toBe(true);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('constantScore filter should have must_not exists condition', () => {
|
|
42
|
+
const constantScoreFilter = filters.permanentFilters.find(
|
|
43
|
+
(f) => typeof f === 'function' && f.id === 'constantScore',
|
|
44
|
+
);
|
|
45
|
+
const result = constantScoreFilter();
|
|
46
|
+
|
|
47
|
+
const mustNotExistsCondition =
|
|
48
|
+
result.constant_score.filter.bool.should.find(
|
|
49
|
+
(s) => s.bool && s.bool.must_not && s.bool.must_not.exists,
|
|
50
|
+
);
|
|
51
|
+
expect(mustNotExistsCondition).toBeDefined();
|
|
52
|
+
expect(mustNotExistsCondition.bool.must_not.exists.field).toBe('issued');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('constantScore filter should have range condition for issued.date', () => {
|
|
56
|
+
const constantScoreFilter = filters.permanentFilters.find(
|
|
57
|
+
(f) => typeof f === 'function' && f.id === 'constantScore',
|
|
58
|
+
);
|
|
59
|
+
const result = constantScoreFilter();
|
|
60
|
+
|
|
61
|
+
const rangeCondition = result.constant_score.filter.bool.should.find(
|
|
62
|
+
(s) => s.range && s.range['issued.date'],
|
|
63
|
+
);
|
|
64
|
+
expect(rangeCondition).toBeDefined();
|
|
65
|
+
expect(rangeCondition.range['issued.date'].lte).toBeDefined();
|
|
66
|
+
});
|
|
67
|
+
});
|
|
@@ -10,8 +10,6 @@ import latest_tasks_for_site from './healthcheck_queries/latest_tasks_for_site.j
|
|
|
10
10
|
import started_or_finished_site_since_last_started from './healthcheck_queries/started_or_finished_site_since_last_started.json';
|
|
11
11
|
|
|
12
12
|
const default_documentCountThreshold = 60000;
|
|
13
|
-
const default_queryTimeSecondsThreshold_OK = 2;
|
|
14
|
-
const default_queryTimeSecondsThreshold_WARNING = 5;
|
|
15
13
|
const default_failedSyncThreshold_WARNING = 5;
|
|
16
14
|
const default_failedSyncThreshold_OK = 2;
|
|
17
15
|
|
|
@@ -24,11 +22,11 @@ export function buildQuery(query, values) {
|
|
|
24
22
|
}
|
|
25
23
|
|
|
26
24
|
async function executeQuery(q, appConfig, params = {}, callback) {
|
|
27
|
-
|
|
25
|
+
const { id, host } = appConfig;
|
|
26
|
+
const url = new URL(host);
|
|
27
|
+
url.pathname = `/_es/{status_}${id}/_search`;
|
|
28
28
|
const query = buildQuery(q, params);
|
|
29
|
-
|
|
30
|
-
const resp = await runRequest(query, appConfig);
|
|
31
|
-
// console.log(JSON.stringify(resp.body));
|
|
29
|
+
const resp = await runRequest(query, appConfig, url);
|
|
32
30
|
return Promise.resolve(callback(resp.body, params));
|
|
33
31
|
}
|
|
34
32
|
|
|
@@ -101,8 +99,7 @@ export function getlatesttasks_for_site(body, params = {}) {
|
|
|
101
99
|
export async function getStatus(appConfig, params) {
|
|
102
100
|
let resp = 'OK';
|
|
103
101
|
let error = null;
|
|
104
|
-
// console.log('
|
|
105
|
-
// console.log('STEP 1');
|
|
102
|
+
// console.log('==== STEP 1 ====');
|
|
106
103
|
const step1 = await executeQuery(
|
|
107
104
|
last_scheduled_started_indexing,
|
|
108
105
|
appConfig,
|
|
@@ -110,16 +107,13 @@ export async function getStatus(appConfig, params) {
|
|
|
110
107
|
getlastandnext_started_execution,
|
|
111
108
|
);
|
|
112
109
|
|
|
113
|
-
// console.log(step1);
|
|
114
|
-
|
|
115
110
|
// const last_successful_schedule = step1.last_started;
|
|
116
111
|
let next_schedule = step1.next_execution_date;
|
|
117
112
|
|
|
118
113
|
const now = params.now || Date.now() - 60 * 1000;
|
|
119
114
|
if (now >= next_schedule) {
|
|
120
115
|
try {
|
|
121
|
-
// console.log('
|
|
122
|
-
// console.log('STEP 2');
|
|
116
|
+
// console.log('==== STEP 2 ====');
|
|
123
117
|
const step2 = await executeQuery(
|
|
124
118
|
failed_scheduled_atempts_since_last_started,
|
|
125
119
|
appConfig,
|
|
@@ -127,7 +121,6 @@ export async function getStatus(appConfig, params) {
|
|
|
127
121
|
getlastfailed_execution,
|
|
128
122
|
);
|
|
129
123
|
next_schedule = step2.next_execution_date;
|
|
130
|
-
// console.log(step2);
|
|
131
124
|
} catch {
|
|
132
125
|
resp = 'CRITICAL';
|
|
133
126
|
error = 'Failed to get status info from elasticsearch';
|
|
@@ -139,19 +132,17 @@ export async function getStatus(appConfig, params) {
|
|
|
139
132
|
error = 'Airflow stopped indexing, no new schedules in the queue';
|
|
140
133
|
} else {
|
|
141
134
|
try {
|
|
135
|
+
// console.log('==== STEP 3 ====');
|
|
142
136
|
const step3 = await executeQuery(
|
|
143
137
|
last_sync_task_since_last_start,
|
|
144
138
|
appConfig,
|
|
145
139
|
step1,
|
|
146
140
|
getlastsynctaskssincestarted,
|
|
147
141
|
);
|
|
148
|
-
// console.log(step3.sites);
|
|
149
142
|
const all_sites_status = {};
|
|
150
143
|
for (let i = 0; i < step3.sites.length; i++) {
|
|
151
144
|
try {
|
|
152
|
-
// console.log('
|
|
153
|
-
// console.log('STEP 4');
|
|
154
|
-
// const step4 =
|
|
145
|
+
// console.log('==== STEP 4 ====');
|
|
155
146
|
await executeQuery(
|
|
156
147
|
started_or_finished_site_since_last_started,
|
|
157
148
|
appConfig,
|
|
@@ -162,10 +153,8 @@ export async function getStatus(appConfig, params) {
|
|
|
162
153
|
getlastsuccessfultasks_for_site,
|
|
163
154
|
);
|
|
164
155
|
all_sites_status[step3.sites[i]] = 'OK';
|
|
165
|
-
// console.log(step4);
|
|
166
156
|
} catch {
|
|
167
|
-
// console.log('
|
|
168
|
-
// console.log('STEP 5');
|
|
157
|
+
// console.log('==== STEP 5 ====');
|
|
169
158
|
const step5 = await executeQuery(
|
|
170
159
|
latest_tasks_for_site,
|
|
171
160
|
appConfig,
|
|
@@ -182,7 +171,6 @@ export async function getStatus(appConfig, params) {
|
|
|
182
171
|
all_sites_status[step3.sites[i]] = step5;
|
|
183
172
|
}
|
|
184
173
|
}
|
|
185
|
-
// console.log(all_sites_status);
|
|
186
174
|
const oks = [];
|
|
187
175
|
const warnings = [];
|
|
188
176
|
const criticals = [];
|
|
@@ -232,19 +220,12 @@ export default async function healthcheck(appConfig, params) {
|
|
|
232
220
|
try {
|
|
233
221
|
let {
|
|
234
222
|
documentCountThreshold,
|
|
235
|
-
queryTimeSecondsThreshold_OK,
|
|
236
|
-
queryTimeSecondsThreshold_WARNING,
|
|
237
223
|
failedSyncThreshold_OK,
|
|
238
224
|
failedSyncThreshold_WARNING,
|
|
239
225
|
now,
|
|
240
226
|
} = params;
|
|
241
227
|
documentCountThreshold =
|
|
242
228
|
documentCountThreshold || default_documentCountThreshold;
|
|
243
|
-
queryTimeSecondsThreshold_OK =
|
|
244
|
-
queryTimeSecondsThreshold_OK || default_queryTimeSecondsThreshold_OK;
|
|
245
|
-
queryTimeSecondsThreshold_WARNING =
|
|
246
|
-
queryTimeSecondsThreshold_WARNING ||
|
|
247
|
-
default_queryTimeSecondsThreshold_WARNING;
|
|
248
229
|
failedSyncThreshold_OK =
|
|
249
230
|
failedSyncThreshold_OK || default_failedSyncThreshold_OK;
|
|
250
231
|
failedSyncThreshold_WARNING =
|
|
@@ -256,9 +237,7 @@ export default async function healthcheck(appConfig, params) {
|
|
|
256
237
|
now: now,
|
|
257
238
|
};
|
|
258
239
|
|
|
259
|
-
///////////////////
|
|
260
240
|
const body_total = buildRequest({ filters: [] }, appConfig);
|
|
261
|
-
//console.log(body_total);
|
|
262
241
|
const resp_total = await runRequest(body_total, appConfig);
|
|
263
242
|
const total = resp_total.body.hits.total.value;
|
|
264
243
|
const total_status =
|
|
@@ -269,41 +248,15 @@ export default async function healthcheck(appConfig, params) {
|
|
|
269
248
|
error:
|
|
270
249
|
'The number of documents in elasticsearch dropped drastically',
|
|
271
250
|
};
|
|
272
|
-
const body_nlp = buildRequest(
|
|
273
|
-
{ filters: [], searchTerm: 'what is bise?' },
|
|
274
|
-
appConfig,
|
|
275
|
-
);
|
|
276
|
-
const resp_nlp = await runRequest(body_nlp, appConfig);
|
|
277
|
-
const elapsed = resp_nlp.body.elapsed;
|
|
278
|
-
|
|
279
|
-
let total_elapsed = 0;
|
|
280
|
-
Object.keys(elapsed).forEach((key) => {
|
|
281
|
-
elapsed[key].forEach((nlp_step) => {
|
|
282
|
-
Object.keys(nlp_step).forEach((step_name) => {
|
|
283
|
-
total_elapsed += nlp_step[step_name].delta;
|
|
284
|
-
});
|
|
285
|
-
});
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
const elapsed_status =
|
|
289
|
-
total_elapsed < queryTimeSecondsThreshold_OK
|
|
290
|
-
? { status: 'OK' }
|
|
291
|
-
: total_elapsed < queryTimeSecondsThreshold_WARNING
|
|
292
|
-
? { status: 'WARNING', error: 'Slow response from NLP' }
|
|
293
|
-
: { status: 'CRITICAL', error: 'Slow response from NLP' };
|
|
294
251
|
|
|
295
252
|
const airflow_status = await getStatus(appConfig, airflow_params);
|
|
296
253
|
|
|
297
254
|
let status = { status: 'OK' };
|
|
298
|
-
if (
|
|
299
|
-
elapsed_status.status === 'WARNING' ||
|
|
300
|
-
airflow_status.status === 'WARNING'
|
|
301
|
-
) {
|
|
255
|
+
if (airflow_status.status === 'WARNING') {
|
|
302
256
|
status = { status: 'WARNING' };
|
|
303
257
|
}
|
|
304
258
|
if (
|
|
305
259
|
total_status.status === 'CRITICAL' ||
|
|
306
|
-
elapsed_status.status === 'CRITICAL' ||
|
|
307
260
|
airflow_status.status === 'CRITICAL'
|
|
308
261
|
) {
|
|
309
262
|
status = { status: 'CRITICAL' };
|
|
@@ -313,9 +266,6 @@ export default async function healthcheck(appConfig, params) {
|
|
|
313
266
|
if (total_status.error) {
|
|
314
267
|
errors_list.push(total_status.error);
|
|
315
268
|
}
|
|
316
|
-
if (elapsed_status.error) {
|
|
317
|
-
errors_list.push(elapsed_status.error);
|
|
318
|
-
}
|
|
319
269
|
if (airflow_status.error) {
|
|
320
270
|
errors_list.push(airflow_status.error);
|
|
321
271
|
}
|
|
@@ -29,6 +29,15 @@ jest.mock('@eeacms/search', () => ({
|
|
|
29
29
|
buildRequest: jest.fn(),
|
|
30
30
|
}));
|
|
31
31
|
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
runRequest.mockClear();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const mockAppConfig = {
|
|
37
|
+
id: 'test_index',
|
|
38
|
+
host: 'http://localhost:9200',
|
|
39
|
+
};
|
|
40
|
+
|
|
32
41
|
const query1 = {
|
|
33
42
|
query: {
|
|
34
43
|
bool: {
|
|
@@ -253,7 +262,7 @@ describe('test the status of the index', () => {
|
|
|
253
262
|
// }),
|
|
254
263
|
);
|
|
255
264
|
const params = { index_name: 'test_index', now: 1695732000000 };
|
|
256
|
-
const status = await getStatus(
|
|
265
|
+
const status = await getStatus(mockAppConfig, params);
|
|
257
266
|
expect(status).toEqual({ status: 'OK' });
|
|
258
267
|
});
|
|
259
268
|
});
|
|
@@ -261,20 +270,11 @@ describe('test the status of the index', () => {
|
|
|
261
270
|
describe('test the healthcheck', () => {
|
|
262
271
|
it('test', async () => {
|
|
263
272
|
runRequest
|
|
273
|
+
// First call: total document count check
|
|
264
274
|
.mockReturnValueOnce(
|
|
265
275
|
Promise.resolve({ body: { hits: { total: { value: 60001 } } } }),
|
|
266
276
|
)
|
|
267
|
-
|
|
268
|
-
Promise.resolve({
|
|
269
|
-
body: {
|
|
270
|
-
elapsed: {
|
|
271
|
-
step1: [{ query: { delta: 0.5 } }],
|
|
272
|
-
step2: [{ query: { delta: 0.6 } }],
|
|
273
|
-
},
|
|
274
|
-
},
|
|
275
|
-
}),
|
|
276
|
-
)
|
|
277
|
-
|
|
277
|
+
// getStatus calls:
|
|
278
278
|
.mockReturnValueOnce(
|
|
279
279
|
Promise.resolve({ body: last_scheduled_started_indexing_resp }),
|
|
280
280
|
)
|
|
@@ -288,13 +288,18 @@ describe('test the healthcheck', () => {
|
|
|
288
288
|
body: last_sync_task_since_last_start_resp,
|
|
289
289
|
}),
|
|
290
290
|
)
|
|
291
|
+
.mockReturnValueOnce(
|
|
292
|
+
Promise.resolve({
|
|
293
|
+
body: started_or_finished_site_since_last_started_resp,
|
|
294
|
+
}),
|
|
295
|
+
)
|
|
291
296
|
.mockReturnValueOnce(
|
|
292
297
|
Promise.resolve({
|
|
293
298
|
body: started_or_finished_site_since_last_started_resp,
|
|
294
299
|
}),
|
|
295
300
|
);
|
|
296
301
|
const params = { index_name: 'test_index', now: 1695732000000 };
|
|
297
|
-
const status = await healthcheck(
|
|
302
|
+
const status = await healthcheck(mockAppConfig, params);
|
|
298
303
|
expect(status).toEqual({ status: 'OK' });
|
|
299
304
|
});
|
|
300
305
|
});
|
package/src/config/index.test.js
CHANGED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import query from './query';
|
|
2
|
+
import '@testing-library/jest-dom';
|
|
3
|
+
|
|
4
|
+
describe('query configuration', () => {
|
|
5
|
+
it('should export query object', () => {
|
|
6
|
+
expect(query).toBeDefined();
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('should have debugQuery set to false', () => {
|
|
10
|
+
expect(query.debugQuery).toBe(false);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should have extraQueryParams', () => {
|
|
14
|
+
expect(query.extraQueryParams).toBeDefined();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should have text_fields in extraQueryParams', () => {
|
|
18
|
+
expect(query.extraQueryParams.text_fields).toBeDefined();
|
|
19
|
+
expect(Array.isArray(query.extraQueryParams.text_fields)).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should have title with boost in text_fields', () => {
|
|
23
|
+
expect(query.extraQueryParams.text_fields).toContain('title^2');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should have subject with boost in text_fields', () => {
|
|
27
|
+
expect(query.extraQueryParams.text_fields).toContain('subject^1.5');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should have description with boost in text_fields', () => {
|
|
31
|
+
expect(query.extraQueryParams.text_fields).toContain('description^1.5');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should have all_fields_for_freetext in text_fields', () => {
|
|
35
|
+
expect(query.extraQueryParams.text_fields).toContain(
|
|
36
|
+
'all_fields_for_freetext',
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should have functions in extraQueryParams', () => {
|
|
41
|
+
expect(query.extraQueryParams.functions).toBeDefined();
|
|
42
|
+
expect(Array.isArray(query.extraQueryParams.functions)).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should have exp function for issued.date', () => {
|
|
46
|
+
const expFunction = query.extraQueryParams.functions.find((f) => f.exp);
|
|
47
|
+
expect(expFunction).toBeDefined();
|
|
48
|
+
expect(expFunction.exp['issued.date']).toBeDefined();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should have correct offset for issued.date function', () => {
|
|
52
|
+
const expFunction = query.extraQueryParams.functions.find((f) => f.exp);
|
|
53
|
+
expect(expFunction.exp['issued.date'].offset).toBe('30d');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should have correct scale for issued.date function', () => {
|
|
57
|
+
const expFunction = query.extraQueryParams.functions.find((f) => f.exp);
|
|
58
|
+
expect(expFunction.exp['issued.date'].scale).toBe('1800d');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should have score_mode set to sum', () => {
|
|
62
|
+
expect(query.extraQueryParams.score_mode).toBe('sum');
|
|
63
|
+
});
|
|
64
|
+
});
|