1 |
|
2 |
|
3 | const _ = require('lodash');
|
4 | const chai = require('chai');
|
5 | const expect = chai.expect;
|
6 | const asPromised = require('chai-as-promised');
|
7 | const Promise = require('bluebird');
|
8 | const TestConfig = require('../config');
|
9 | const Utils = require('../utils');
|
10 | const Mutators = require('../../app/services/mutators');
|
11 | const ObjectId = require('../../app/models/objectId');
|
12 | const createRedisClient = require('../../config/redis');
|
13 | const config = require('../../config/index');
|
14 | chai.use(asPromised);
|
15 |
|
16 | const log = config.log;
|
17 |
|
18 | Promise.longStackTraces();
|
19 | Promise.onPossiblyUnhandledRejection((error) => log.error('Likely error: ', error.stack));
|
20 |
|
21 | const ns = 'namespace';
|
22 | const id = 'id';
|
23 | const topLevelArguments = {
|
24 | first: 'this thing',
|
25 | second: 'other thing'
|
26 | };
|
27 | const specificArguments = {
|
28 | second: 'second thing',
|
29 | third: 'last thing'
|
30 | };
|
31 | const validateMutator = (mutator) => {
|
32 | expect(_.isFunction(mutator.predicate)).is.true;
|
33 | expect(_.isFunction(mutator.mutate)).is.true;
|
34 | };
|
35 |
|
36 | describe('mutators service', function () {
|
37 | this.timeout(5000);
|
38 |
|
39 | let redis = null;
|
40 | let mutators = null;
|
41 | let objectId = null;
|
42 | let utils = null;
|
43 |
|
44 | before((done) => {
|
45 | redis = createRedisClient(TestConfig.redis.host, TestConfig.redis.port);
|
46 | mutators = new Mutators(redis);
|
47 | utils = new Utils();
|
48 | done();
|
49 | });
|
50 |
|
51 | after((done) => {
|
52 | redis.flushdb().finally(() => done());
|
53 | });
|
54 |
|
55 | beforeEach((done) => {
|
56 | objectId = new ObjectId({namespace: ns, id: id});
|
57 | redis.flushdb().finally(() => done());
|
58 | });
|
59 |
|
60 | it('invalid id', (done) => {
|
61 | objectId.id = '~badId';
|
62 | mutators.add(objectId, 'dummySrc')
|
63 | .then(() => done('fail'))
|
64 | .catch((e) => expect(e.message).equals("Id must be string of 1-40 alphanumeric characters, given '~badId'"))
|
65 | .then(() => done());
|
66 | });
|
67 |
|
68 | it('invalid src type', (done) => {
|
69 | mutators.add(objectId, {})
|
70 | .then(() => done('fail'))
|
71 | .catch((e) => expect(e.message).equals('mutatorSrc must be string'))
|
72 | .then(() => done());
|
73 | });
|
74 |
|
75 | it('invalid javascript', (done) => {
|
76 | mutators.add(objectId, utils.loadFile(`${__dirname}/invalidMutators/notAJsFile`))
|
77 | .then(() => done('fail'))
|
78 | .catch((e) => expect(e.message).equals("Unable to load external module due to 'SyntaxError - Unexpected identifier'"))
|
79 | .then(() => done());
|
80 | });
|
81 |
|
82 | it('mutator missing type', (done) => {
|
83 | mutators.add(objectId, utils.loadFile(`${__dirname}/invalidMutators/noType.js`))
|
84 | .then(() => done('fail'))
|
85 | .catch((e) => expect(e.message).equals('Mutator type string not provided'))
|
86 | .then(() => done());
|
87 | }
|
88 | );
|
89 |
|
90 | it('mutator invalid type', (done) => {
|
91 | mutators.add(objectId, utils.loadFile(`${__dirname}/invalidMutators/invalidType.js`))
|
92 | .then(() => done('fail'))
|
93 | .catch((e) => expect(e.message).equals(`Mutator type 'wrong' not one of: [${Mutators.TYPES}]`))
|
94 | .then(() => done());
|
95 | });
|
96 |
|
97 | it('mutator missing predicate', (done) => {
|
98 | mutators.add(objectId, utils.loadFile(`${__dirname}/invalidMutators/noPredicate.js`))
|
99 | .then(() => done('fail'))
|
100 | .catch((e) => expect(e.message).equals('Mutator predicate() not provided'))
|
101 | .then(() => done());
|
102 | });
|
103 |
|
104 | it('mutator missing mutate', (done) => {
|
105 | mutators.add(objectId, utils.loadFile(`${__dirname}/invalidMutators/noMutate.js`))
|
106 | .then(() => done('fail'))
|
107 | .catch((e) => expect(e.message).equals('Mutator mutate() not provided'))
|
108 | .then(() => done());
|
109 | });
|
110 |
|
111 | it('get ids in empty namespace', (done) => {
|
112 | mutators.getIds(ns)
|
113 | .then((ids) => expect(ids).to.be.empty)
|
114 | .then(() => done());
|
115 | });
|
116 |
|
117 | it('basic crud', (done) => {
|
118 | mutators.add(objectId, utils.loadFile(`${__dirname}/validMutators/data.js`))
|
119 | .then(() => mutators.exists(objectId))
|
120 | .then((exists) => expect(exists).to.be.equals(1))
|
121 | .then(() => mutators.getIds(ns)
|
122 | .then((ids) => {
|
123 | expect(ids).to.have.length(1);
|
124 | expect(ids[0]).to.be.equals('id');
|
125 | })
|
126 | )
|
127 | .then(() => mutators.remove(objectId))
|
128 | .then(() => mutators.exists(objectId))
|
129 | .then((exists) => expect(exists).to.be.equals(0))
|
130 | .then(() => mutators.getIds(ns))
|
131 | .then((ids) => expect(ids).to.be.empty)
|
132 | .then(() => done());
|
133 | });
|
134 |
|
135 | it('add twice', (done) => {
|
136 | mutators.add(objectId, utils.loadFile(`${__dirname}/validMutators/data.js`))
|
137 | .then(() => mutators.exists(objectId))
|
138 | .then((exists) => expect(exists).to.be.equals(1))
|
139 | .then(() => mutators.add(objectId, utils.loadFile(`${__dirname}/validMutators/data.js`)))
|
140 | .catch((e) => expect(e.message).to.be.equals('Mutator \'namespace/id\' exists, delete first.'))
|
141 | .then(() => done());
|
142 | });
|
143 |
|
144 | it('load a specific mutator with top-level args', (done) => {
|
145 | mutators.add(objectId, utils.loadFile(`${__dirname}/validMutators/data.js`))
|
146 | .then(() => mutators.load(ns, {
|
147 | actions: [
|
148 | {id: id}
|
149 | ],
|
150 | arguments: topLevelArguments
|
151 | }))
|
152 | .then((loadedMutators) => {
|
153 | expect(_.size(loadedMutators)).to.be.equals(1);
|
154 | expect(loadedMutators['data']).to.have.length(1);
|
155 |
|
156 | const data = loadedMutators['data'][0];
|
157 | expect(data.type).to.be.equals('data');
|
158 | expect(data.arguments).to.be.equals(topLevelArguments);
|
159 | validateMutator(data);
|
160 | done();
|
161 | })
|
162 | .catch(done);
|
163 | });
|
164 |
|
165 | it('load a specific mutator with arg overrides', (done) => {
|
166 | mutators.add(objectId, utils.loadFile(`${__dirname}/validMutators/data.js`))
|
167 | .then(() => mutators.load(ns, {
|
168 | actions: [
|
169 | {
|
170 | id: id,
|
171 | arguments: specificArguments
|
172 | }
|
173 | ],
|
174 | arguments: topLevelArguments
|
175 | }))
|
176 | .then((loadedMutators) => {
|
177 | expect(_.size(loadedMutators)).to.be.equals(1);
|
178 | expect(loadedMutators['data']).to.have.length(1);
|
179 |
|
180 | const data = loadedMutators['data'][0];
|
181 | expect(data.type).to.be.equals('data');
|
182 | expect(data.arguments).to.be.equals(specificArguments);
|
183 | validateMutator(data);
|
184 | done();
|
185 | })
|
186 | .catch(done);
|
187 | });
|
188 |
|
189 | it('load a multiple mutators in different namespaces', (done) => {
|
190 | const objectId1 = new ObjectId({namespace: 'task', id: id});
|
191 | const objectId2 = new ObjectId({namespace: 'global', id: id});
|
192 | const objectId3 = new ObjectId({namespace: 'othernamespace', id: id});
|
193 | const objectId4 = new ObjectId({namespace: 'othernamespace', id: 'other'});
|
194 |
|
195 | mutators.add(objectId1, utils.loadFile(`${__dirname}/validMutators/data.js`))
|
196 | .then(() => mutators.add(objectId2, utils.loadFile(`${__dirname}/validMutators/index.js`)))
|
197 | .then(() => mutators.add(objectId3, utils.loadFile(`${__dirname}/validMutators/indexWithArgs.js`)))
|
198 | .then(() => mutators.add(objectId4, utils.loadFile(`${__dirname}/validMutators/template.js`)))
|
199 | .then(() => mutators.load('task', {
|
200 | actions: [
|
201 | {
|
202 | namespace: objectId3.namespace,
|
203 | id: objectId3.id,
|
204 | arguments: specificArguments
|
205 | },
|
206 | {
|
207 | namespace: objectId2.namespace,
|
208 | id: objectId2.id
|
209 | },
|
210 | {
|
211 | id: objectId1.id,
|
212 | arguments: specificArguments
|
213 | },
|
214 | {
|
215 | namespace: objectId4.namespace,
|
216 | id: objectId4.id
|
217 | }
|
218 | ],
|
219 | arguments: topLevelArguments
|
220 | }))
|
221 | .then((loadedMutators) => {
|
222 | expect(_.size(loadedMutators)).to.be.equals(3);
|
223 | expect(loadedMutators['data']).to.have.length(1);
|
224 | expect(loadedMutators['index']).to.have.length(2);
|
225 | expect(loadedMutators['template']).to.have.length(1);
|
226 |
|
227 | const data = loadedMutators['data'][0];
|
228 | expect(data.type).to.be.equals('data');
|
229 | expect(data.arguments).to.be.equals(specificArguments);
|
230 | validateMutator(data);
|
231 |
|
232 | const index1 = loadedMutators['index'][0];
|
233 | expect(index1.type).to.be.equals('index');
|
234 | expect(index1.arguments).to.be.equals(specificArguments);
|
235 | validateMutator(index1);
|
236 |
|
237 | const index2 = loadedMutators['index'][1];
|
238 | expect(index2.type).to.be.equals('index');
|
239 | expect(index2.arguments).to.be.equals(topLevelArguments);
|
240 | validateMutator(index2);
|
241 |
|
242 | const template = loadedMutators['template'][0];
|
243 | expect(template.type).to.be.equals('template');
|
244 | expect(template.arguments).to.be.equals(topLevelArguments);
|
245 | validateMutator(template);
|
246 | done();
|
247 | })
|
248 | .catch(done);
|
249 | });
|
250 | });
|