meadow-endpoints 2.0.12 → 3.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.
@@ -0,0 +1,1325 @@
1
+ /**
2
+ * Unit tests for the MeadowEndpoints Server in trusted session data mode.
3
+ *
4
+ * @license MIT
5
+ *
6
+ * @author Alex Decker <alex.decker@headlght.com>
7
+ */
8
+
9
+ const Chai = require('chai');
10
+ const Expect = Chai.expect;
11
+ const Assert = Chai.assert;
12
+
13
+ const libSuperTest = require('supertest');
14
+
15
+ const libMySQL = require('mysql2');
16
+ const libAsync = require('async');
17
+
18
+ let tmpFableSettings = (
19
+ {
20
+ Product: 'MockOratorAlternate',
21
+ ProductVersion: '0.0.0',
22
+
23
+ UnauthorizedRequestDelay: 10,
24
+
25
+ APIServerPort: 9082,
26
+
27
+ MySQL:
28
+ {
29
+ // This is queued up for Travis defaults.
30
+ Server: 'localhost',
31
+ Port: 3306,
32
+ User: process.env.DEV_MYSQL_USER || 'root',
33
+ Password: process.env.DEV_MYSQL_PASS || '',
34
+ Database: 'FableTest',
35
+ ConnectionPoolLimit: 20
36
+ },
37
+ ConfigFile: + `${__dirname}/../MeadowTest-Settings.json`,
38
+ });
39
+
40
+ const libFable = require('fable').new(tmpFableSettings);
41
+ tmpFableSettings = libFable.settings;
42
+
43
+ libFable.MeadowMySQLConnectionPool = libMySQL.createPool
44
+ (
45
+ {
46
+ connectionLimit: libFable.settings.MySQL.ConnectionPoolLimit,
47
+ host: libFable.settings.MySQL.Server,
48
+ port: libFable.settings.MySQL.Port,
49
+ user: libFable.settings.MySQL.User,
50
+ password: libFable.settings.MySQL.Password,
51
+ database: libFable.settings.MySQL.Database,
52
+ namedPlaceholders: true
53
+ }
54
+ );
55
+
56
+ let _Meadow;
57
+ let _MeadowEndpoints;
58
+
59
+ const _AnimalSchema = require('./Animal.json');
60
+
61
+ // Now that we have some test data, wire up the endpoints!
62
+
63
+ // Load up a Meadow (pointing at the Animal database)
64
+ _Meadow = require('meadow')
65
+ .new(libFable, 'FableTest')
66
+ .setProvider('MySQL')
67
+ .setSchema(_AnimalSchema.Schema)
68
+ .setJsonSchema(_AnimalSchema.JsonSchema)
69
+ .setDefaultIdentifier(_AnimalSchema.DefaultIdentifier)
70
+ .setDefault(_AnimalSchema.DefaultObject)
71
+ .setAuthorizer(_AnimalSchema.Authorization);
72
+ // Instantiate the endpoints
73
+ _MeadowEndpoints = require('../source/Meadow-Endpoints.js').new(_Meadow);
74
+
75
+ suite
76
+ (
77
+ 'Meadow-Endpoints with Disabled Auth',
78
+ function()
79
+ {
80
+ // TODO: Abstract this so it can be run again and again.
81
+ let _SpooledUp = false;
82
+ let _Orator;
83
+
84
+ const getAnimalInsert = function(pName, pType)
85
+ {
86
+ return "INSERT INTO `FableTest` (`IDAnimal`, `GUIDAnimal`, `CreateDate`, `CreatingIDUser`, `UpdateDate`, `UpdatingIDUser`, `Deleted`, `DeleteDate`, `DeletingIDUser`, `Name`, `Type`, `IDCustomer`) VALUES (NULL, '00000000-0000-0000-0000-000000000000', NOW(), 1, NOW(), 1, 0, NULL, 0, '"+pName+"', '"+pType+"', 1); ";
87
+ };
88
+
89
+ setup
90
+ (
91
+ function(fDone)
92
+ {
93
+ // Only do this for the first test, so we persiste database state across suites
94
+ if (!_SpooledUp)
95
+ {
96
+ _Orator = require('orator').new(tmpFableSettings);
97
+ _Orator.enabledModules.CORS = true;
98
+ _Orator.enabledModules.FullResponse = true;
99
+ _Orator.enabledModules.Body = false;
100
+
101
+
102
+ const _SQLConnectionPool = libMySQL.createPool
103
+ (
104
+ {
105
+ connectionLimit: tmpFableSettings.MySQL.ConnectionPoolLimit,
106
+ host: tmpFableSettings.MySQL.Server,
107
+ port: tmpFableSettings.MySQL.Port,
108
+ user: tmpFableSettings.MySQL.User,
109
+ password: tmpFableSettings.MySQL.Password,
110
+ database: tmpFableSettings.MySQL.Database
111
+ }
112
+ );
113
+
114
+ // Tear down previous test data, rebuild records
115
+ libAsync.waterfall(
116
+ [
117
+ function(fCallBack)
118
+ {
119
+ _SQLConnectionPool.query('DROP TABLE IF EXISTS FableTest',
120
+ function(pErrorUpdate, pResponse) { fCallBack(null); });
121
+ },
122
+ function(fCallBack)
123
+ {
124
+ _SQLConnectionPool.query("CREATE TABLE IF NOT EXISTS FableTest (IDAnimal INT UNSIGNED NOT NULL AUTO_INCREMENT, GUIDAnimal CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', CreateDate DATETIME, CreatingIDUser INT NOT NULL DEFAULT '0', UpdateDate DATETIME, UpdatingIDUser INT NOT NULL DEFAULT '0', Deleted TINYINT NOT NULL DEFAULT '0', DeleteDate DATETIME, DeletingIDUser INT NOT NULL DEFAULT '0', Name CHAR(128) NOT NULL DEFAULT '', Type CHAR(128) NOT NULL DEFAULT '', IDCustomer INT NOT NULL DEFAULT '0', PRIMARY KEY (IDAnimal) );",
125
+ function(pErrorUpdate, pResponse) { fCallBack(null); });
126
+ },
127
+ function(fCallBack)
128
+ {
129
+ _SQLConnectionPool.query(getAnimalInsert('Foo Foo', 'Bunny'),
130
+ function(pErrorUpdate, pResponse) { fCallBack(null); });
131
+ },
132
+ function(fCallBack)
133
+ {
134
+ _SQLConnectionPool.query(getAnimalInsert('Red Riding Hood', 'Girl'),
135
+ function(pErrorUpdate, pResponse) { fCallBack(null); });
136
+ },
137
+ function(fCallBack)
138
+ {
139
+ _SQLConnectionPool.query(getAnimalInsert('Red', 'Dog'),
140
+ function(pErrorUpdate, pResponse) { fCallBack(null); });
141
+ },
142
+ function(fCallBack)
143
+ {
144
+ _SQLConnectionPool.query(getAnimalInsert('Spot', 'Dog'),
145
+ function(pErrorUpdate, pResponse) { fCallBack(null); });
146
+ },
147
+ function(fCallBack)
148
+ {
149
+ _SQLConnectionPool.query(getAnimalInsert('Gertrude', 'Frog'),
150
+ function(pErrorUpdate, pResponse) { fCallBack(null); });
151
+ },
152
+ function(fCallBack)
153
+ {
154
+ // Start the web server
155
+ _MeadowEndpoints.setEndpointAuthorization
156
+ (
157
+ 'Create',
158
+ 2
159
+ );
160
+ _MeadowEndpoints.setEndpointAuthenticator ('Reads');
161
+ _MeadowEndpoints.setEndpointAuthenticator
162
+ (
163
+ 'Reads',
164
+ function(pRequest, pResponse, fNext)
165
+ {
166
+ pRequest.EndpointAuthenticated = true;
167
+ fNext();
168
+ }
169
+ );
170
+ _MeadowEndpoints.setEndpoint('Randomize');
171
+ _MeadowEndpoints.setEndpoint('Randomize', function() {});
172
+
173
+ _MeadowEndpoints.behaviorModifications.setTemplate('ListQuery', '<%= MyData %>');
174
+ //_MeadowEndpoints.behaviorModifications.setTemplate('SelectList', '<%= Name %>|<%= Type %>');
175
+
176
+ // Wire the endpoints up
177
+ _MeadowEndpoints.connectRoutes(_Orator.webServer);
178
+ _Orator.startWebServer (function() { fCallBack(null); });
179
+ }
180
+ ],
181
+ function(pError, pResult)
182
+ {
183
+ // Now continue the tests.
184
+ _SpooledUp = true;
185
+ fDone();
186
+ }
187
+ );
188
+ }
189
+ else
190
+ {
191
+ fDone();
192
+ }
193
+ }
194
+ );
195
+
196
+ setup
197
+ (
198
+ function()
199
+ {
200
+ }
201
+ );
202
+
203
+ suite
204
+ (
205
+ 'Object Sanity',
206
+ function()
207
+ {
208
+ test
209
+ (
210
+ 'initialize should build a happy little object',
211
+ function()
212
+ {
213
+ Expect(_MeadowEndpoints).to.be.an('object', 'MeadowEndpoints should initialize as an object directly from the require statement.');
214
+ }
215
+ );
216
+ }
217
+ );
218
+ suite
219
+ (
220
+ 'Behavior Modifications',
221
+ function()
222
+ {
223
+ test
224
+ (
225
+ 'exercise the security modification api',
226
+ function()
227
+ {
228
+ const tmpAuthorizers = require('../source/Meadow-Authorizers.js').new(libFable);
229
+ tmpAuthorizers.setAuthorizer('AlwaysAuthorize',
230
+ function(pRequest, fComplete)
231
+ {
232
+ pRequest.MeadowAuthorization = false;
233
+ });
234
+ const tmpMockRequest = { };
235
+ tmpAuthorizers.authorize('BadHash', tmpMockRequest,
236
+ function()
237
+ {
238
+ Expect(tmpMockRequest.MeadowAuthorization).to.equal(true);
239
+ });
240
+ tmpAuthorizers.authorize('AlwaysAuthorize', tmpMockRequest,
241
+ function()
242
+ {
243
+ // doesn't invoke behavior when disabled
244
+ Expect(tmpMockRequest.MeadowAuthorization).to.equal(true);
245
+ });
246
+ tmpAuthorizers.authorize('Allow', tmpMockRequest,
247
+ function()
248
+ {
249
+ Expect(tmpMockRequest.MeadowAuthorization).to.equal(true);
250
+ });
251
+ tmpAuthorizers.authorize('Deny', tmpMockRequest,
252
+ function()
253
+ {
254
+ Expect(tmpMockRequest.MeadowAuthorization).to.equal(true);
255
+ });
256
+ }
257
+ );
258
+ test
259
+ (
260
+ 'exercise the security modification api with initial authorization state',
261
+ function()
262
+ {
263
+ const tmpAuthorizers = require('../source/Meadow-Authorizers.js').new(libFable);
264
+ tmpAuthorizers.setAuthorizer('AlwaysAuthorize',
265
+ function(pRequest, fComplete)
266
+ {
267
+ pRequest.MeadowAuthorization = false;
268
+ });
269
+ // disabled doesn't force to true, it just leaves what's there (if anything; if absent, will set true as default)
270
+ const tmpMockRequest = {MeadowAuthorization: 'Green'};
271
+ tmpAuthorizers.authorize('BadHash', tmpMockRequest,
272
+ function()
273
+ {
274
+ Expect(tmpMockRequest.MeadowAuthorization).to.equal('Green');
275
+ });
276
+ tmpAuthorizers.authorize('AlwaysAuthorize', tmpMockRequest,
277
+ function()
278
+ {
279
+ Expect(tmpMockRequest.MeadowAuthorization).to.equal('Green');
280
+ });
281
+ tmpAuthorizers.authorize('Allow', tmpMockRequest,
282
+ function()
283
+ {
284
+ Expect(tmpMockRequest.MeadowAuthorization).to.equal('Green');
285
+ });
286
+ tmpAuthorizers.authorize('Deny', tmpMockRequest,
287
+ function()
288
+ {
289
+ Expect(tmpMockRequest.MeadowAuthorization).to.equal('Green');
290
+ });
291
+ }
292
+ );
293
+ test
294
+ (
295
+ 'exercise the security modification authenticators',
296
+ function()
297
+ {
298
+ const tmpAuthorizers = require('../source/Meadow-Authorizers.js').new(libFable);
299
+ const tmpMockFullRequest =
300
+ {
301
+ UserSession:
302
+ {
303
+ CustomerID: 10,
304
+ UserID: 1
305
+ },
306
+ Record:
307
+ {
308
+ IDCustomer: 10,
309
+ CreatingIDUser: 1
310
+ }
311
+ };
312
+ // Mine and MyCustomer should both work
313
+ tmpAuthorizers.authorize('Mine', tmpMockFullRequest,
314
+ function()
315
+ {
316
+ Expect(tmpMockFullRequest.MeadowAuthorization).to.equal(true);
317
+ });
318
+ tmpAuthorizers.authorize('MyCustomer', tmpMockFullRequest,
319
+ function()
320
+ {
321
+ Expect(tmpMockFullRequest.MeadowAuthorization).to.equal(true);
322
+ });
323
+ tmpMockFullRequest.UserSession.CustomerID = 100;
324
+ tmpMockFullRequest.UserSession.UserID = 100;
325
+ // Now they should both fail
326
+ tmpAuthorizers.authorize('Mine', tmpMockFullRequest,
327
+ function()
328
+ {
329
+ // Auth disabled, so this should still be allowed
330
+ Expect(tmpMockFullRequest.MeadowAuthorization).to.equal(true);
331
+ });
332
+ tmpAuthorizers.authorize('MyCustomer', tmpMockFullRequest,
333
+ function()
334
+ {
335
+ // Auth disabled, so this should still be allowed
336
+ Expect(tmpMockFullRequest.MeadowAuthorization).to.equal(true);
337
+ });
338
+ }
339
+ );
340
+ }
341
+ );
342
+ suite
343
+ (
344
+ 'Basic Server Routes',
345
+ function()
346
+ {
347
+ test
348
+ (
349
+ 'create: create a record',
350
+ function(fDone)
351
+ {
352
+ var tmpRecord = {Name:'BatBrains', Type:'Mammoth'};
353
+ libSuperTest('http://localhost:9082/')
354
+ .post('1.0/FableTest')
355
+ .send(tmpRecord)
356
+ .end(
357
+ function(pError, pResponse)
358
+ {
359
+ // Expect response to be the record we just created.
360
+ var tmpResult = JSON.parse(pResponse.text);
361
+ Expect(tmpResult.Type).to.equal('Mammoth');
362
+ //Expect(tmpResult.CreatingIDUser).to.equal(37);
363
+ fDone();
364
+ }
365
+ );
366
+ }
367
+ );
368
+ test
369
+ (
370
+ 'create: create a record',
371
+ function(fDone)
372
+ {
373
+ var tmpRecord = {Name:'BatBrains', Type:'Mammoth'};
374
+ libSuperTest('http://localhost:9082/')
375
+ .post('1.0/FableTest')
376
+ .send(tmpRecord)
377
+ .end(
378
+ function(pError, pResponse)
379
+ {
380
+ // Expect response to be the record we just created.
381
+ var tmpResult = JSON.parse(pResponse.text);
382
+ Expect(tmpResult.Error).to.not.exist;
383
+ Expect(tmpResult.ErrorCode).to.not.exist;
384
+ fDone();
385
+ }
386
+ );
387
+ }
388
+ );
389
+ test
390
+ (
391
+ 'create: create a record with a bad record passed in',
392
+ function(fDone)
393
+ {
394
+ var tmpRecord = ' ';
395
+ libSuperTest('http://localhost:9082/')
396
+ .post('1.0/FableTest')
397
+ .send(tmpRecord)
398
+ .end(
399
+ function(pError, pResponse)
400
+ {
401
+ // Expect response to be the record we just created.
402
+ var tmpResult = JSON.parse(pResponse.text);
403
+ Expect(tmpResult.Error).to.not.be.null;
404
+ fDone();
405
+ }
406
+ );
407
+ }
408
+ );
409
+ test
410
+ (
411
+ 'read: get a specific record',
412
+ function(fDone)
413
+ {
414
+ libSuperTest('http://localhost:9082/')
415
+ .get('1.0/FableTest/2')
416
+ .end(
417
+ function (pError, pResponse)
418
+ {
419
+ var tmpResult = JSON.parse(pResponse.text);
420
+ Expect(tmpResult.Type).to.equal('Girl');
421
+ fDone();
422
+ }
423
+ );
424
+ }
425
+ );
426
+ test
427
+ (
428
+ 'read: define a custom route and get a record with it',
429
+ function(fDone)
430
+ {
431
+ _Orator.webServer.get('/CustomHotRodRoute/:IDRecord', _MeadowEndpoints.endpointAuthenticators.Read, _MeadowEndpoints.wireState, _MeadowEndpoints.endpoints.Read);
432
+ libSuperTest('http://localhost:9082/')
433
+ .get('CustomHotRodRoute/2')
434
+ .end(
435
+ function (pError, pResponse)
436
+ {
437
+ var tmpResult = JSON.parse(pResponse.text);
438
+ Expect(tmpResult.Type).to.equal('Girl');
439
+ fDone();
440
+ }
441
+ );
442
+ }
443
+ );
444
+ test
445
+ (
446
+ 'read: get a specific record but be denied by security',
447
+ function(fDone)
448
+ {
449
+ _Meadow.schemaFull.authorizer.Manager = {};
450
+ _Meadow.schemaFull.authorizer.Manager.Read = 'Deny';
451
+
452
+ libSuperTest('http://localhost:9082/')
453
+ .get('1.0/FableTest/2')
454
+ .end(
455
+ function (pError, pResponse)
456
+ {
457
+ Expect(pError).to.not.exist;
458
+ Expect(pResponse.text).not.to.contain('UNAUTHORIZED ACCESS IS NOT ALLOWED');
459
+ // Reset authorization
460
+ _Meadow.schemaFull.authorizer.Manager.Read = 'Allow';
461
+ fDone();
462
+ }
463
+ );
464
+ }
465
+ );
466
+ test
467
+ (
468
+ 'read: get a specific record with a bad parameter',
469
+ function(fDone)
470
+ {
471
+ libSuperTest('http://localhost:9082/')
472
+ .get('1.0/FableTest/')
473
+ .end(
474
+ function (pError, pResponse)
475
+ {
476
+ var tmpResult = JSON.parse(pResponse.text);
477
+ Expect(tmpResult.Error).to.equal('Error retreiving a record. Record not found');
478
+ fDone();
479
+ }
480
+ );
481
+ }
482
+ );
483
+ test
484
+ (
485
+ 'reads: get all records',
486
+ function(fDone)
487
+ {
488
+ libSuperTest('http://localhost:9082/')
489
+ .get('1.0/FableTests')
490
+ .end(
491
+ function (pError, pResponse)
492
+ {
493
+ var tmpResults = JSON.parse(pResponse.text);
494
+ Expect(tmpResults.length).to.equal(7);
495
+ Expect(tmpResults[0].Type).to.equal('Bunny');
496
+ Expect(tmpResults[4].Name).to.equal('Gertrude');
497
+ fDone();
498
+ }
499
+ );
500
+ }
501
+ );
502
+ test
503
+ (
504
+ 'readsLiteExtended: get all records',
505
+ function(fDone)
506
+ {
507
+ libSuperTest('http://localhost:9082/')
508
+ .get('1.0/FableTests/LiteExtended/Type,Name')
509
+ .end(
510
+ function (pError, pResponse)
511
+ {
512
+ var tmpResults = JSON.parse(pResponse.text);
513
+ Expect(tmpResults.length).to.equal(7);
514
+ Expect(tmpResults[0].IDAnimal).to.equal(1);
515
+ Expect(tmpResults[4].IDAnimal).to.equal(5);
516
+ Expect(tmpResults[4].Type).to.equal('Frog');
517
+ fDone();
518
+ }
519
+ );
520
+ }
521
+ );
522
+ test
523
+ (
524
+ 'readsby: get all records by Type',
525
+ function(fDone)
526
+ {
527
+ libSuperTest('http://localhost:9082/')
528
+ .get('1.0/FableTests/By/Type/Dog')
529
+ .end(
530
+ function (pError, pResponse)
531
+ {
532
+ var tmpResults = JSON.parse(pResponse.text);
533
+ Expect(tmpResults.length).to.equal(2);
534
+ Expect(tmpResults[0].Type).to.equal('Dog');
535
+ fDone();
536
+ }
537
+ );
538
+ }
539
+ );
540
+ test
541
+ (
542
+ 'readsby: get all records by Type IN LIST',
543
+ function(fDone)
544
+ {
545
+ libSuperTest('http://localhost:9082/')
546
+ .get('1.0/FableTests/By/Type/Mammoth%2C%20WithComma,Dog')
547
+ .end(
548
+ function (pError, pResponse)
549
+ {
550
+ var tmpResults = JSON.parse(pResponse.text);
551
+ Expect(tmpResults.length).to.equal(2);
552
+ Expect(tmpResults[0].Type).to.equal('Dog');
553
+ fDone();
554
+ }
555
+ );
556
+ }
557
+ );
558
+ test
559
+ (
560
+ 'countby: get count of records by Type',
561
+ function(fDone)
562
+ {
563
+ libSuperTest('http://localhost:9082/')
564
+ .get('1.0/FableTests/Count/By/Type/Dog')
565
+ .end(
566
+ function (pError, pResponse)
567
+ {
568
+ var tmpResults = JSON.parse(pResponse.text);
569
+ Expect(tmpResults.Count).to.equal(2);
570
+ fDone();
571
+ }
572
+ );
573
+ }
574
+ );
575
+ test
576
+ (
577
+ 'countby: get count of records by multiple Types',
578
+ function(fDone)
579
+ {
580
+ libSuperTest('http://localhost:9082/')
581
+ .get('1.0/FableTests/Count/By/Type/Dog,Mammoth')
582
+ .end(
583
+ function (pError, pResponse)
584
+ {
585
+ var tmpResults = JSON.parse(pResponse.text);
586
+ Expect(tmpResults.Count).to.equal(4);
587
+ fDone();
588
+ }
589
+ );
590
+ }
591
+ );
592
+ test
593
+ (
594
+ 'readsby: get paged records by Type',
595
+ function(fDone)
596
+ {
597
+ libSuperTest('http://localhost:9082/')
598
+ .get('1.0/FableTests/By/Type/Dog/1/1')
599
+ .end(
600
+ function (pError, pResponse)
601
+ {
602
+ var tmpResults = JSON.parse(pResponse.text);
603
+ Expect(tmpResults.length).to.equal(1);
604
+ Expect(tmpResults[0].Name).to.equal('Spot');
605
+ fDone();
606
+ }
607
+ );
608
+ }
609
+ );
610
+ test
611
+ (
612
+ 'readselect: get a page of filtered records by date',
613
+ function(fDone)
614
+ {
615
+ var today = new Date();
616
+ today = today.toISOString().substring(0, 10);
617
+
618
+ libSuperTest('http://localhost:9082/')
619
+ .get(`1.0/FableTestSelect/FilteredTo/FBD~UpdateDate~EQ~${today}/0/1`)
620
+ .end(
621
+ function (pError, pResponse)
622
+ {
623
+ console.log(pResponse.text)
624
+ var tmpResults = JSON.parse(pResponse.text);
625
+ Expect(tmpResults.length).to.equal(1);
626
+ Expect(tmpResults[0].Value).to.equal('FableTest #1');
627
+ fDone();
628
+ }
629
+ );
630
+ }
631
+ );
632
+ test
633
+ (
634
+ 'readselect: get all records',
635
+ function(fDone)
636
+ {
637
+ libSuperTest('http://localhost:9082/')
638
+ .get('1.0/FableTestSelect')
639
+ .end(
640
+ function (pError, pResponse)
641
+ {
642
+ console.log(pResponse.text)
643
+ var tmpResults = JSON.parse(pResponse.text);
644
+ Expect(tmpResults.length).to.equal(7);
645
+ Expect(tmpResults[4].Value).to.equal('FableTest #5');
646
+ fDone();
647
+ }
648
+ );
649
+ }
650
+ );
651
+ test
652
+ (
653
+ 'readselect: get a page of records',
654
+ function(fDone)
655
+ {
656
+ libSuperTest('http://localhost:9082/')
657
+ .get('1.0/FableTestSelect/2/2')
658
+ .end(
659
+ function (pError, pResponse)
660
+ {
661
+ console.log(pResponse.text)
662
+ var tmpResults = JSON.parse(pResponse.text);
663
+ Expect(tmpResults.length).to.equal(2);
664
+ Expect(tmpResults[1].Value).to.equal('FableTest #4');
665
+ fDone();
666
+ }
667
+ );
668
+ }
669
+ );
670
+ test
671
+ (
672
+ 'readselect: get a page of records',
673
+ function(fDone)
674
+ {
675
+ libSuperTest('http://localhost:9082/')
676
+ .get('1.0/FableTestSelect/2/2')
677
+ .end(
678
+ function (pError, pResponse)
679
+ {
680
+ console.log(pResponse.text)
681
+ var tmpResults = JSON.parse(pResponse.text);
682
+ Expect(tmpResults.length).to.equal(2);
683
+ Expect(tmpResults[1].Value).to.equal('FableTest #4');
684
+ fDone();
685
+ }
686
+ );
687
+ }
688
+ );
689
+ test
690
+ (
691
+ 'readselect: get filtered records',
692
+ function(fDone)
693
+ {
694
+ libSuperTest('http://localhost:9082/')
695
+ .get('1.0/FableTestSelect/FilteredTo/FBV~Type~EQ~Dog')
696
+ .end(
697
+ function (pError, pResponse)
698
+ {
699
+ var tmpResults = JSON.parse(pResponse.text);
700
+ Expect(tmpResults.length).to.equal(2);
701
+ Expect(tmpResults[0].Value).to.equal('FableTest #3');
702
+ fDone();
703
+ }
704
+ );
705
+ }
706
+ );
707
+ test
708
+ (
709
+ 'readselect: get a page of filtered records',
710
+ function(fDone)
711
+ {
712
+ libSuperTest('http://localhost:9082/')
713
+ .get('1.0/FableTestSelect/FilteredTo/FBV~Type~EQ~Dog/1/1')
714
+ .end(
715
+ function (pError, pResponse)
716
+ {
717
+ console.log(pResponse.text)
718
+ var tmpResults = JSON.parse(pResponse.text);
719
+ Expect(tmpResults.length).to.equal(1);
720
+ Expect(tmpResults[0].Value).to.equal('FableTest #4');
721
+ fDone();
722
+ }
723
+ );
724
+ }
725
+ );
726
+ test
727
+ (
728
+ 'readselect: get an empty page of records',
729
+ function(fDone)
730
+ {
731
+ libSuperTest('http://localhost:9082/')
732
+ .get('1.0/FableTestSelect/200/200')
733
+ .end(
734
+ function (pError, pResponse)
735
+ {
736
+ console.log(pResponse.text)
737
+ var tmpResults = JSON.parse(pResponse.text);
738
+ Expect(tmpResults.length).to.equal(0);
739
+ fDone();
740
+ }
741
+ );
742
+ }
743
+ );
744
+ test
745
+ (
746
+ 'reads: get a page of records',
747
+ function(fDone)
748
+ {
749
+ libSuperTest('http://localhost:9082/')
750
+ // Get page 2, 2 records per page.
751
+ .get('1.0/FableTests/2/2')
752
+ .end(
753
+ function (pError, pResponse)
754
+ {
755
+ var tmpResults = JSON.parse(pResponse.text);
756
+ Expect(tmpResults.length).to.equal(2);
757
+ Expect(tmpResults[0].Type).to.equal('Dog');
758
+ Expect(tmpResults[1].Name).to.equal('Spot');
759
+ fDone();
760
+ }
761
+ );
762
+ }
763
+ );
764
+ test
765
+ (
766
+ 'reads: get a filtered set of records',
767
+ function(fDone)
768
+ {
769
+ libSuperTest('http://localhost:9082/')
770
+ .get('1.0/FableTests/FilteredTo/FBV~Type~EQ~Frog')
771
+ .end(
772
+ function (pError, pResponse)
773
+ {
774
+ var tmpResults = JSON.parse(pResponse.text);
775
+ Expect(tmpResults.length).to.equal(1);
776
+ Expect(tmpResults[0].Type).to.equal('Frog');
777
+ fDone();
778
+ }
779
+ );
780
+ }
781
+ );
782
+ test
783
+ (
784
+ 'reads: get distinct values for a column',
785
+ function(fDone)
786
+ {
787
+ libSuperTest('http://localhost:9082/')
788
+ .get('1.0/FableTests/Distinct/Type')
789
+ .end(
790
+ function (pError, pResponse)
791
+ {
792
+ var tmpResults = JSON.parse(pResponse.text);
793
+ Expect(tmpResults.length).to.equal(5);
794
+ const types = tmpResults.map((r) => r.Type);
795
+ Expect(types).to.have.members(['Bunny', 'Girl', 'Dog', 'Frog', 'Mammoth']);
796
+ fDone();
797
+ }
798
+ );
799
+ }
800
+ );
801
+ test
802
+ (
803
+ 'reads: get distinct values for a column with filter',
804
+ function(fDone)
805
+ {
806
+ libSuperTest('http://localhost:9082/')
807
+ .get('1.0/FableTests/Distinct/Type/FilteredTo/FBV~IDAnimal~LT~3')
808
+ .end(
809
+ function (pError, pResponse)
810
+ {
811
+ var tmpResults = JSON.parse(pResponse.text);
812
+ Expect(tmpResults.length).to.equal(2);
813
+ const types = new Set(tmpResults.map((r) => r.Type));
814
+ Expect(types.size).to.equal(2);
815
+ fDone();
816
+ }
817
+ );
818
+ }
819
+ );
820
+ test
821
+ (
822
+ 'reads: get distinct values for a column with filter and pagination',
823
+ function(fDone)
824
+ {
825
+ libSuperTest('http://localhost:9082/')
826
+ .get('1.0/FableTests/Distinct/Type/FilteredTo/FBV~IDAnimal~LT~3/0/1')
827
+ .end(
828
+ function (pError, pResponse)
829
+ {
830
+ var tmpResults = JSON.parse(pResponse.text);
831
+ Expect(tmpResults.length).to.equal(1);
832
+ fDone();
833
+ }
834
+ );
835
+ }
836
+ );
837
+ test
838
+ (
839
+ 'reads: get distinct values for a column with pagination',
840
+ function(fDone)
841
+ {
842
+ libSuperTest('http://localhost:9082/')
843
+ .get('1.0/FableTests/Distinct/Type/2/2')
844
+ .end(
845
+ function (pError, pResponse)
846
+ {
847
+ var tmpResults = JSON.parse(pResponse.text);
848
+ Expect(tmpResults.length).to.equal(2);
849
+ const types = new Set(tmpResults.map((r) => r.Type));
850
+ Expect(types.size).to.equal(2);
851
+ fDone();
852
+ }
853
+ );
854
+ }
855
+ );
856
+ test
857
+ (
858
+ 'reads: get a filtered paged set of records',
859
+ function(fDone)
860
+ {
861
+ libSuperTest('http://localhost:9082/')
862
+ // Skip one record, 2 records per page.
863
+ .get('1.0/FableTests/FilteredTo/FBV~Type~EQ~Dog/1/2')
864
+ .end(
865
+ function (pError, pResponse)
866
+ {
867
+ var tmpResults = JSON.parse(pResponse.text);
868
+ Expect(tmpResults.length).to.equal(1);
869
+ Expect(tmpResults[0].Type).to.equal('Dog');
870
+ fDone();
871
+ }
872
+ );
873
+ }
874
+ );
875
+ test
876
+ (
877
+ 'update: update a record',
878
+ function(fDone)
879
+ {
880
+ // Change animal 4 ("Spot") to a Corgi
881
+ var tmpRecord = {IDAnimal:4, Type:'Corgi'};
882
+ libSuperTest('http://localhost:9082/')
883
+ .put('1.0/FableTest')
884
+ .send(tmpRecord)
885
+ .end(
886
+ function(pError, pResponse)
887
+ {
888
+ // Expect response to be the record we just created.
889
+ var tmpResult = JSON.parse(pResponse.text);
890
+ Expect(tmpResult.Type).to.equal('Corgi');
891
+ //Expect(tmpResult.CreatingIDUser).to.equal(1);
892
+ //Expect(tmpResult.UpdatingIDUser).to.equal(37);
893
+ fDone();
894
+ }
895
+ );
896
+ }
897
+ );
898
+ test
899
+ (
900
+ 'delete: delete a record',
901
+ function(fDone)
902
+ {
903
+ // Delete animal 3 ("Red")
904
+ var tmpRecord = {IDAnimal:3};
905
+ libSuperTest('http://localhost:9082/')
906
+ .del('1.0/FableTest')
907
+ .send(tmpRecord)
908
+ .end(
909
+ function(pError, pResponse)
910
+ {
911
+ // Expect response to be the count of deleted records.
912
+ var tmpResult = JSON.parse(pResponse.text);
913
+ Expect(tmpResult.Count).to.equal(1);
914
+ fDone();
915
+ }
916
+ );
917
+ }
918
+ );
919
+ test
920
+ (
921
+ 'delete: delete a record with a bad parameter',
922
+ function(fDone)
923
+ {
924
+ // Delete animal 3 ("Red")
925
+ var tmpRecord = {IDAnimal:{MyStuff:4}};
926
+ libSuperTest('http://localhost:9082/')
927
+ .del('1.0/FableTest')
928
+ .send(tmpRecord)
929
+ .end(
930
+ function(pError, pResponse)
931
+ {
932
+ // Expect response to be the count of deleted records.
933
+ var tmpResult = JSON.parse(pResponse.text);
934
+ Expect(tmpResult.Error).to.contain('a valid record ID is required');
935
+ fDone();
936
+ }
937
+ );
938
+ }
939
+ );
940
+ test
941
+ (
942
+ 'count: get the count of records',
943
+ function(fDone)
944
+ {
945
+ libSuperTest('http://localhost:9082/')
946
+ .get('1.0/FableTests/Count')
947
+ .end(
948
+ function (pError, pResponse)
949
+ {
950
+ var tmpResults = JSON.parse(pResponse.text);
951
+ Expect(tmpResults.Count).to.equal(6);
952
+ fDone();
953
+ }
954
+ );
955
+ }
956
+ );
957
+ test
958
+ (
959
+ 'count: get the count of filtered records',
960
+ function(fDone)
961
+ {
962
+ libSuperTest('http://localhost:9082/')
963
+ .get('1.0/FableTests/Count/FilteredTo/FBV~Type~EQ~Girl')
964
+ .end(
965
+ function (pError, pResponse)
966
+ {
967
+ var tmpResults = JSON.parse(pResponse.text);
968
+ Expect(tmpResults.Count).to.equal(1);
969
+ fDone();
970
+ }
971
+ );
972
+ }
973
+ );
974
+ test
975
+ (
976
+ 'schema: get the schema of a record',
977
+ function(fDone)
978
+ {
979
+ libSuperTest('http://localhost:9082/')
980
+ .get('1.0/FableTest/Schema')
981
+ .end(
982
+ function (pError, pResponse)
983
+ {
984
+ var tmpResults = JSON.parse(pResponse.text);
985
+ //console.log('SCHEMA --> '+JSON.stringify(tmpResults, null, 4))
986
+ Expect(tmpResults.title).to.equal('Animal');
987
+ Expect(tmpResults.description).to.contain('creature that lives in');
988
+ fDone();
989
+ }
990
+ );
991
+ }
992
+ );
993
+ test
994
+ (
995
+ 'new: get a new empty record',
996
+ function(fDone)
997
+ {
998
+ libSuperTest('http://localhost:9082/')
999
+ .get('1.0/FableTest/Schema/New')
1000
+ .end(
1001
+ function (pError, pResponse)
1002
+ {
1003
+ var tmpResults = JSON.parse(pResponse.text);
1004
+ //console.log(JSON.stringify(tmpResults, null, 4))
1005
+ Expect(tmpResults.IDAnimal).to.equal(null);
1006
+ Expect(tmpResults.Name).to.equal('Unknown');
1007
+ Expect(tmpResults.Type).to.equal('Unclassified');
1008
+ fDone();
1009
+ }
1010
+ );
1011
+ }
1012
+ );
1013
+ test
1014
+ (
1015
+ 'validate: validate an invalid record',
1016
+ function(fDone)
1017
+ {
1018
+ var tmpRecord = {IDAnimal:4, Type:'Corgi'};
1019
+ libSuperTest('http://localhost:9082/')
1020
+ .post('1.0/FableTest/Schema/Validate')
1021
+ .send(tmpRecord)
1022
+ .end(
1023
+ function(pError, pResponse)
1024
+ {
1025
+ // Expect response to be the record we just created.
1026
+ var tmpResult = JSON.parse(pResponse.text);
1027
+ //console.log(JSON.stringify(tmpResult, null, 4))
1028
+ Expect(tmpResult.Valid).to.equal(false);
1029
+ Expect(tmpResult.Errors[0].field).to.equal('data.Name');
1030
+ Expect(tmpResult.Errors[0].message).to.equal('is required');
1031
+ fDone();
1032
+ }
1033
+ );
1034
+ }
1035
+ );
1036
+ test
1037
+ (
1038
+ 'validate: validate a valid record',
1039
+ function(fDone)
1040
+ {
1041
+ var tmpRecord = {IDAnimal:4, Type:'Corgi', Name:'Doofer', CreatingIDUser:10};
1042
+ libSuperTest('http://localhost:9082/')
1043
+ .post('1.0/FableTest/Schema/Validate')
1044
+ .send(tmpRecord)
1045
+ .end(
1046
+ function(pError, pResponse)
1047
+ {
1048
+ // Expect response to be the record we just created.
1049
+ var tmpResult = JSON.parse(pResponse.text);
1050
+ //console.log(JSON.stringify(tmpResult, null, 4))
1051
+ Expect(tmpResult.Valid).to.equal(true);
1052
+ fDone();
1053
+ }
1054
+ );
1055
+ }
1056
+ );
1057
+ test
1058
+ (
1059
+ 'validate: validate bad data',
1060
+ function(fDone)
1061
+ {
1062
+ var tmpRecord = 'IAMBAD';
1063
+ libSuperTest('http://localhost:9082/')
1064
+ .post('1.0/FableTest/Schema/Validate')
1065
+ .send(tmpRecord)
1066
+ .end(
1067
+ function(pError, pResponse)
1068
+ {
1069
+ // Expect response to be the record we just created.
1070
+ var tmpResult = JSON.parse(pResponse.text);
1071
+ //console.log(JSON.stringify(tmpResult, null, 4))
1072
+ Expect(tmpResult.Valid).to.be.false;
1073
+ fDone();
1074
+ }
1075
+ );
1076
+ }
1077
+ );
1078
+ }
1079
+ );
1080
+ suite
1081
+ (
1082
+ 'Basic Server Routes',
1083
+ function()
1084
+ {
1085
+ }
1086
+ );
1087
+ suite
1088
+ (
1089
+ 'Unauthorized server routes',
1090
+ function()
1091
+ {
1092
+ test
1093
+ (
1094
+ 'read: get a specific record',
1095
+ function(fDone)
1096
+ {
1097
+ libSuperTest('http://localhost:9082/')
1098
+ .get('1.0/FableTest/2')
1099
+ .end(
1100
+ function (pError, pResponse)
1101
+ {
1102
+ const tmpResult = JSON.parse(pResponse.text);
1103
+ Expect(tmpResult.Error).to.not.exist;
1104
+ Expect(tmpResult.ErrorCode).to.not.exist;
1105
+ fDone();
1106
+ }
1107
+ );
1108
+ }
1109
+ );
1110
+ }
1111
+ );
1112
+ suite
1113
+ (
1114
+ 'Bad user server routes',
1115
+ function()
1116
+ {
1117
+ test
1118
+ (
1119
+ 'create: create a record',
1120
+ function(fDone)
1121
+ {
1122
+ const tmpRecord = {Name:'BatBrains', Type:'Mammoth'};
1123
+ libSuperTest('http://localhost:9082/')
1124
+ .post('1.0/FableTest')
1125
+ .send(tmpRecord)
1126
+ .end(
1127
+ function(pError, pResponse)
1128
+ {
1129
+ const tmpResult = JSON.parse(pResponse.text);
1130
+ Expect(tmpResult.Error).to.not.exist;
1131
+ Expect(tmpResult.ErrorCode).to.not.exist;
1132
+ fDone();
1133
+ }
1134
+ );
1135
+ }
1136
+ );
1137
+ test
1138
+ (
1139
+ 'read: get a specific record',
1140
+ function(fDone)
1141
+ {
1142
+ libSuperTest('http://localhost:9082/')
1143
+ .get('1.0/FableTest/2')
1144
+ .end(
1145
+ function (pError, pResponse)
1146
+ {
1147
+ const tmpResult = JSON.parse(pResponse.text);
1148
+ Expect(tmpResult.Error).to.not.exist;
1149
+ Expect(tmpResult.ErrorCode).to.not.exist;
1150
+ fDone();
1151
+ }
1152
+ );
1153
+ }
1154
+ );
1155
+ test
1156
+ (
1157
+ 'readselect: get all records',
1158
+ function(fDone)
1159
+ {
1160
+ libSuperTest('http://localhost:9082/')
1161
+ .get('1.0/FableTestSelect')
1162
+ .end(
1163
+ function (pError, pResponse)
1164
+ {
1165
+ console.log(pResponse.text)
1166
+ const tmpResults = JSON.parse(pResponse.text);
1167
+ Expect(tmpResults.Error).to.not.exist;
1168
+ Expect(tmpResults.ErrorCode).to.not.exist;
1169
+ fDone();
1170
+ }
1171
+ );
1172
+ }
1173
+ );
1174
+ test
1175
+ (
1176
+ 'update: update a record',
1177
+ function(fDone)
1178
+ {
1179
+ // Change animal 4 ("Spot") to a Corgi
1180
+ const tmpRecord = {IDAnimal:4, Type:'Corgi'};
1181
+ libSuperTest('http://localhost:9082/')
1182
+ .put('1.0/FableTest')
1183
+ .send(tmpRecord)
1184
+ .end(
1185
+ function(pError, pResponse)
1186
+ {
1187
+ // Expect response to be the record we just created.
1188
+ const tmpResult = JSON.parse(pResponse.text);
1189
+ Expect(tmpResult.Error).to.not.exist;
1190
+ Expect(tmpResult.ErrorCode).to.not.exist;
1191
+ fDone();
1192
+ }
1193
+ );
1194
+ }
1195
+ );
1196
+ test
1197
+ (
1198
+ 'schema: get the schema of a record',
1199
+ function(fDone)
1200
+ {
1201
+ libSuperTest('http://localhost:9082/')
1202
+ .get('1.0/FableTest/Schema')
1203
+ .end(
1204
+ function (pError, pResponse)
1205
+ {
1206
+ const tmpResults = JSON.parse(pResponse.text);
1207
+ //console.log('SCHEMA --> '+JSON.stringify(tmpResults, null, 4))
1208
+ Expect(tmpResults.Error).to.not.exist;
1209
+ Expect(tmpResults.ErrorCode).to.not.exist;
1210
+ fDone();
1211
+ }
1212
+ );
1213
+ }
1214
+ );
1215
+ test
1216
+ (
1217
+ 'new: get a new empty record',
1218
+ function(fDone)
1219
+ {
1220
+ libSuperTest('http://localhost:9082/')
1221
+ .get('1.0/FableTest/Schema/New')
1222
+ .end(
1223
+ function (pError, pResponse)
1224
+ {
1225
+ const tmpResults = JSON.parse(pResponse.text);
1226
+ //console.log(JSON.stringify(tmpResults, null, 4))
1227
+ Expect(tmpResults.Error).to.not.exist;
1228
+ Expect(tmpResults.ErrorCode).to.not.exist;
1229
+ fDone();
1230
+ }
1231
+ );
1232
+ }
1233
+ );
1234
+ test
1235
+ (
1236
+ 'validate: validate an invalid record',
1237
+ function(fDone)
1238
+ {
1239
+ const tmpRecord = {IDAnimal:4, Type:'Corgi'};
1240
+ libSuperTest('http://localhost:9082/')
1241
+ .post('1.0/FableTest/Schema/Validate')
1242
+ .send(tmpRecord)
1243
+ .end(
1244
+ function(pError, pResponse)
1245
+ {
1246
+ // Expect response to be the record we just created.
1247
+ const tmpResult = JSON.parse(pResponse.text);
1248
+ console.log(JSON.stringify(tmpResult, null, 4))
1249
+ Expect(tmpResult.Error).to.not.exist;
1250
+ Expect(tmpResult.ErrorCode).to.not.exist;
1251
+ fDone();
1252
+
1253
+ }
1254
+ );
1255
+ }
1256
+ );
1257
+ test
1258
+ (
1259
+ 'count: get the count of records',
1260
+ function(fDone)
1261
+ {
1262
+ libSuperTest('http://localhost:9082/')
1263
+ .get('1.0/FableTests/Count')
1264
+ .end(
1265
+ function (pError, pResponse)
1266
+ {
1267
+ const tmpResult = JSON.parse(pResponse.text);
1268
+ Expect(tmpResult.Error).to.not.exist;
1269
+ Expect(tmpResult.ErrorCode).to.not.exist;
1270
+ fDone();
1271
+ }
1272
+ );
1273
+ }
1274
+ );
1275
+ test
1276
+ (
1277
+ 'delete: delete a record',
1278
+ function(fDone)
1279
+ {
1280
+ // Delete animal 3 ("Red")
1281
+ const tmpRecord = {IDAnimal:3};
1282
+ libSuperTest('http://localhost:9082/')
1283
+ .del('1.0/FableTest')
1284
+ .send(tmpRecord)
1285
+ .end(
1286
+ function(pError, pResponse)
1287
+ {
1288
+ // Expect response to be the count of deleted records.
1289
+ const tmpResult = JSON.parse(pResponse.text);
1290
+ Expect(tmpResult.Error).to.not.exist;
1291
+ Expect(tmpResult.ErrorCode).to.not.exist;
1292
+ fDone();
1293
+ }
1294
+ );
1295
+ }
1296
+ );
1297
+ }
1298
+ );
1299
+ suite
1300
+ (
1301
+ 'Not logged in server routes',
1302
+ function()
1303
+ {
1304
+ test
1305
+ (
1306
+ 'read: get a specific record',
1307
+ function(fDone)
1308
+ {
1309
+ libSuperTest('http://localhost:9082/')
1310
+ .get('1.0/FableTest/2')
1311
+ .end(
1312
+ function (pError, pResponse)
1313
+ {
1314
+ const tmpResult = JSON.parse(pResponse.text);
1315
+ Expect(tmpResult.Error).to.not.exist;
1316
+ Expect(tmpResult.ErrorCode).to.not.exist;
1317
+ fDone();
1318
+ }
1319
+ );
1320
+ }
1321
+ );
1322
+ }
1323
+ );
1324
+ }
1325
+ );