UNPKG

17.5 kBJavaScriptView Raw
1/*eslint no-magic-numbers: "off"*/
2/*eslint no-invalid-this: "off"*/
3const _ = require('lodash');
4const expect = require('chai').expect;
5const Promise = require('bluebird');
6const TestConfig = require('../config');
7const Utils = require('../utils');
8const Compiler = require('../../app/services/compiler');
9const Transfer = require('../../app/services/transfer');
10const createEsClient = require('../../config/elasticsearch.js');
11const config = require('../../config/index');
12
13const log = config.log;
14const compiler = new Compiler();
15const utils = new Utils();
16
17Promise.longStackTraces();
18Promise.onPossiblyUnhandledRejection((error) => log.error('Likely error: ', error.stack));
19
20const loadMutator = (path) => compiler.compile(utils.loadFile(path));
21
22describe('transfer', function () {
23 this.timeout(5000);
24
25 let transfer = null;
26 let source = null;
27 let dest = null;
28
29 before((done) => {
30 source = createEsClient(TestConfig.elasticsearch.source);
31 dest = createEsClient(TestConfig.elasticsearch.destination);
32
33 transfer = new Transfer(source, dest);
34
35 utils.deleteAllTemplates(source)
36 .finally(() => utils.deleteAllTemplates(dest))
37 .finally(() => utils.deleteAllIndices(source))
38 .finally(() => utils.deleteAllIndices(dest))
39 .finally(() => done());
40 });
41
42 afterEach((done) => {
43 transfer.clearMutators();
44 transfer.setUpdateCallback(null);
45
46 utils.deleteAllTemplates(source)
47 .finally(() => utils.deleteAllTemplates(dest))
48 .finally(() => utils.deleteAllIndices(source))
49 .finally(() => utils.deleteAllIndices(dest))
50 .finally(() => done());
51 });
52
53 const addTemplate = () => transfer.source.indices.putTemplate({
54 name: 'test_template',
55 body: {
56 template: 'te*',
57 refresh: true,
58 settings: {
59 number_of_shards: 1
60 },
61 mappings: {
62 type1: {
63 _source: {
64 enabled: false
65 },
66 properties: {
67 host_name: {
68 type: 'keyword'
69 },
70 created_at: {
71 type: 'date',
72 format: 'EEE MMM dd HH:mm:ss Z YYYY'
73 }
74 }
75 }
76 }
77 }
78 });
79
80 it('should get all indices and types', (done) => {
81 utils.addData(source)
82 .then(() => source.indices.refresh())
83 .then(() => Transfer.getIndices(source, '*'))
84 .then((indices) => {
85 expect(_.size(indices)).to.be.equals(3);
86
87 const myindex1 = _.find(indices, {name: 'myindex1'});
88 expect(myindex1).to.not.be.undefined;
89 expect(_.size(myindex1.mappings)).to.be.equals(1);
90 expect(myindex1.mappings.mytype1).to.not.be.undefined;
91 expect(myindex1.mappings.mytype2).to.be.undefined;
92
93 const myindex2 = _.find(indices, {name: 'myindex2'});
94 expect(myindex2).to.not.be.undefined;
95 expect(_.size(myindex2.mappings)).to.be.equals(1);
96 expect(myindex2.mappings.mytype1).to.not.be.undefined;
97
98 const myindex3 = _.find(indices, {name: 'myindex3'});
99 expect(myindex3).to.not.be.undefined;
100 expect(_.size(myindex1.mappings)).to.be.equals(1);
101 expect(myindex3.mappings.mytype2).to.be.undefined;
102 expect(myindex3.mappings.mytype3).to.not.be.undefined;
103 })
104 .then(() => done())
105 .catch(done);
106 });
107
108 it('should throw if getTemplates arg is not a non-zero string', (done) => {
109 Transfer.getTemplates(source, {})
110 .then(() => done('fail'))
111 .catch((e) => expect(e.message).to.be.equals('targetTemplates must be string with length'))
112 .then(() => Transfer.getTemplates(source, () => {
113 }))
114 .then(() => done('fail'))
115 .catch((e) => expect(e.message).to.be.equals('targetTemplates must be string with length'))
116 .then(() => Transfer.getTemplates(source, 1))
117 .then(() => done('fail'))
118 .catch((e) => expect(e.message).to.be.equals('targetTemplates must be string with length'))
119 .then(() => Transfer.getTemplates(source, ''))
120 .then(() => done('fail'))
121 .catch((e) => expect(e.message).to.be.equals('targetTemplates must be string with length'))
122 .then(() => done());
123 });
124
125 it('should reject if there are no templates', (done) => {
126 Transfer.getTemplates(source, '*')
127 .then(() => done('fail'))
128 .catch((error) => {
129 expect(error).to.match(/Templates asked to be copied, but none found/);
130 done();
131 });
132 });
133
134 it('should get templates', (done) => {
135 addTemplate()
136 .then(() => Transfer.getTemplates(source, '*'))
137 .then((templates) => {
138 expect(templates).to.be.an.instanceof(Array);
139 expect(_.size(templates)).to.be.equals(1);
140 expect(templates[0].name).to.be.equals('test_template');
141 expect(templates[0].index_patterns[0]).to.be.equals('te*');
142 done();
143 })
144 .catch(done);
145 });
146
147 it('should put templates', (done) => {
148 const sourceTemplates = [
149 {
150 name: 'test_template',
151 template: 'te*',
152 refresh: true,
153 settings: {
154 number_of_shards: 1
155 },
156 mappings: {
157 type1: {
158 _source: {
159 enabled: false
160 },
161 properties: {
162 host_name: {
163 type: 'text'
164 },
165 created_at: {
166 type: 'date',
167 format: 'EEE MMM dd HH:mm:ss Z YYYY'
168 }
169 }
170 }
171 }
172 },
173 {
174 name: 'test_template_2',
175 template: 'te2*',
176 refresh: true,
177 settings: {
178 number_of_shards: 1
179 },
180 mappings: {
181 type1: {
182 _source: {
183 enabled: false
184 },
185 properties: {
186 host_name: {
187 type: 'text'
188 },
189 created_at: {
190 type: 'date',
191 format: 'EEE MMM dd HH:mm:ss Z YYYY'
192 }
193 }
194 }
195 }
196 }
197 ];
198
199 transfer.putTemplates(sourceTemplates)
200 .then(() => transfer.dest.indices.getTemplate())
201 .then((destTemplates) => {
202 expect(destTemplates).to.have.property('test_template');
203 expect(destTemplates.test_template.index_patterns[0]).to.be.equals('te*');
204 expect(destTemplates).to.have.property('test_template_2');
205 expect(destTemplates.test_template_2.index_patterns[0]).to.be.equals('te2*');
206 done();
207 })
208 .catch(done);
209 });
210
211 it('should get indices', (done) => {
212 const index = {
213 settings: {
214 number_of_shards: 1,
215 number_of_replicas: 2
216 },
217 mappings: {
218 type1: {
219 properties: {
220 field1: {type: 'text'}
221 }
222 }
223 },
224 aliases: {
225 alias_1: {}
226 }
227 };
228
229 transfer.source.indices.create({
230 index: 'twitter1',
231 body: index
232 })
233 .then(() => transfer.source.indices.create({
234 index: 'twitter2',
235 body: index
236 }))
237 .then(() => Transfer.getIndices(transfer.source, '*'))
238 .then((indices) => {
239 expect(indices).to.have.length(2);
240 expect(Object.keys(indices[0])).to.include('name', 'settings', 'mappings', 'alias', 'warmers');
241 expect(indices[0].name).to.be.oneOf([
242 'twitter1',
243 'twitter2'
244 ]);
245 expect(Object.keys(indices[1])).to.include('name', 'settings', 'mappings', 'alias', 'warmers');
246 expect(indices[1].name).to.be.oneOf([
247 'twitter1',
248 'twitter2'
249 ]);
250 expect(indices[0].name).to.not.eql(indices[1].name);
251 })
252 .then(() => done());
253 });
254
255 it('should reject if there is an error during get indices', (done) => {
256 Transfer.getIndices(transfer.source, 'missingIndexName')
257 .then(() => done('fail'))
258 .catch(() => done());
259 });
260
261 it('should put indices', (done) => {
262 const index = {
263 settings: {
264 number_of_shards: 1,
265 number_of_replicas: 2
266 },
267 mappings: {
268 type1: {
269 properties: {
270 field1: {type: 'long'}
271 }
272 }
273 },
274 aliases: {
275 alias_1: {}
276 }
277 };
278
279 utils.deleteAllIndices(transfer.dest)
280 .then(() => transfer.source.indices.create({
281 index: 'twitter1',
282 body: index
283 }))
284 .then(() => transfer.source.indices.create({
285 index: 'twitter2',
286 body: index
287 }))
288 .then(() => Transfer.getIndices(transfer.source, '*'))
289 .then((indices) => transfer.putIndices(indices))
290 .then(() => transfer.dest.indices.get({index: '*'}))
291 .then((response) => {
292 expect(_.size(response)).to.be.equals(2);
293
294 expect(response.twitter1).to.not.be.undefined;
295 expect(response.twitter1.settings.index.number_of_shards).to.be.equals('1');
296 expect(response.twitter1.settings.index.number_of_replicas).to.be.equals('2');
297 expect(response.twitter1.mappings.type1.properties.field1.type).to.be.equals('long');
298
299 expect(response.twitter2).to.not.be.undefined;
300 expect(response.twitter2.settings.index.number_of_shards).to.be.equals('1');
301 expect(response.twitter2.settings.index.number_of_replicas).to.be.equals('2');
302 expect(response.twitter2.mappings.type1.properties.field1.type).to.be.equals('long');
303 })
304 .then(() => done())
305 .catch(done);
306 });
307
308 it('should reject if there is an error during put indices', (done) => {
309 const indices = [
310 {
311 name: 'something',
312 settings: {
313 number_of_shards: -100
314 },
315 mappings: {
316 type1: {
317 properties: {
318 field1: {type: 'text'}
319 }
320 }
321 },
322 aliases: {
323 alias_1: {}
324 }
325 }
326 ];
327
328 transfer.putIndices(indices)
329 .then(() => done('fail'))
330 .catch(() => done());
331 });
332
333 it('should get all data in given index and type', (done) => {
334 const index = 'myindex1';
335 const type = 'mytype1';
336
337 utils.createIndices(transfer, index, index)
338 .then(() => source.bulk({
339 refresh: true,
340 body: require('./lotsOfData.json')
341 }))
342 .then(() => transfer.transferData(index, type, 10))
343 .then(() => transfer.dest.indices.refresh({index: '*'}))
344 .then(() => transfer.dest.search({size: 100}))
345 .then((response) => expect(response.hits.hits).to.be.length(20))
346 .then(() => done())
347 .catch(done);
348 });
349
350 it('should throw if no indexName is provided', (done) => {
351 const throws = () => transfer.transferData(null, 'mytype1');
352 expect(throws).to.throw('targetIndex must be string with length');
353 done();
354 });
355
356 it('should throw if no typeName is provided', (done) => {
357 const throws = () => transfer.transferData('myindex', null);
358 expect(throws).to.throw('targetType must be string with length');
359 done();
360 });
361
362 it('should reject if index does not exist', (done) => {
363 transfer.transferData('notthere', 'mytype1')
364 .then(() => done('fail'))
365 .catch(() => done());
366 });
367
368 it('should call callback with status updates', (done) => {
369 const index = 'myindex1';
370 const data = [];
371
372 _.times(100, (n) => {
373 data.push({
374 index: {
375 _index: index,
376 _type: index
377 }
378 });
379 data.push({something: `data${n}`});
380 });
381
382 transfer.setUpdateCallback((status) => {
383 log.info('status', status);
384 if (status.transferred === 100) {
385 done();
386 }
387 });
388
389 utils.createIndices(transfer, index, index)
390 .then(() => source.bulk({body: data}))
391 .then((results) => results.errors ? Promise.reject(`errors: ${results.errors}`) : source.indices.refresh())
392 .then(() => transfer.transferData(index, index))
393 .catch(done);
394 });
395
396 it('should return the original when no mutator is present', (done) => {
397 source.indices.create({
398 index: 'index_to_mutate',
399 body: {settings: {number_of_shards: 4}}
400 })
401 .then(() => transfer.transferIndices('index_to_mutate'))
402 .then(() => dest.indices.refresh())
403 .then(() => dest.indices.get({index: 'index_to_mutate'}))
404 .then((index) => expect(index.index_to_mutate.settings.index.number_of_shards).to.be.equals('4'))
405 .then(() => done());
406 });
407
408 it('should return the original when the mutator does not apply', (done) => {
409 transfer.setMutators({index: [loadMutator(`${__dirname}/validMutators/index.js`)]});
410
411 source.indices.create({
412 index: 'index_not_to_mutate',
413 body: {settings: {number_of_shards: 4}}
414 })
415 .then(() => transfer.transferIndices('index_not_to_mutate'))
416 .then(() => dest.indices.refresh())
417 .then(() => dest.indices.get({index: 'index_not_to_mutate'}))
418 .then((index) => expect(index.index_not_to_mutate.settings.index.number_of_shards).to.be.equals('4'))
419 .then(() => done())
420 .catch(done);
421 });
422
423 it('should use index mutator to change index during transfer', (done) => {
424 transfer.setMutators({index: [loadMutator(`${__dirname}/validMutators/index.js`)]});
425
426 source.indices.create({
427 index: 'index_to_mutate',
428 body: {settings: {number_of_shards: 4}}
429 })
430 .then(() => transfer.transferIndices('index_to_mutate'))
431 .then(() => dest.indices.refresh())
432 .then(() => dest.indices.get({index: 'new_index_name'}))
433 .then((index) => {
434 expect(index.new_index_name.settings.index.number_of_shards).to.be.equals('4');
435 return dest.indices.get({index: 'index_to_mutate'}).catch((error) => {
436 expect(error.status).to.be.equals(404);
437 return 'not found';
438 });
439 })
440 .then((result) => expect(result).to.be.equals('not found'))
441 .then(() => done())
442 .catch(done);
443 });
444
445 it('should call mutator with arguments', (done) => {
446 const mutator = loadMutator(`${__dirname}/validMutators/indexWithArgs.js`);
447 mutator.arguments = {
448 name: 'creative',
449 target: 'index_to_mutate'
450 };
451
452 transfer.setMutators({index: [mutator]});
453
454 source.indices.create({
455 index: 'index_to_mutate',
456 body: {settings: {number_of_shards: 4}}
457 })
458 .then(() => transfer.transferIndices('index_to_mutate'))
459 .then(() => dest.indices.refresh())
460 .then(() => dest.indices.get({index: 'creative'}))
461 .then((index) => {
462 expect(index.creative.settings.index.number_of_shards).to.be.equals('4');
463 return dest.indices.get({index: 'index_to_mutate'}).catch((error) => {
464 expect(error.status).to.be.equals(404);
465 return 'not found';
466 });
467 })
468 .then((result) => expect(result).to.be.equals('not found'))
469 .then(() => done())
470 .catch(done);
471 });
472
473 it('should use a template mutator to change template during transfer', (done) => {
474 transfer.setMutators({template: [loadMutator(`${__dirname}/validMutators/template.js`)]});
475
476 source.indices.putTemplate({
477 name: 'test_template',
478 body: {template: 'template_this*'}
479 })
480 .then(() => transfer.transferTemplates('test_template'))
481 .then(() => dest.indices.getTemplate({name: 'test_template'}))
482 .then((template) => expect(template.test_template.index_patterns[0]).to.be.equals('template_that*'))
483 .then(() => done())
484 .catch(done);
485 });
486
487 it('should use a data mutator to change documents during transfer', (done) => {
488 transfer.setMutators({data: [loadMutator(`${__dirname}/validMutators/data.js`)]});
489
490 const srcIndex = 'something_1990-05-21';
491 const dstIndex = 'something_1990-05';
492 const type = 'sometype';
493
494 utils.createIndices(transfer, srcIndex, dstIndex)
495 .then(() => source.index({
496 index: srcIndex,
497 type: type,
498 body: {field: 'daata'}
499 }))
500 .then(() => source.indices.refresh())
501 .then(() => transfer.transferData(srcIndex, type))
502 .then(() => dest.indices.refresh())
503 .then(() => dest.search({index: 'something_1990*'}))
504 .then((document) => {
505 expect(document.hits.hits.length).to.be.equals(1);
506 expect(document.hits.hits[0]._index).to.be.equals('something_1990-05');
507 expect(document.hits.hits[0]._source.field).to.be.equals('daata');
508 })
509 .then(() => done())
510 .catch(done);
511 });
512
513 it('should use a data mutator to drop some documents during transfer', (done) => {
514 const mutator = loadMutator(`${__dirname}/validMutators/dropWithArgs.js`);
515 mutator.arguments = {
516 match: 'daata2'
517 };
518 transfer.setMutators({data: [mutator]});
519
520 const index = 'something_1990-05-21';
521 const type = 'sometype';
522
523 utils.createIndices(transfer, index, index)
524 .then(() => source.index({
525 index: index,
526 type: type,
527 body: {field: 'daata'}
528 }))
529 .then(() => source.index({
530 index: index,
531 type: type,
532 body: {field: 'daata2'}
533 }))
534 .then(() => source.indices.refresh())
535 .then(() => transfer.transferData(index, type))
536 .then(() => dest.indices.refresh())
537 .then(() => dest.search({index}))
538 .then((document) => {
539 expect(document.hits.hits.length).to.be.equals(1);
540 expect(document.hits.hits[0]._index).to.be.equals(index);
541 expect(document.hits.hits[0]._source.field).to.be.equals('daata');
542 })
543 .then(() => done())
544 .catch(done);
545 });
546});
\No newline at end of file