@@ -4,7 +4,13 @@ import { MeteorMock } from '../../__mocks__/meteor'
4
4
import { logger } from '../logging'
5
5
import { getRandomId , getRandomString , literal , protectString } from '../lib/tempLib'
6
6
import { SnapshotType } from '@sofie-automation/meteor-lib/dist/collections/Snapshots'
7
- import { IBlueprintPieceType , PieceLifespan , StatusCode , TSR } from '@sofie-automation/blueprints-integration'
7
+ import {
8
+ IBlueprintPieceType ,
9
+ PieceLifespan ,
10
+ PlaylistTimingType ,
11
+ StatusCode ,
12
+ TSR ,
13
+ } from '@sofie-automation/blueprints-integration'
8
14
import {
9
15
PeripheralDeviceType ,
10
16
PeripheralDeviceCategory ,
@@ -27,6 +33,8 @@ import {
27
33
SegmentId ,
28
34
SnapshotId ,
29
35
UserActionsLogItemId ,
36
+ StudioId ,
37
+ RundownPlaylistId ,
30
38
} from '@sofie-automation/corelib/dist/dataModel/Ids'
31
39
32
40
// Set up mocks for tests in this suite
@@ -53,6 +61,8 @@ import {
53
61
UserActionsLog ,
54
62
Segments ,
55
63
SofieIngestDataCache ,
64
+ Studios ,
65
+ RundownPlaylists ,
56
66
} from '../collections'
57
67
import { NrcsIngestCacheType } from '@sofie-automation/corelib/dist/dataModel/NrcsIngestDataCache'
58
68
import { JSONBlobStringify } from '@sofie-automation/shared-lib/dist/lib/JSONBlob'
@@ -64,7 +74,7 @@ import {
64
74
import { DBSegment } from '@sofie-automation/corelib/dist/dataModel/Segment'
65
75
import { Settings } from '../Settings'
66
76
import { SofieIngestCacheType } from '@sofie-automation/corelib/dist/dataModel/SofieIngestDataCache'
67
- import { ObjectOverrideSetOp } from '@sofie-automation/corelib/dist/settings/objectWithOverrides'
77
+ import { ObjectOverrideSetOp , ObjectWithOverrides } from '@sofie-automation/corelib/dist/settings/objectWithOverrides'
68
78
69
79
describe ( 'cronjobs' , ( ) => {
70
80
let env : DefaultEnvironment
@@ -476,7 +486,10 @@ describe('cronjobs', () => {
476
486
expect ( await Snapshots . findOneAsync ( snapshot1 ) ) . toBeUndefined ( )
477
487
} )
478
488
async function insertPlayoutDevice (
479
- props : Pick < PeripheralDevice , 'subType' | 'deviceName' | 'lastSeen' | 'parentDeviceId' > &
489
+ props : Pick <
490
+ PeripheralDevice ,
491
+ 'subType' | 'deviceName' | 'lastSeen' | 'parentDeviceId' | 'studioAndConfigId'
492
+ > &
480
493
Partial < Pick < PeripheralDevice , 'token' > >
481
494
) : Promise < PeripheralDeviceId > {
482
495
const deviceId = protectString < PeripheralDeviceId > ( getRandomString ( ) )
@@ -504,7 +517,10 @@ describe('cronjobs', () => {
504
517
return deviceId
505
518
}
506
519
507
- async function createMockPlayoutGatewayAndDevices ( lastSeen : number ) : Promise < {
520
+ async function createMockPlayoutGatewayAndDevices (
521
+ lastSeen : number ,
522
+ studioId ?: StudioId
523
+ ) : Promise < {
508
524
deviceToken : string
509
525
mockPlayoutGw : PeripheralDeviceId
510
526
mockCasparCg : PeripheralDeviceId
@@ -516,6 +532,12 @@ describe('cronjobs', () => {
516
532
lastSeen : lastSeen ,
517
533
subType : PERIPHERAL_SUBTYPE_PROCESS ,
518
534
token : deviceToken ,
535
+ studioAndConfigId : studioId
536
+ ? {
537
+ configId : '' ,
538
+ studioId,
539
+ }
540
+ : undefined ,
519
541
} )
520
542
const mockCasparCg = await insertPlayoutDevice ( {
521
543
deviceName : 'CasparCG' ,
@@ -540,6 +562,73 @@ describe('cronjobs', () => {
540
562
}
541
563
}
542
564
565
+ async function createMockStudioAndRundown ( ) : Promise < {
566
+ studioId : StudioId
567
+ rundownPlaylistId : RundownPlaylistId
568
+ } > {
569
+ function newObjectWithOverrides < T extends { } > ( defaults : T ) : ObjectWithOverrides < T > {
570
+ return {
571
+ defaults,
572
+ overrides : [ ] ,
573
+ }
574
+ }
575
+ const studioId = protectString < StudioId > ( getRandomString ( ) )
576
+ await Studios . insertAsync ( {
577
+ _id : studioId ,
578
+ organizationId : null ,
579
+ name : 'Studio' ,
580
+ blueprintConfigWithOverrides : newObjectWithOverrides ( { } ) ,
581
+ _rundownVersionHash : '' ,
582
+ lastBlueprintConfig : undefined ,
583
+ lastBlueprintFixUpHash : undefined ,
584
+ mappingsWithOverrides : newObjectWithOverrides ( { } ) ,
585
+ supportedShowStyleBase : [ ] ,
586
+ settingsWithOverrides : newObjectWithOverrides ( {
587
+ allowHold : true ,
588
+ allowPieceDirectPlay : true ,
589
+ enableBuckets : true ,
590
+ enableEvaluationForm : true ,
591
+ frameRate : 25 ,
592
+ mediaPreviewsUrl : '' ,
593
+ minimumTakeSpan : 1000 ,
594
+ } ) ,
595
+ routeSetsWithOverrides : newObjectWithOverrides ( { } ) ,
596
+ routeSetExclusivityGroupsWithOverrides : newObjectWithOverrides ( { } ) ,
597
+ packageContainersWithOverrides : newObjectWithOverrides ( { } ) ,
598
+ previewContainerIds : [ ] ,
599
+ thumbnailContainerIds : [ ] ,
600
+ peripheralDeviceSettings : {
601
+ deviceSettings : newObjectWithOverrides ( { } ) ,
602
+ ingestDevices : newObjectWithOverrides ( { } ) ,
603
+ inputDevices : newObjectWithOverrides ( { } ) ,
604
+ playoutDevices : newObjectWithOverrides ( { } ) ,
605
+ } ,
606
+ } )
607
+
608
+ const rundownPlaylistId = protectString < RundownPlaylistId > ( getRandomString ( ) )
609
+ await RundownPlaylists . mutableCollection . insertAsync ( {
610
+ _id : rundownPlaylistId ,
611
+ created : Date . now ( ) ,
612
+ currentPartInfo : null ,
613
+ nextPartInfo : null ,
614
+ externalId : '' ,
615
+ modified : Date . now ( ) ,
616
+ name : 'Rundown' ,
617
+ previousPartInfo : null ,
618
+ rundownIdsInOrder : [ ] ,
619
+ studioId,
620
+ timing : {
621
+ type : PlaylistTimingType . None ,
622
+ } ,
623
+ activationId : protectString ( '' ) ,
624
+ } )
625
+
626
+ return {
627
+ studioId,
628
+ rundownPlaylistId,
629
+ }
630
+ }
631
+
543
632
test ( 'Attempts to restart CasparCG when job is enabled' , async ( ) => {
544
633
const { mockCasparCg, deviceToken } = await createMockPlayoutGatewayAndDevices ( Date . now ( ) ) // Some time after the threshold
545
634
@@ -605,6 +694,28 @@ describe('cronjobs', () => {
605
694
expect ( logger . info ) . toHaveBeenLastCalledWith ( 'Nightly cronjob: done' )
606
695
} , MAX_WAIT_TIME )
607
696
} )
697
+ test ( 'Skips CasparCG in Studios with active Playlists when job is enabled' , async ( ) => {
698
+ const { studioId } = await createMockStudioAndRundown ( )
699
+ await createMockPlayoutGatewayAndDevices ( Date . now ( ) , studioId ) // Some time after the threshold
700
+ ; ( logger . info as jest . Mock ) . mockClear ( )
701
+ // set time to 2020/07/{date} 04:05 Local Time, should be more than 24 hours after 2020/07/19 00:00 UTC
702
+ mockCurrentTime = new Date ( 2020 , 6 , date ++ , 4 , 5 , 0 ) . getTime ( )
703
+ // cronjob is checked every 5 minutes, so advance 6 minutes
704
+ await jest . advanceTimersByTimeAsync ( 6 * 60 * 1000 )
705
+
706
+ await waitUntil ( async ( ) => {
707
+ // Run timers, so that all promises in the cronjob has a chance to resolve:
708
+ const pendingCommands = await PeripheralDeviceCommands . findFetchAsync ( { } )
709
+ expect ( pendingCommands ) . toHaveLength ( 0 )
710
+ } , MAX_WAIT_TIME )
711
+
712
+ // make sure that the cronjob ends
713
+ await waitUntil ( async ( ) => {
714
+ // Run timers, so that all promises in the cronjob has a chance to resolve:
715
+ await runAllTimers ( )
716
+ expect ( logger . info ) . toHaveBeenLastCalledWith ( 'Nightly cronjob: done' )
717
+ } , MAX_WAIT_TIME )
718
+ } )
608
719
test ( 'Does not attempt to restart CasparCG when job is disabled' , async ( ) => {
609
720
await createMockPlayoutGatewayAndDevices ( Date . now ( ) ) // Some time after the threshold
610
721
await setCasparCGCronEnabled ( false )
0 commit comments