UNPKG

47.4 kBtext/coffeescriptView Raw
1esm_tests = (ESM) ->
2 ns = "default"
3
4 describe 'construction', ->
5 describe 'namespace operations', ->
6 it '#list_namespaces should list all namespaces', ->
7 ns1 = "namespace1"
8 ns2 = "namespace2"
9 esm = new_esm(ESM) #pass knex as it might be needed
10 bb.all([esm.destroy(ns1), esm.destroy(ns2)])
11 .then( ->
12 esm.list_namespaces()
13 )
14 .then( (list) ->
15 list.should.not.include ns1
16 list.should.not.include ns2
17 )
18 .then( -> bb.all([esm.initialize(ns1), esm.initialize(ns2)]) )
19 .then( ->
20 esm.list_namespaces()
21 )
22 .then( (list) ->
23 list.should.include ns1
24 list.should.include ns2
25 )
26
27 it 'should initialize namespace', ->
28 namespace = "namespace"
29 esm = new_esm(ESM)
30 esm.destroy(namespace)
31 .then( -> esm.exists(namespace))
32 .then( (exist) -> exist.should.equal false)
33 .then( -> esm.initialize(namespace))
34 .then( -> esm.exists(namespace))
35 .then( (exist) -> exist.should.equal true)
36
37 it 'should sucessfully initialize namespace with default', ->
38 #based on an error where default is a reserved name in postgres
39 namespace = "new_namespace"
40 esm = new_esm(ESM)
41 esm.destroy(namespace)
42 .then( -> esm.exists(namespace))
43 .then( (exist) -> exist.should.equal false)
44 .then( -> esm.initialize(namespace))
45 .then( -> esm.exists(namespace))
46 .then( (exist) -> exist.should.equal true)
47
48 it 'should start with no events', ->
49 namespace = "namespace"
50 esm = new_esm(ESM)
51 esm.destroy(namespace)
52 .then( -> esm.initialize(namespace))
53 .then( -> esm.count_events(namespace))
54 .then( (count) ->
55 count.should.equal 0
56 )
57
58 it 'should not error out or remove events if re-initialized', ->
59 namespace = "namespace"
60 esm = new_esm(ESM)
61 esm.destroy()
62 .then( -> esm.initialize(namespace))
63 .then( -> esm.add_event(namespace, 'p','a','t'))
64 .then( -> esm.count_events(namespace))
65 .then( (count) -> count.should.equal 1)
66 .then( -> esm.initialize(namespace))
67 .then( -> esm.count_events(namespace))
68 .then( (count) -> count.should.equal 1)
69
70 it 'should create resources for ESM namespace', ->
71 ns1 = "namespace1"
72 ns2 = "namespace2"
73 esm = new_esm(ESM) #pass knex as it might be needed
74 bb.all([esm.destroy(ns1), esm.destroy(ns2)])
75 .then( -> bb.all([esm.initialize(ns1), esm.initialize(ns2)]) )
76 .then( ->
77 bb.all([
78 esm.add_event(ns1, 'p','a','t')
79 esm.add_event(ns1, 'p1','a','t')
80
81 esm.add_event(ns2, 'p2','a','t')
82 ])
83 )
84 .then( ->
85 bb.all([esm.count_events(ns1), esm.count_events(ns2) ])
86 )
87 .spread((c1,c2) ->
88 c1.should.equal 2
89 c2.should.equal 1
90 )
91
92 it 'should destroy should not break if resource does not exist', ->
93 namespace = "namespace"
94 esm = new_esm(ESM)
95 esm.destroy(namespace)
96 .then( -> esm.destroy(namespace))
97
98 describe 'recommendation methods', ->
99
100 describe '#thing_neighbourhood', ->
101
102 it 'should limit its search to event number of neighbourhood_search_size', ->
103 init_esm(ESM, ns)
104 .then (esm) ->
105 bb.all([
106 esm.add_event(ns,'p1','view','t1', created_at: today)
107 esm.add_event(ns,'p2','view','t1', created_at: yesterday)
108
109 esm.add_event(ns,'p1','view','t2', expires_at: tomorrow)
110 esm.add_event(ns,'p2','view','t3', expires_at: tomorrow)
111 ])
112 .then( ->
113 esm.thing_neighbourhood(ns, 't1', ['view'], {neighbourhood_search_size: 1})
114 )
115 .then( (things) ->
116 things.length.should.equal 1
117 things[0].thing.should.equal 't2'
118 )
119 .then( ->
120 esm.thing_neighbourhood(ns, 't1', ['view'], {neighbourhood_search_size: 2})
121 )
122 .then( (things) ->
123 things.length.should.equal 2
124 )
125
126 it 'should return a list of objects with thing, max_created_at, max_expires_at', ->
127 init_esm(ESM, ns)
128 .then (esm) ->
129 bb.all([
130 esm.add_event(ns,'p1','view','t1', expires_at: tomorrow)
131 esm.add_event(ns,'p1','view','t2', expires_at: tomorrow)
132 ])
133 .then( ->
134 esm.thing_neighbourhood(ns, 't1', ['view'])
135 )
136 .then( (things) ->
137 things.length.should.equal 1
138 things[0].thing.should.equal 't2'
139 )
140
141 it 'should return a list of people who actioned thing', ->
142 init_esm(ESM, ns)
143 .then (esm) ->
144 bb.all([
145 esm.add_event(ns,'p1','view','t1', expires_at: tomorrow)
146 esm.add_event(ns,'p1','view','t2', expires_at: tomorrow)
147 esm.add_event(ns,'p2','view','t1', expires_at: tomorrow)
148 esm.add_event(ns,'p2','view','t2', expires_at: tomorrow)
149 esm.add_event(ns,'p2','view','t3', expires_at: tomorrow)
150 ])
151 .then( ->
152 esm.thing_neighbourhood(ns, 't1', ['view'])
153 )
154 .then( (things) ->
155 things.length.should.equal 2
156 things[0].people.length.should.equal 2
157 things[0].people.should.include 'p1'
158 things[0].people.should.include 'p2'
159 )
160
161 it 'should return a list of unique people', ->
162 init_esm(ESM, ns)
163 .then (esm) ->
164 bb.all([
165 esm.add_event(ns,'p1','view','t1', expires_at: tomorrow)
166 esm.add_event(ns,'p1','view','t2', expires_at: tomorrow)
167 esm.add_event(ns,'p2','view','t1', expires_at: tomorrow)
168 esm.add_event(ns,'p2','view','t2', expires_at: tomorrow)
169 esm.add_event(ns,'p2','view','t3', expires_at: tomorrow)
170 ])
171 .then( ->
172 esm.thing_neighbourhood(ns, 't1', ['view'])
173 )
174 .then( (things) ->
175 things.length.should.equal 2
176 things[0].people.length.should.equal 2
177 things[0].people.should.include 'p1'
178 things[0].people.should.include 'p2'
179 )
180 it 'should not list things twice', ->
181 init_esm(ESM, ns)
182 .then (esm) ->
183 bb.all([
184 esm.add_event(ns,'p1','v','a', expires_at: tomorrow),
185 esm.add_event(ns,'p1','b','b', expires_at: tomorrow),
186 esm.add_event(ns,'p1','v','b', expires_at: tomorrow),
187 ])
188 .then(-> esm.thing_neighbourhood(ns, 'a', ['v','b']))
189 .then((neighbourhood) ->
190 neighbourhood.length.should.equal 1
191 neighbourhood[0].thing.should.equal 'b'
192 )
193
194 it 'should list recommendable things', ->
195 init_esm(ESM, ns)
196 .then (esm) ->
197 bb.all([
198 esm.add_event(ns,'p1','v','a', expires_at: tomorrow),
199 esm.add_event(ns,'p1','v','b', expires_at: tomorrow)
200 esm.add_event(ns,'p1','v','c', expires_at: yesterday)
201 esm.add_event(ns,'p1','v','d')
202 ])
203 .then(-> esm.thing_neighbourhood(ns, 'a', ['v']))
204 .then((neighbourhood) ->
205 neighbourhood.length.should.equal 1
206 neighbourhood[0].thing.should.equal 'b'
207 )
208
209 it 'should order the things by how many people actioned it', ->
210 init_esm(ESM, ns)
211 .then (esm) ->
212 bb.all([
213 esm.add_event(ns,'p1','v','a', created_at: last_week, expires_at: tomorrow),
214 esm.add_event(ns,'p2','v','a', created_at: yesterday, expires_at: tomorrow),
215 esm.add_event(ns,'p3','v','a', created_at: yesterday, expires_at: tomorrow),
216 esm.add_event(ns,'p1','v','b', expires_at: tomorrow),
217 esm.add_event(ns,'p2','v','c', expires_at: tomorrow)
218 esm.add_event(ns,'p3','v','c', expires_at: tomorrow)
219 ])
220 .then(-> esm.thing_neighbourhood(ns, 'a', ['v']))
221 .then((neighbourhood) ->
222 neighbourhood.length.should.equal 2
223 neighbourhood[0].thing.should.equal 'c'
224 neighbourhood[0].people.length.should.equal 2
225 neighbourhood[1].thing.should.equal 'b'
226 neighbourhood[1].people.length.should.equal 1
227 )
228
229 it 'should return the last_expires_at and last_actioned_at', ->
230 init_esm(ESM, ns)
231 .then (esm) ->
232 bb.all([
233 esm.add_event(ns,'p1','v','a')
234 esm.add_event(ns,'p2','v','a')
235 esm.add_event(ns,'p3','v','a')
236 esm.add_event(ns,'p1','v','b', created_at: yesterday, expires_at: tomorrow),
237 esm.add_event(ns,'p2','v','b', created_at: today, expires_at: yesterday),
238 esm.add_event(ns,'p3','v','b', created_at: last_week)
239 ])
240 .then(-> esm.thing_neighbourhood(ns, 'a', ['v']))
241 .then((neighbourhood) ->
242 neighbourhood.length.should.equal 1
243 neighbourhood[0].thing.should.equal 'b'
244 neighbourhood[0].last_actioned_at.getTime().should.equal today.toDate().getTime()
245 neighbourhood[0].last_expires_at.getTime().should.equal tomorrow.toDate().getTime()
246 )
247
248 it 'should return a unique list of the people that actioned the things (and ordered by number of people)', ->
249 init_esm(ESM, ns)
250 .then (esm) ->
251 bb.all([
252 esm.add_event(ns,'p1','v','a')
253 esm.add_event(ns,'p2','v','a')
254 esm.add_event(ns,'p1','v','b', expires_at: tomorrow),
255 esm.add_event(ns,'p1','x','b', expires_at: tomorrow),
256 esm.add_event(ns,'p2','v','b', expires_at: tomorrow),
257 esm.add_event(ns,'p1','v','c', expires_at: tomorrow),
258 esm.add_event(ns,'p3','v','c')
259 ])
260 .then(-> esm.thing_neighbourhood(ns, 'a', ['v', 'x']))
261 .then((neighbourhood) ->
262 neighbourhood.length.should.equal 2
263 neighbourhood[0].thing.should.equal 'b'
264 neighbourhood[1].thing.should.equal 'c'
265
266 neighbourhood[0].people.length.should.equal 2
267 neighbourhood[0].people.should.include 'p1'
268 neighbourhood[0].people.should.include 'p2'
269
270 neighbourhood[1].people.length.should.equal 1
271 neighbourhood[1].people.should.include 'p1'
272 )
273
274
275 describe '#calculate_similarities_from_thing', ->
276 it 'more similar histories should be greater', ->
277 init_esm(ESM, ns)
278 .then (esm) ->
279 bb.all([
280 esm.add_event(ns,'p1','a','t1')
281 esm.add_event(ns,'p2','a','t1')
282
283 esm.add_event(ns,'p1','a','t2')
284 esm.add_event(ns,'p2','a','t2')
285
286 esm.add_event(ns,'p2','a','t3')
287 ])
288 .then( -> esm.calculate_similarities_from_thing(ns, 't1',['t2','t3'],{a: 1}))
289 .then( (similarities) ->
290 similarities['t3'].should.be.lessThan(similarities['t2'])
291 )
292
293 describe '#person_neighbourhood' , ->
294 it 'should return a list of similar people', ->
295 init_esm(ESM, ns)
296 .then (esm) ->
297 bb.all([
298 esm.add_event(ns,'p1','view','t1', expires_at: tomorrow)
299 esm.add_event(ns,'p2','view','t1', expires_at: tomorrow)
300 esm.add_event(ns,'p2','buy','t1', expires_at: tomorrow)
301 esm.add_event(ns,'p1','buy','t1', expires_at: tomorrow)
302 ])
303 .then( ->
304 esm.person_neighbourhood(ns, 'p1', ['view', 'buy'])
305 )
306 .then( (people) ->
307 people.length.should.equal 1
308 )
309
310 it 'should not return people who have no unexpired events (i.e. potential recommendations) or in actions', ->
311 init_esm(ESM, ns)
312 .then (esm) ->
313 bb.all([
314 esm.add_event(ns,'p1','view','t1', expires_at: tomorrow)
315 esm.add_event(ns,'p2','view','t1', expires_at: tomorrow)
316 esm.add_event(ns,'p3','view','t1', expires_at: yesterday)
317 esm.add_event(ns,'p4','view','t1')
318 esm.add_event(ns,'p5','view','t1')
319 esm.add_event(ns,'p5','likes','t2', expires_at: tomorrow)
320 ])
321 .then( ->
322 esm.person_neighbourhood(ns, 'p1', ['view','buy'])
323 )
324 .then( (people) ->
325 people.length.should.equal 1
326 )
327
328 it 'should not return more people than limited', ->
329 init_esm(ESM, ns)
330 .then (esm) ->
331 bb.all([
332 esm.add_event(ns,'p1','view','t1', expires_at: tomorrow)
333 esm.add_event(ns,'p2','view','t1', expires_at: tomorrow)
334 esm.add_event(ns,'p3','view','t1', expires_at: tomorrow)
335 esm.add_event(ns,'p4','view','t1', expires_at: tomorrow)
336 ])
337 .then( ->
338 esm.person_neighbourhood(ns, 'p1', ['view','buy'], {neighbourhood_size: 1})
339 )
340 .then( (people) ->
341 people.length.should.equal 1
342 esm.person_neighbourhood(ns, 'p1', ['view','buy'], {neighbourhood_size: 2})
343 )
344 .then( (people) ->
345 people.length.should.equal 2
346 )
347
348 it 'should not return the given person', ->
349 @timeout(360000)
350 init_esm(ESM, ns)
351 .then (esm) ->
352 bb.all([
353 esm.add_event(ns,'p1','view','t1', expires_at: tomorrow)
354 ])
355 .then( ->
356 esm.person_neighbourhood(ns, 'p1', ['view'])
357 )
358 .then( (people) ->
359 people.length.should.equal 0
360 )
361
362 it 'should only return people related via given actions', ->
363 init_esm(ESM, ns)
364 .then (esm) ->
365 bb.all([
366 esm.add_event(ns,'p1','view','t1', expires_at: tomorrow)
367 esm.add_event(ns,'p2','buy','t1', expires_at: tomorrow)
368 ])
369 .then( ->
370 esm.person_neighbourhood(ns, 'p1', ['buy'])
371 )
372 .then( (people) ->
373 people.length.should.equal 0
374 )
375 .then( ->
376 esm.person_neighbourhood(ns, 'p1', ['view'])
377 )
378 .then( (people) ->
379 people.length.should.equal 0
380 )
381
382 it 'should return people with different actions on the same item', ->
383 init_esm(ESM, ns)
384 .then (esm) ->
385 bb.all([
386 esm.add_event(ns,'p1','view','t1', created_at: yesterday, expires_at: tomorrow)
387 esm.add_event(ns,'p1','view','t2', created_at: today, expires_at: tomorrow)
388
389 esm.add_event(ns,'p2','view','t1', expires_at: tomorrow)
390 esm.add_event(ns,'p3', 'buy','t2', expires_at: tomorrow)
391 ])
392 .then( ->
393 esm.person_neighbourhood(ns, 'p1', ['view', 'buy'])
394 )
395 .then( (people) ->
396 people.length.should.equal 2
397 people.should.contain 'p3'
398 people.should.contain 'p2'
399 )
400
401 it 'should return people ordered by the similar persons most recent date', ->
402 init_esm(ESM, ns)
403 .then (esm) ->
404 bb.all([
405 esm.add_event(ns,'p1','view','t1', expires_at: tomorrow)
406 esm.add_event(ns,'p2','view','t1', expires_at: tomorrow)
407 ])
408 .then( ->
409 esm.person_neighbourhood(ns, 'p1', ['view','buy'])
410 )
411 .then( (people) ->
412 people.length.should.equal 1
413 people[0].should.equal 'p2'
414 )
415
416 it 'should find similar people across actions', ->
417 init_esm(ESM, ns)
418 .then (esm) ->
419 bb.all([
420 esm.add_event(ns, 'p1','view','a'),
421 esm.add_event(ns, 'p1','view','b'),
422 #p2 is closer to p1, but theie recommendation was 2 days ago. It should still be included
423 esm.add_event(ns, 'p2','view','a'),
424 esm.add_event(ns, 'p2','view','b'),
425 esm.add_event(ns, 'p2','buy','x', created_at: moment().subtract(2, 'days'), expires_at: tomorrow),
426
427 esm.add_event(ns, 'p3','view','a'),
428 esm.add_event(ns, 'p3','buy','l', created_at: moment().subtract(3, 'hours'), expires_at: tomorrow),
429 esm.add_event(ns, 'p3','buy','m', created_at: moment().subtract(2, 'hours'), expires_at: tomorrow),
430 esm.add_event(ns, 'p3','buy','n', created_at: moment().subtract(1, 'hours'), expires_at: tomorrow)
431 ])
432 .then(-> esm.person_neighbourhood(ns, 'p1', ['buy', 'view']))
433 .then((people) ->
434 people.length.should.equal 2
435 )
436
437 it 'should be able to set current_datetime', ->
438 init_esm(ESM, ns)
439 .then (esm) ->
440 bb.all([
441 esm.add_event(ns, 'p1','view','a', created_at: moment().subtract(3, 'days')),
442 esm.add_event(ns, 'p1','view','b', created_at: moment().subtract(1, 'days')),
443 #p2 is closer to p1, but theie recommendation was 2 days ago. It should still be included
444 esm.add_event(ns, 'p2','view','a', created_at: moment().subtract(3, 'days'), expires_at: tomorrow),
445
446 esm.add_event(ns, 'p3','view','b', created_at: moment().subtract(3, 'days'), expires_at: tomorrow)
447 ])
448 .then(->
449 esm.person_neighbourhood(ns, 'p1', ['view'])
450 )
451 .then((people) ->
452 people.length.should.equal 2
453 esm.person_neighbourhood(ns, 'p1', ['view'], current_datetime: moment().subtract(2, 'days'))
454 )
455 .then((people) ->
456 people.length.should.equal 1
457 )
458
459 describe '#calculate_similarities_from_person', ->
460 it 'handle weights of 0 and people with no hisotry, and people with no similar history', ->
461 init_esm(ESM, ns)
462 .then (esm) ->
463 bb.all([
464 esm.add_event(ns,'p1','a','t1')
465 esm.add_event(ns,'p2','a','t1')
466 esm.add_event(ns,'p4','a','t2')
467 ])
468 .then( -> esm.calculate_similarities_from_person(ns, 'p1',['p2','p3', 'p4'],{a: 0}))
469 .then( (similarities) ->
470 similarities['p2'].should.equal 0
471 similarities['p3'].should.equal 0
472 similarities['p4'].should.equal 0
473 )
474
475 it 'more similar histories should be greater', ->
476 init_esm(ESM, ns)
477 .then (esm) ->
478 bb.all([
479 esm.add_event(ns,'p1','a','t1')
480 esm.add_event(ns,'p1','a','t2')
481
482 esm.add_event(ns,'p2','a','t1')
483 esm.add_event(ns,'p2','a','t2')
484
485 esm.add_event(ns,'p3','a','t1')
486 esm.add_event(ns,'p3','a','t3')
487 ])
488 .then( -> esm.calculate_similarities_from_person(ns, 'p1',['p2','p3'],{a: 1}))
489 .then( (similarities) ->
490 similarities['p3'].should.be.lessThan(similarities['p2'])
491 )
492
493 it 'should weight the actions', ->
494 init_esm(ESM, ns)
495 .then (esm) ->
496 bb.all([
497 esm.add_event(ns,'p1','view','t1')
498 esm.add_event(ns,'p1','buy','t2')
499
500 esm.add_event(ns,'p2','view','t1')
501
502 esm.add_event(ns,'p3','buy','t2')
503 ])
504 .then( -> esm.calculate_similarities_from_person(ns, 'p1',['p2','p3'],{view: 1, buy: 5}))
505 .then( (similarities) ->
506 similarities['p3'].should.be.greaterThan(similarities['p2'])
507 )
508
509 it 'should limit similarity measure on similarity_search_size (ordered by created_at)', ->
510 init_esm(ESM, ns)
511 .then (esm) ->
512 bb.all([
513 esm.add_event(ns,'p1','a','t1', created_at: today)
514
515 esm.add_event(ns,'p2','a','t3', created_at: today)
516 esm.add_event(ns,'p2','a','t1', created_at: yesterday)
517 ])
518 .then( -> esm.calculate_similarities_from_person(ns, 'p1',['p2'], {a: 1}, {similarity_search_size: 1}))
519 .then( (similarities) ->
520 similarities['p2'].should.equal 0
521 )
522 .then( -> esm.calculate_similarities_from_person(ns, 'p1',['p2'], {a: 1}, {similarity_search_size: 2}))
523 .then( (similarities) ->
524 similarities['p2'].should.not.equal 0
525 )
526
527 it 'should not limit similarity measure similarity_search_size for non selected actions', ->
528 init_esm(ESM, ns)
529 .then (esm) ->
530 bb.all([
531 esm.add_event(ns,'p1','a','t1', created_at: today)
532
533 esm.add_event(ns,'p2','b','t3', created_at: today)
534 esm.add_event(ns,'p2','a','t1', created_at: yesterday)
535 ])
536 .then( -> esm.calculate_similarities_from_person(ns, 'p1',['p2'], {a: 1}, {similarity_search_size: 1}))
537 .then( (similarities) ->
538 similarities['p2'].should.not.equal 0
539 )
540
541 it 'should handle multiple actions', ->
542 #example taken from http://infolab.stanford.edu/~ullman/mmds/ch9.pdf
543 init_esm(ESM, ns)
544 .then (esm) ->
545 bb.all([
546 esm.add_event(ns,'A','r4','HP1')
547 esm.add_event(ns,'A','r5','TW')
548 esm.add_event(ns,'A','r1','SW1')
549
550 esm.add_event(ns,'B','r5','HP1')
551 esm.add_event(ns,'B','r5','HP2')
552 esm.add_event(ns,'B','r4','HP3')
553
554 esm.add_event(ns,'C','r2','TW')
555 esm.add_event(ns,'C','r4','SW1')
556 esm.add_event(ns,'C','r5','SW2')
557 ])
558 .then( -> esm.calculate_similarities_from_person(ns, 'A',['B','C'], {r1: -2, r2: -1, r3: 0, r4: 1, r5: 2}))
559 .then( (similarities) ->
560 similarities['C'].should.be.lessThan(similarities['B'])
561 )
562
563 it 'should calculate the similarity between a person and a set of people for a list of actions', ->
564 init_esm(ESM, ns)
565 .then (esm) ->
566 bb.all([
567 esm.add_event(ns,'p1','a','t1'),
568 esm.add_event(ns,'p2','a','t1')
569 ])
570 .then( -> esm.calculate_similarities_from_person(ns, 'p1',['p2'],{a: 1}))
571 .then( (similarities) ->
572 similarities['p2'].should.exist
573 )
574
575 it 'should be ale to set current_datetime', ->
576 init_esm(ESM, ns)
577 .then (esm) ->
578 bb.all([
579 esm.add_event(ns,'p1','view','t2', created_at: today),
580 esm.add_event(ns,'p1','view','t1', created_at: three_days_ago),
581
582 esm.add_event(ns,'p2','view','t2', created_at: today),
583 esm.add_event(ns,'p2','view','t1', created_at: three_days_ago),
584
585 esm.add_event(ns,'p3','view','t1', created_at: three_days_ago),
586 ])
587 .then( ->
588 esm.calculate_similarities_from_person(ns, 'p1',['p2', 'p3'],
589 {view: 1}, { current_datetime: two_days_ago}
590 )
591 )
592 .then( (similarities) ->
593 similarities['p3'].should.equal(similarities['p2'])
594 esm.calculate_similarities_from_person(ns, 'p1',['p2', 'p3'],
595 {view: 1}
596 )
597 )
598 .then( (similarities) ->
599 similarities['p2'].should.be.greaterThan(similarities['p3'])
600 )
601
602 describe "recent events", ->
603 it 'if p1 viewed a last week and b today, a person closer to b should be more similar', ->
604 init_esm(ESM, ns)
605 .then (esm) ->
606 bb.all([
607 esm.add_event(ns,'p1','view','a', created_at: moment().subtract(7, 'days')),
608 esm.add_event(ns,'p1','view','b', created_at: today),
609
610 esm.add_event(ns,'p2','view','b', created_at: today),
611 esm.add_event(ns,'p3','view','a', created_at: today)
612
613 ])
614 .then( -> esm.calculate_similarities_from_person(ns, 'p1',['p2', 'p3'], {view: 1}, event_decay_rate: 1.05))
615 .then( (similarities) ->
616 similarities['p3'].should.be.lessThan(similarities['p2'])
617 )
618
619 it 'should calculate the recent event decay weight relative to current_datetime', ->
620 init_esm(ESM, ns)
621 .then (esm) ->
622 bb.all([
623 esm.add_event(ns,'p1','view','a', created_at: today),
624 esm.add_event(ns,'p1','view','b', created_at: today),
625
626 esm.add_event(ns,'p2','view','b', created_at: yesterday),
627 esm.add_event(ns,'p2','view','a', created_at: today),
628
629 #all actions but one day offset
630 esm.add_event(ns,'p1`','view','a', created_at: yesterday),
631 esm.add_event(ns,'p1`','view','b', created_at: yesterday),
632
633 esm.add_event(ns,'p2`','view','b', created_at: two_days_ago),
634 esm.add_event(ns,'p2`','view','a', created_at: yesterday),
635 ])
636 .then( ->
637 sim_today = esm.calculate_similarities_from_person(ns, 'p1',['p2'], {view: 1},
638 event_decay_rate: 1.2, current_datetime: today)
639 sim_yesterday = esm.calculate_similarities_from_person(ns, 'p1`',['p2`'], {view: 1},
640 event_decay_rate: 1.2, current_datetime: yesterday)
641 bb.all([sim_today, sim_yesterday])
642 )
643 .spread( (s1, s2) ->
644 s1['p2'].should.equal(s2['p2`'])
645 )
646
647 it 'should not be effected by having same events (through add_event)', ->
648 init_esm(ESM, ns)
649 .then (esm) ->
650 bb.all([
651 esm.add_event(ns,'p1','a','t1'),
652 esm.add_event(ns,'p2','a','t1')
653 esm.add_event(ns,'p3','a','t1')
654 esm.add_event(ns,'p3','a','t1')
655 ])
656 .then( -> esm.calculate_similarities_from_person(ns, 'p1',['p2', 'p3'],{a: 1}))
657 .then( (similarities) ->
658 similarities['p2'].should.equal similarities['p3']
659 )
660
661
662 it 'should not be effected by having bad names', ->
663 init_esm(ESM, ns)
664 .then (esm) ->
665 bb.all([
666 esm.add_event(ns,"'p\n,1};","v'i\new","'a\n;"),
667 esm.add_event(ns,"'p\n2};","v'i\new","'a\n;")
668 ])
669 .then(-> esm.calculate_similarities_from_person(ns, "'p\n,1};",["'p\n2};"], {"v'i\new": 1}))
670 .then((similarities) ->
671 similarities["'p\n2};"].should.be.greaterThan(0)
672 )
673
674 describe '#recent_recommendations_by_people', ->
675
676 # TODO multiple returned things
677 # it 'should return multiple things for multiple actions', ->
678 # init_esm(ESM, ns)
679 # .then (esm) ->
680 # bb.all([
681 # esm.add_event(ns,'p1','a1','t1', expires_at: tomorrow),
682 # esm.add_event(ns,'p1','a2','t1', expires_at: tomorrow)
683 # ])
684 # .then( -> esm.recent_recommendations_by_people(ns, ['a1', 'a2'], ['p1']))
685 # .then( (people_recommendations) ->
686 # people_recommendations['p1']['a1'].length.should.equal 1
687 # people_recommendations['p1']['a2'].length.should.equal 1
688 # )
689
690 it 'should only return things created before current_datetime', ->
691 a2daysago = moment().subtract(2, 'days')
692 a3daysago = moment().subtract(3, 'days')
693 init_esm(ESM, ns)
694 .then (esm) ->
695 bb.all([
696 esm.add_event(ns,'p1','a','t1', created_at: today, expires_at: tomorrow),
697 esm.add_event(ns,'p1','a','t2', created_at: yesterday, expires_at: tomorrow),
698 esm.add_event(ns,'p1','a','t3', created_at: a2daysago, expires_at: tomorrow),
699 esm.add_event(ns,'p1','a','t4', created_at: a3daysago, expires_at: tomorrow),
700 ])
701 .then( -> esm.recent_recommendations_by_people(ns, ['a'], ['p1']))
702 .then( (people_recommendations) ->
703 people_recommendations.length.should.equal 4
704
705 esm.recent_recommendations_by_people(ns, ['a'], ['p1'], current_datetime: yesterday)
706 )
707 .then( (people_recommendations) ->
708 people_recommendations.length.should.equal 3
709 esm.recent_recommendations_by_people(ns, ['a'], ['p1'], current_datetime: a2daysago)
710 )
711 .then( (people_recommendations) ->
712 people_recommendations.length.should.equal 2
713 )
714
715
716 it 'should return multiple things for multiple actions', ->
717 init_esm(ESM, ns)
718 .then (esm) ->
719 bb.all([
720 esm.add_event(ns,'p1','a1','t1', expires_at: tomorrow),
721 esm.add_event(ns,'p1','a2','t2', expires_at: tomorrow)
722 ])
723 .then( -> esm.recent_recommendations_by_people(ns, ['a1', 'a2'], ['p1']))
724 .then( (people_recommendations) ->
725 people_recommendations.length.should.equal 2
726 )
727
728 it 'should return things for multiple actions and multiple people', ->
729 init_esm(ESM, ns)
730 .then (esm) ->
731 bb.all([
732 esm.add_event(ns,'p1','a1','t1', created_at: yesterday, expires_at: tomorrow),
733 esm.add_event(ns,'p2','a2','t2', created_at: today, expires_at: tomorrow)
734 ])
735 .then( -> esm.recent_recommendations_by_people(ns, ['a1', 'a2'] ,['p1', 'p2']))
736 .then( (people_recommendations) ->
737 people_recommendations.length.should.equal 2
738 people_recommendations[0].person.should.equal 'p2'
739 people_recommendations[0].thing.should.equal 't2'
740
741 people_recommendations[1].person.should.equal 'p1'
742 people_recommendations[1].thing.should.equal 't1'
743 )
744
745 it 'should return things for multiple people', ->
746 init_esm(ESM, ns)
747 .then (esm) ->
748 bb.all([
749 esm.add_event(ns,'p1','a','t1', expires_at: tomorrow),
750 esm.add_event(ns,'p2','a','t2', expires_at: tomorrow)
751 ])
752 .then( -> esm.recent_recommendations_by_people(ns, ['a'] ,['p1', 'p2']))
753 .then( (people_recommendations) ->
754 people_recommendations.length.should.equal 2
755 )
756
757 it 'should not return things without expiry date', ->
758 init_esm(ESM, ns)
759 .then (esm) ->
760 bb.all([
761 esm.add_event(ns,'p1','a','t1', expires_at: tomorrow),
762 esm.add_event(ns,'p1','a','t2')
763 ])
764 .then( -> esm.recent_recommendations_by_people(ns, ['a'], ['p1']))
765 .then( (people_recommendations) ->
766 people_recommendations.length.should.equal 1
767 )
768
769 it 'should not return expired things', ->
770 init_esm(ESM, ns)
771 .then (esm) ->
772 bb.all([
773 esm.add_event(ns,'p1','a','t1', expires_at: tomorrow),
774 esm.add_event(ns,'p1','a','t2', expires_at: yesterday)
775 ])
776 .then( -> esm.recent_recommendations_by_people(ns, ['a'], ['p1']))
777 .then( (people_recommendations) ->
778 people_recommendations.length.should.equal 1
779 )
780
781
782 it 'should return the same item for different people', ->
783 init_esm(ESM, ns)
784 .then (esm) ->
785 bb.all([
786 esm.add_event(ns,'p1','a1','t', created_at: yesterday, expires_at: tomorrow),
787 esm.add_event(ns,'p2','a2','t', created_at: today, expires_at: tomorrow)
788 ])
789 .then( -> esm.recent_recommendations_by_people(ns, ['a1', 'a2'] ,['p1', 'p2']))
790 .then( (people_recommendations) ->
791 people_recommendations.length.should.equal 2
792 people_recommendations[0].person.should.equal 'p2'
793 people_recommendations[0].thing.should.equal 't'
794
795 people_recommendations[1].person.should.equal 'p1'
796 people_recommendations[1].thing.should.equal 't'
797 )
798
799 it 'should be limited by related things limit', ->
800 init_esm(ESM, ns)
801 .then (esm) ->
802 bb.all([
803 esm.add_event(ns,'p1','a','t1', expires_at: tomorrow),
804 esm.add_event(ns,'p1','a','t2', expires_at: tomorrow),
805 esm.add_event(ns,'p2','a','t2', expires_at: tomorrow)
806 ])
807 .then( -> esm.recent_recommendations_by_people(ns, ['a'],['p1','p2'], {recommendations_per_neighbour: 1}))
808 .then( (people_recommendations) ->
809 people_recommendations.length.should.equal 2
810 )
811
812
813
814 it 'should return the last_actioned_at last_expires_at', ->
815 init_esm(ESM, ns)
816 .then (esm) ->
817 esm.add_event(ns,'p1','a','t1', created_at: yesterday, expires_at: tomorrow)
818 .then( ->
819 esm.add_event(ns,'p1','a','t1', created_at: today, expires_at: next_week)
820 )
821 .then( -> esm.recent_recommendations_by_people(ns, ['a'], ['p1', 'p2']))
822 .then( (people_recommendations) ->
823 people_recommendations.length.should.equal 1
824 people_recommendations[0].last_expires_at.getTime().should.equal next_week.toDate().getTime()
825 people_recommendations[0].last_actioned_at.getTime().should.equal today.toDate().getTime()
826 )
827
828 describe 'time_until_expiry', ->
829
830 it 'should not return things that expire before the date passed', ->
831
832 a1day = moment().add(1, 'days').format()
833 a2days = moment().add(2, 'days').format()
834 a3days = moment().add(3, 'days').format()
835
836 init_esm(ESM, ns)
837 .then (esm) ->
838 bb.all([
839 esm.add_event(ns,'p1','a','t1', expires_at: a3days),
840 esm.add_event(ns,'p2','a','t2', expires_at: a1day)
841 ])
842 .then( -> esm.recent_recommendations_by_people(ns, ['a'],['p1','p2'], { time_until_expiry: 48*60*60}))
843 .then( (people_recommendations) ->
844 people_recommendations.length.should.equal 1
845 )
846
847
848 describe '#filter_things_by_previous_actions', ->
849 it 'should remove things that a person has previously actioned', ->
850 init_esm(ESM, ns)
851 .then (esm) ->
852 bb.all([
853 esm.add_event(ns,'p1','view','t1')
854 ])
855 .then( ->
856 esm.filter_things_by_previous_actions(ns, 'p1', ['t1','t2'], ['view'])
857 )
858 .then( (things) ->
859 things.length.should.equal 1
860 things[0].should.equal 't2'
861 )
862
863 it 'should filter things only for given actions', ->
864 init_esm(ESM, ns)
865 .then (esm) ->
866 bb.all([
867 esm.add_event(ns,'p1','view','t1')
868 esm.add_event(ns,'p1','buy','t2')
869 ])
870 .then( ->
871 esm.filter_things_by_previous_actions(ns, 'p1', ['t1','t2'], ['view'])
872 )
873 .then( (things) ->
874 things.length.should.equal 1
875 things[0].should.equal 't2'
876 )
877
878 it 'should filter things for multiple actions', ->
879 init_esm(ESM, ns)
880 .then (esm) ->
881 bb.all([
882 esm.add_event(ns,'p1','view','t1')
883 esm.add_event(ns,'p1','buy','t2')
884 ])
885 .then( ->
886 esm.filter_things_by_previous_actions(ns, 'p1', ['t1','t2'], ['view', 'buy'])
887 )
888 .then( (things) ->
889 things.length.should.equal 0
890 )
891
892 describe 'inserting data', ->
893 describe '#add_events', ->
894 it 'should add an events to the ESM', ->
895 init_esm(ESM, ns)
896 .then (esm) ->
897 esm.add_events([{namespace: ns, person: 'p', action: 'a', thing: 't'}])
898 .then( ->
899 esm.count_events(ns)
900 )
901 .then( (count) ->
902 count.should.equal 1
903 esm.find_events(ns, person: 'p', action: 'a', thing: 't')
904 )
905 .then( (events) ->
906 event = events[0]
907 event.should.not.equal null
908 )
909
910 it 'should add multiple events to the ESM', ->
911 exp_date = (new Date()).toISOString()
912 init_esm(ESM, ns)
913 .then (esm) ->
914 esm.add_events([
915 {namespace: ns, person: 'p1', action: 'a', thing: 't1'}
916 {namespace: ns, person: 'p1', action: 'a', thing: 't2', created_at: new Date().toISOString()}
917 {namespace: ns, person: 'p1', action: 'a', thing: 't3', expires_at: exp_date}
918 ])
919 .then( ->
920 esm.count_events(ns)
921 )
922 .then( (count) ->
923 count.should.equal 3
924 esm.find_events(ns, person: 'p1', action: 'a', thing: 't3')
925 )
926 .then( (events) ->
927 event = events[0]
928 event.should.not.equal null
929 event.expires_at.toISOString().should.equal exp_date
930 )
931
932
933 describe '#add_event', ->
934 it 'should add an event to the ESM', ->
935 init_esm(ESM, ns)
936 .then (esm) ->
937 esm.add_event(ns,'p','a','t')
938 .then( ->
939 esm.count_events(ns)
940 )
941 .then( (count) ->
942 count.should.equal 1
943 esm.find_events(ns, person: 'p', action: 'a', thing: 't')
944 )
945 .then( (events) ->
946 event = events[0]
947 event.should.not.equal null
948 )
949
950 describe '#count_events', ->
951 it 'should return the number of events in the event store', ->
952 init_esm(ESM, ns)
953 .then (esm) ->
954 esm.add_event(ns,'p','a','t')
955 .then( ->
956 esm.count_events(ns)
957 )
958 .then( (count) ->
959 count.should.equal 1
960 )
961
962 describe '#estimate_event_count', ->
963 it 'should be a fast estimate of events', ->
964 init_esm(ESM, ns)
965 .then (esm) ->
966 bb.all([
967 esm.add_event(ns,'p1','view','t1')
968 esm.add_event(ns,'p1','view','t2')
969 esm.add_event(ns,'p1','view','t3')
970 ])
971 .then( ->
972 esm.pre_compact(ns)
973 )
974 .then( ->
975 esm.estimate_event_count(ns)
976 )
977 .then( (count) ->
978 count.should.equal 3
979 )
980
981 describe '#delete_events', ->
982 it "should return 0 if no events are deleted", ->
983 init_esm(ESM, ns)
984 .then (esm) ->
985 esm.delete_events(ns, person: 'p1', action: 'view', thing: 't1')
986 .then( (ret) ->
987 ret.deleted.should.equal 0
988 )
989
990 it "should delete events from esm", ->
991 init_esm(ESM, ns)
992 .then (esm) ->
993 bb.all([
994 esm.add_event(ns,'p1','view','t1')
995 esm.add_event(ns,'p1','view','t2')
996 esm.add_event(ns,'p1','like','t1')
997 ])
998 .then( ->
999 esm.delete_events(ns, person: 'p1', action: 'view', thing: 't1')
1000 )
1001 .then( (ret) ->
1002 ret.deleted.should.equal 1
1003 esm.count_events(ns)
1004 ).then( (count) ->
1005 count.should.equal 2
1006 )
1007
1008 it "should delete events from esm for person", ->
1009 init_esm(ESM, ns)
1010 .then (esm) ->
1011 bb.all([
1012 esm.add_event(ns,'p1','view','t1')
1013 esm.add_event(ns,'p1','view','t2')
1014 esm.add_event(ns,'p1','like','t1')
1015 ])
1016 .then( ->
1017 esm.delete_events(ns, person: 'p1')
1018 )
1019 .then( (ret) ->
1020 ret.deleted.should.equal 3
1021 esm.count_events(ns)
1022 ).then( (count) ->
1023 count.should.equal 0
1024 )
1025
1026 it "should delete events from esm for action", ->
1027 init_esm(ESM, ns)
1028 .then (esm) ->
1029 bb.all([
1030 esm.add_event(ns,'p1','view','t1')
1031 esm.add_event(ns,'p1','view','t2')
1032 esm.add_event(ns,'p1','like','t1')
1033 ])
1034 .then( ->
1035 esm.delete_events(ns, action: 'view')
1036 )
1037 .then( (ret) ->
1038 ret.deleted.should.equal 2
1039 esm.count_events(ns)
1040 ).then( (count) ->
1041 count.should.equal 1
1042 )
1043
1044 it "should delete all events if no value is given", ->
1045 init_esm(ESM, ns)
1046 .then (esm) ->
1047 bb.all([
1048 esm.add_event(ns,'p1','view','t1')
1049 esm.add_event(ns,'p1','view','t2')
1050 esm.add_event(ns,'p1','like','t1')
1051 ])
1052 .then( ->
1053 esm.delete_events(ns)
1054 )
1055 .then( (ret) ->
1056 ret.deleted.should.equal 3
1057 esm.count_events(ns)
1058 ).then( (count) ->
1059 count.should.equal 0
1060 )
1061
1062 describe '#find_events', ->
1063 it 'should return the event', ->
1064 init_esm(ESM, ns)
1065 .then (esm) ->
1066 esm.add_event(ns,'p','a','t')
1067 .then( ->
1068 esm.find_events(ns, person: 'p', action: 'a', thing: 't')
1069 )
1070 .then( (events) ->
1071 event = events[0]
1072 event.person.should.equal 'p'
1073 event.action.should.equal 'a'
1074 event.thing.should.equal 't'
1075 )
1076
1077 it "should return null if no event matches", ->
1078 init_esm(ESM, ns)
1079 .then (esm) ->
1080 esm.find_events(ns, person: 'p', action: 'a', thing: 't')
1081 .then( (events) ->
1082 events.length.should.equal 0
1083 )
1084
1085 it "should find event with only one argument", ->
1086 init_esm(ESM, ns)
1087 .then (esm) ->
1088 esm.add_event(ns,'p','a','t')
1089 .then( ->
1090 bb.all([
1091 esm.find_events(ns, person: 'p')
1092 esm.find_events(ns, action: 'a')
1093 esm.find_events(ns, thing: 't')
1094 ])
1095 )
1096 .spread( (events1, events2, events3) ->
1097 e1 = events1[0]
1098 e2 = events2[0]
1099 e3 = events3[0]
1100 for event in [e1, e2, e3]
1101 event.person.should.equal 'p'
1102 event.action.should.equal 'a'
1103 event.thing.should.equal 't'
1104 )
1105
1106 it "should return multiple events", ->
1107 init_esm(ESM, ns)
1108 .then (esm) ->
1109 bb.all([
1110 esm.add_event(ns,'p1','view','t1')
1111 esm.add_event(ns,'p1','view','t2')
1112 esm.add_event(ns,'p1','like','t1')
1113 ])
1114 .then( ->
1115 bb.all([
1116 esm.find_events(ns, person: 'p1')
1117 esm.find_events(ns, person:'p1', action: 'view')
1118 esm.find_events(ns, person:'p1', action: 'view', thing: 't1')
1119 esm.find_events(ns, action: 'view')
1120 esm.find_events(ns, person: 'p1', thing:'t1')
1121 ])
1122 )
1123 .spread( (events1, events2, events3, events4, events5) ->
1124 events1.length.should.equal 3
1125 events2.length.should.equal 2
1126 events3.length.should.equal 1
1127 events4.length.should.equal 2
1128 events5.length.should.equal 2
1129 )
1130
1131 it "should return events in created_at descending order (most recent first)", ->
1132 init_esm(ESM, ns)
1133 .then (esm) ->
1134 esm.add_events([
1135 {namespace: ns, person:'bob', action: 'hates', thing: 'hobbit', created_at: yesterday},
1136 {namespace: ns, person:'bob', action: 'likes', thing: 'hobbit', created_at: today},
1137 ])
1138 .then( ->
1139 esm.find_events(ns, person: 'bob', size: 1, current_datetime: undefined)
1140 )
1141 .then( (events) ->
1142 events.length.should.equal 1
1143 events[0].action.should.equal 'likes'
1144
1145 )
1146
1147 it "should return only the most recent unique events", ->
1148 init_esm(ESM, ns)
1149 .then (esm) ->
1150 esm.add_event(ns,'p1','a','t1', created_at: yesterday)
1151 .then( ->
1152 esm.add_event(ns,'p1','a','t1', created_at: today)
1153 )
1154 .then( ->
1155 esm.find_events(ns, person: 'p1')
1156 )
1157 .then( (events) ->
1158 events.length.should.equal 1
1159 moment(events[0].created_at).format().should.equal today.format()
1160 events[0].thing.should.equal 't1'
1161 )
1162
1163 it "should limit the returned events to size", ->
1164 init_esm(ESM, ns)
1165 .then (esm) ->
1166 bb.all([
1167 esm.add_event(ns,'p1','a','t1', created_at: new Date()),
1168 esm.add_event(ns,'p1','a','t2', created_at: moment().subtract(2, 'days'))
1169 esm.add_event(ns,'p1','a','t3', created_at: moment().subtract(10, 'days'))
1170 ])
1171 .then( ->
1172 esm.find_events(ns, person: 'p1', size: 2)
1173 )
1174 .then( (events) ->
1175 events.length.should.equal 2
1176 events[0].thing.should.equal 't1'
1177 events[1].thing.should.equal 't2'
1178 )
1179
1180 it "should return pagable events", ->
1181 init_esm(ESM, ns)
1182 .then (esm) ->
1183 bb.all([
1184 esm.add_event(ns, 'p1','a','t1', created_at: new Date()),
1185 esm.add_event(ns, 'p1','a','t2', created_at: moment().subtract(2, 'days'))
1186 esm.add_event(ns, 'p1','a','t3', created_at: moment().subtract(10, 'days'))
1187 ])
1188 .then( ->
1189 esm.find_events(ns, person: 'p1', size: 2, page: 1)
1190 )
1191 .then( (events) ->
1192 events.length.should.equal 1
1193 events[0].thing.should.equal 't3'
1194 )
1195
1196 it 'should be able to take arrays', ->
1197 init_esm(ESM, ns)
1198 .then (esm) ->
1199 bb.all([
1200 esm.add_event(ns,'p1','view','t1')
1201 esm.add_event(ns,'p1','view','t2')
1202 esm.add_event(ns,'p1','like','t1')
1203 esm.add_event(ns,'p2','view','t1')
1204 ])
1205 .then( ->
1206 bb.all([
1207 esm.find_events(ns, people: ['p1', 'p2'])
1208 esm.find_events(ns, person: 'p1', actions: ['view', 'like'])
1209 esm.find_events(ns, person: 'p1', action: 'view', things: ['t1','t2'])
1210 ])
1211 )
1212 .spread( (events1, events2, events3) ->
1213 events1.length.should.equal 4
1214 events2.length.should.equal 3
1215 events3.length.should.equal 2
1216 )
1217
1218 it 'should be able to select current_datetime', ->
1219 init_esm(ESM, ns)
1220 .then (esm) ->
1221 bb.all([
1222 esm.add_event(ns,'p1','a','t1', created_at: new Date()),
1223 esm.add_event(ns,'p1','a','t2', created_at: moment().subtract(2, 'days'))
1224 esm.add_event(ns,'p1','a','t3', created_at: moment().subtract(6, 'days'))
1225 ])
1226 .then( ->
1227 esm.find_events(ns, person: 'p1')
1228 )
1229 .then( (events) ->
1230 events.length.should.equal 3
1231 esm.find_events(ns, person: 'p1', current_datetime: moment().subtract(1, 'days'))
1232 )
1233 .then( (events) ->
1234 events.length.should.equal 2
1235 esm.find_events(ns, person: 'p1', current_datetime: moment().subtract(3, 'days'))
1236 )
1237 .then( (events) ->
1238 events.length.should.equal 1
1239 )
1240
1241 it 'should be able to select time_until_expiry', ->
1242 init_esm(ESM, ns)
1243 .then (esm) ->
1244 bb.all([
1245 esm.add_event(ns,'p1','a','t1', expires_at: today),
1246 esm.add_event(ns,'p1','a','t2', expires_at: moment(today).add(10, 'minutes'))
1247 esm.add_event(ns,'p1','a','t3', expires_at: moment(today).add(100, 'minutes'))
1248 ])
1249 .then( ->
1250 esm.find_events(ns, person: 'p1')
1251 )
1252 .then( (events) ->
1253 events.length.should.equal 3
1254 esm.find_events(ns, person: 'p1', time_until_expiry: 60)
1255 )
1256 .then( (events) ->
1257 events.length.should.equal 2
1258 esm.find_events(ns, person: 'p1', time_until_expiry: 630)
1259 )
1260 .then( (events) ->
1261 events.length.should.equal 1
1262 )
1263
1264
1265
1266module.exports = esm_tests;
1267
1268