11const should = require ( 'should' ) // eslint-disable-line
22const sinon = require ( 'sinon' )
33
4+ const { Roles } = require ( '../../../../../forge/lib/roles' )
45const setup = require ( '../setup' )
56
67describe ( 'Logging API' , function ( ) {
@@ -17,27 +18,43 @@ describe('Logging API', function () {
1718 device1 : null ,
1819 device2 : null
1920 } ,
20- team1 : null ,
21+ ATeam : null ,
2122 project1 : null ,
2223 project2 : null ,
2324 device1 : null ,
2425 device2 : null ,
25- alice : null
26+ alice : null ,
27+ bob : null ,
28+ chris : null ,
29+ dave : null
2630 }
2731
2832 before ( async function ( ) {
2933 app = await setup ( { } )
3034 factory = app . factory
35+ TestObjects . ATeam = app . team
3136 TestObjects . application = app . application
3237 TestObjects . alice = await app . db . models . User . byUsername ( 'alice' )
33- TestObjects . team1 = app . team
38+ // owner of ATeam
39+ TestObjects . bob = await app . db . models . User . create ( { username : 'bob' , name : 'Bob Fett' , email : 'bob@example.com' , password : 'bbPassword' , sso_enabled : true } )
40+ await app . db . controllers . Team . addUser ( TestObjects . ATeam , TestObjects . bob , Roles . Owner )
41+ // member of ATeam
42+ TestObjects . chris = await app . db . models . User . create ( { username : 'chris' , name : 'Chris Kenobi' , email : 'chris@example.com' , password : 'ccPassword' , sso_enabled : true } )
43+ await app . db . controllers . Team . addUser ( TestObjects . ATeam , TestObjects . chris , Roles . Member )
44+ // viewer of ATeam
45+ TestObjects . dave = await app . db . models . User . create ( { username : 'dave' , name : 'Dave Vader' , email : 'dave@example.com' , password : 'ddPassword' , sso_enabled : true } )
46+ await app . db . controllers . Team . addUser ( TestObjects . ATeam , TestObjects . dave , Roles . Viewer )
47+ // dashboard viewer of ATeam
48+ TestObjects . eve = await app . db . models . User . create ( { username : 'eve' , name : 'Eve Skywalker' , email : 'eve@example.com' , password : 'eePassword' , sso_enabled : true } )
49+ await app . db . controllers . Team . addUser ( TestObjects . ATeam , TestObjects . eve , Roles . Dashboard )
50+
3451 TestObjects . project1 = app . project
3552 TestObjects . project2 = await app . db . models . Project . create ( { name : 'project2' , type : '' , url : '' } )
36- const device1 = await factory . createDevice ( { name : generateName ( 'device-1' ) } , TestObjects . team1 , null , TestObjects . application )
53+ const device1 = await factory . createDevice ( { name : generateName ( 'device-1' ) } , TestObjects . ATeam , null , TestObjects . application )
3754 TestObjects . device1 = await app . db . models . Device . byId ( device1 . id )
38- const device2 = await factory . createDevice ( { name : generateName ( 'device-2' ) } , TestObjects . team1 , null , TestObjects . application )
55+ const device2 = await factory . createDevice ( { name : generateName ( 'device-2' ) } , TestObjects . ATeam , null , TestObjects . application )
3956 TestObjects . device2 = await app . db . models . Device . byId ( device2 . id )
40- await TestObjects . team1 . addProject ( TestObjects . project2 )
57+ await TestObjects . ATeam . addProject ( TestObjects . project2 )
4158 TestObjects . tokens . project1 = ( await TestObjects . project1 . refreshAuthTokens ( ) ) . token
4259 TestObjects . tokens . project2 = ( await TestObjects . project2 . refreshAuthTokens ( ) ) . token
4360 TestObjects . tokens . device1 = ( await TestObjects . device1 . refreshAuthTokens ( ) ) . token
@@ -54,7 +71,7 @@ describe('Logging API', function () {
5471 after ( async ( ) => {
5572 app && await app . close ( )
5673 delete TestObjects . tokens
57- delete TestObjects . team1
74+ delete TestObjects . ATeam
5875 delete TestObjects . project1
5976 delete TestObjects . project2
6077 delete TestObjects . device1
@@ -63,7 +80,9 @@ describe('Logging API', function () {
6380 delete TestObjects . application
6481 app . db . controllers . Project . addProjectModule . restore ( )
6582 app . db . controllers . Project . removeProjectModule . restore ( )
83+ sinon . restore ( )
6684 } )
85+
6786 describe ( 'instance audit logging' , function ( ) {
6887 it ( 'Accepts valid token' , async function ( ) {
6988 const url = `/logging/${ TestObjects . project1 . id } /audit`
@@ -374,4 +393,63 @@ describe('Logging API', function () {
374393 } )
375394 } )
376395 } )
396+
397+ describe ( 'adds notification' , function ( ) {
398+ beforeEach ( function ( ) {
399+ sinon . stub ( app . notifications , 'send' )
400+ } )
401+ afterEach ( async function ( ) {
402+ await app . db . models . Notification . destroy ( { where : { } } )
403+ app . notifications . send . restore ( )
404+ } )
405+ it ( 'for every member and owner when instance crashed' , async function ( ) {
406+ await testSimulateLogEvent ( 'instance' , 'crashed' , 'error' , TestObjects . project1 , TestObjects . tokens . project1 )
407+ } )
408+ it ( 'for every member and owner when device crashed' , async function ( ) {
409+ await testSimulateLogEvent ( 'device' , 'crashed' , 'error' , TestObjects . device1 , TestObjects . tokens . device1 )
410+ } )
411+ it ( 'for every member and owner when instance safe-mode' , async function ( ) {
412+ await testSimulateLogEvent ( 'instance' , 'safe-mode' , 'warning' , TestObjects . project1 , TestObjects . tokens . project1 )
413+ } )
414+ it ( 'for every member and owner when device safe-mode' , async function ( ) {
415+ await testSimulateLogEvent ( 'device' , 'safe-mode' , 'warning' , TestObjects . device1 , TestObjects . tokens . device1 )
416+ } )
417+
418+ async function testSimulateLogEvent ( kind , event , severity , model , token ) {
419+ const id = kind === 'instance' ? model . id : model . hashid
420+ const type = `${ kind } -${ event } `
421+ const reference = `${ type } :${ id } `
422+ const baseUrl = kind === 'instance' ? '/logging' : '/logging/device'
423+ const url = `${ baseUrl } /${ id } /audit`
424+ const response = await app . inject ( {
425+ method : 'POST' ,
426+ url,
427+ headers : {
428+ authorization : `Bearer ${ token } `
429+ } ,
430+ payload : { event }
431+ } )
432+ response . should . have . property ( 'statusCode' , 200 )
433+ // should be called for every member and owner
434+ app . notifications . send . callCount . should . equal ( 3 ) // alice, bob, chris
435+ const calls = app . notifications . send . getCalls ( )
436+ for ( const call of calls ) {
437+ const args = call . args
438+ // func signature of notification.send (user, type, data, reference = null, options = null)
439+ args . should . have . length ( 5 )
440+ args [ 0 ] . should . be . an . instanceOf ( app . db . models . User )
441+ args [ 0 ] . should . have . property ( 'id' ) . and . be . oneOf ( [ TestObjects . alice . id , TestObjects . bob . id , TestObjects . chris . id ] )
442+ args [ 1 ] . should . equal ( type )
443+ args [ 2 ] . should . be . an . Object ( )
444+ args [ 2 ] . should . have . property ( kind ) . and . be . an . Object ( ) // instance or device
445+ args [ 2 ] [ kind ] . should . have . property ( 'id' ) . and . equal ( id )
446+ args [ 2 ] [ kind ] . should . have . property ( 'name' ) . and . equal ( model . name )
447+ args [ 2 ] . should . have . property ( 'meta' ) . and . be . an . Object ( )
448+ args [ 2 ] . meta . should . have . property ( 'severity' , severity )
449+ args [ 3 ] . should . equal ( reference )
450+ args [ 4 ] . should . be . an . Object ( )
451+ args [ 4 ] . should . have . property ( 'upsert' , true ) // crash and safe notifications use upsert option
452+ }
453+ }
454+ } )
377455} )
0 commit comments