UNPKG

14.7 kBJavaScriptView Raw
1var chai = require('chai'),
2 spies = require('chai-spies'),
3 AWS = require('aws-sdk'),
4 _= require('underscore'),
5 dyngo= require('../index.js');
6
7chai.use(spies);
8
9var should= chai.should(),
10 assert= chai.assert;
11
12const noerr= function (done)
13 {
14 return function (err)
15 {
16 should.not.exist(err);
17 done();
18 };
19 },
20 accept= function (code,done)
21 {
22 return function (err)
23 {
24 if (err.code==code)
25 done();
26 else
27 done(err);
28 };
29 };
30
31describe('transactions',function ()
32{
33 var db;
34
35 before(function (done)
36 {
37 dyngo({ dynamo: { endpoint: new AWS.Endpoint('http://localhost:8000') }, hints: false },
38 function (err,_db)
39 {
40 db= _db;
41
42 db.ensureTransactionTable().success(done).error(done);
43 });
44 });
45
46 beforeEach(function (done)
47 {
48 db.test.remove().success(done)
49 .error(done);
50 });
51
52 describe('insert',function ()
53 {
54
55 it('If transaction A inserts a new object transaction B cannot see it while not committed (transient)',
56 function (done)
57 {
58 db.transaction().transaction(function (A)
59 {
60 db.transaction().transaction(function (B)
61 {
62 A.test.save({ _id: 'transient' }).success(function ()
63 {
64 B.test.findOne({ _id: 'transient' })
65 .result(should.not.exist)
66 .error(accept('notfound',done));
67 }).error(done);
68 }).error(done);
69 }).error(done);
70 });
71
72 it('If transaction A inserts a new object, while there was a transient object already present, transaction B cannot see it while not committed (transient)',
73 function (done)
74 {
75 db.transaction().transaction(function (A)
76 {
77 db.transaction().transaction(function (B)
78 {
79 A.test.save({ _id: 'transient2' }).success(function ()
80 {
81 A.test.save({ _id: 'transient2' }).success(function ()
82 {
83 B.test.findOne({ _id: 'transient2' })
84 .result(should.not.exist)
85 .error(accept('notfound',done));
86 }).error(done);
87 }).error(done);
88 }).error(done);
89 }).error(done);
90 });
91
92 it('If transaction A inserts a new object, and commit, transaction B can see the new object',
93 function (done)
94 {
95 db.transaction().transaction(function (A)
96 {
97 db.transaction().transaction(function (B)
98 {
99 A.test.save({ _id: 'transient3' }).success(function ()
100 {
101 A.commit().committed(function ()
102 {
103 B.test.findOne({ _id: 'transient3' })
104 .result(function (r)
105 {
106 should.exist(r);
107 r._id.should.equal('transient3');
108 done();
109 })
110 .error(done);
111 }).error(done);
112 }).error(done);
113 }).error(done);
114 }).error(done);
115 });
116
117 });
118
119 describe('delete',function ()
120 {
121
122 it('If transaction A deletes an object and does not commit, transaction B can see the object, but transaction A can\'t',
123 function (done)
124 {
125 db.test.save({ _id: 'delete1' }).success(function ()
126 {
127 db.transaction().transaction(function (A)
128 {
129 db.transaction().transaction(function (B)
130 {
131 A.test.remove({ _id: 'delete1' }).success(function ()
132 {
133 B.test.findOne({ _id: 'delete1' })
134 .result(function (r)
135 {
136 should.exist(r);
137 r._id.should.equal('delete1');
138
139 A.test.findOne({ _id: 'delete1' })
140 .result(should.not.exist)
141 .error(accept('notfound',done));
142 })
143 .error(done);
144
145 }).error(done);
146 }).error(done);
147 }).error(done);
148 }).error(done);
149 });
150
151 it('If transaction A deletes an object and commit, transaction B cannot see the object',
152 function (done)
153 {
154 db.test.save({ _id: 'delete2' }).success(function ()
155 {
156 db.transaction().transaction(function (A)
157 {
158 db.transaction().transaction(function (B)
159 {
160 A.test.remove({ _id: 'delete2' }).success(function ()
161 {
162 A.commit().committed(function ()
163 {
164 B.test.findOne({ _id: 'delete2' })
165 .result(should.not.exist)
166 .error(accept('notfound',done));
167 }).error(done);
168 }).error(done);
169 }).error(done);
170 }).error(done);
171 }).error(done);
172 });
173
174 });
175
176 describe('update',function ()
177 {
178
179 it('If transaction A updates an object and does not commit, transaction B still see the old version of the object, when A commits, B sees the new version',
180 function (done)
181 {
182 var obj= { _id: 'update1', n: 0 };
183
184 db.test.save(obj).success(function ()
185 {
186 db.transaction().transaction(function (A)
187 {
188 db.transaction().transaction(function (B)
189 {
190 obj.name= 'Update2';
191 obj.n++;
192
193 A.test.save(obj).success(function ()
194 {
195 B.test.findOne({ _id: 'update1' })
196 .result(function (copy)
197 {
198 should.not.exist(copy.name);
199 copy.n.should.equal(0);
200
201 A.test.findOne({ _id: 'update1' })
202 .result(function (copy)
203 {
204 copy.name.should.equal('Update2');
205 copy.n.should.equal(1);
206
207 A.commit().committed(function ()
208 {
209 B.test.findOne({ _id: 'update1' })
210 .result(function (copy)
211 {
212 copy.name.should.equal('Update2');
213 copy.n.should.equal(1);
214
215 done();
216 })
217 .error(done);
218 })
219 .error(done);
220 })
221 .error(done);
222 })
223 .error(done);
224 }).error(done);
225 }).error(done);
226 }).error(done);
227 }).error(done);
228 });
229
230 });
231
232 describe('query',function ()
233 {
234 it('If transaction A inserts an item without committing, transaction B should not see the inserted item until commited',
235 function (done)
236 {
237 var items= _.collect(_.range(10),function (n) { return { _id: 'item'+n, n: n+1 } });
238
239 db.test.save(items).success(function ()
240 {
241 db.transaction().transaction(function (A)
242 {
243 db.transaction().transaction(function (B)
244 {
245 A.test.save({ _id: 'itemS', n: 0 }).success(function ()
246 {
247 B.test.find().sort({ n: 1 }).limit(3)
248 .results(function (objs)
249 {
250 objs[0].n.should.equal(1);
251 objs.length.should.equal(3);
252 })
253 .error(done)
254 .end(function ()
255 {
256 A.test.find().sort({ n: 1 }).limit(3)
257 .results(function (objs)
258 {
259 objs[0].n.should.equal(0);
260 objs.length.should.equal(3);
261 })
262 .error(done)
263 .end(function ()
264 {
265 A.commit().committed(function ()
266 {
267 B.test.find().sort({ n: 1 }).limit(3)
268 .results(function (objs)
269 {
270 objs[0].n.should.equal(0);
271 objs.length.should.equal(3);
272 })
273 .error(done)
274 .end(done);
275 });
276 });
277 });
278 }).error(done);
279 });
280 });
281 });
282 });
283 });
284
285 describe('concurrency',function ()
286 {
287 it('rollsback competing transaction',
288 function (done)
289 {
290 db.test.save({ _id: 'hot', name: 'Hot' }).success(function ()
291 {
292 db.transaction().transaction(function (A)
293 {
294 db.transaction().transaction(function (B)
295 {
296 A.test.findOne({ _id: 'hot' })
297 .result(function (hotA)
298 {
299 hotA.name= 'HotA';
300
301 B.test.findOne({ _id: 'hot' })
302 .result(function (hotB)
303 {
304 hotB.name= 'HotB';
305
306 A.test.save(hotA).success(function ()
307 {
308 B.test.save(hotB).success(function ()
309 {
310 var committedA= chai.spy();
311
312 A.commit()
313 .committed(committedA)
314 .error(function (err)
315 {
316 if (err.code=='rolledback')
317 B.commit().committed(function ()
318 {
319 db.test.findOne({ _id: 'hot' })
320 .result(function (obj)
321 {
322 committedA.should.not.have.been.called();
323 obj.name.should.equal('HotB');
324 done();
325 })
326 .error(done);
327 })
328 .error(done);
329 else
330 done(err);
331 });
332 })
333 .error(done);
334 })
335 .error(done);
336 })
337 .error(done);
338 })
339 .error(done);
340
341 }).error(done);
342 }).error(done);
343 }).error(done);
344 });
345 });
346});