@@ -3,16 +3,25 @@ package com.gu.mobile.notifications.football.lib
33import java .time .ZonedDateTime
44import java .util .UUID
55
6+ import com .gu .mobile .notifications .client .models .liveActitivites .FootballMatchContentState
7+ import org .specs2 .mock .Mockito
68import org .specs2 .mutable .Specification
79import org .specs2 .specification .Scope
810import pa .{MatchDay , MatchDayTeam , Round , Stage }
911
10- class SyntheticMatchEventGeneratorSpec extends Specification {
12+ import scala .concurrent .{ExecutionContext , Future }
13+
14+ class SyntheticMatchEventGeneratorSpec extends Specification with Mockito {
1115
1216 trait TestScope extends Scope {
1317 val home = MatchDayTeam (" 1" , " Liverpool" , None , None , None , None )
1418 val away = MatchDayTeam (" 2" , " Plymouth" , None , None , None , None )
1519
20+ // The match state differ can be a mock for now - by default we report the state as identical
21+ // so that no synthetic state-change event is emitted and the other assertions are unaffected.
22+ val matchStateDiffer = mock[DynamoMatchStateDiffer ]
23+ matchStateDiffer.isIdentical(any[String ], any[FootballMatchContentState ])(any[ExecutionContext ]) returns Future .successful(true )
24+
1625 val matchInfo = MatchDay (
1726 id = " some-match-id" ,
1827 date = ZonedDateTime .parse(" 2000-01-01T00:00:00Z" ),
@@ -56,118 +65,132 @@ class SyntheticMatchEventGeneratorSpec extends Specification {
5665
5766 " A SyntheticMatchEvent generator" should {
5867 " Add id to first timeline event" in new TestScope {
59- val generator = new SyntheticMatchEventGenerator (currentTime)
68+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
6069 generator.generate(List (timelineEvent), " match-id" , matchInfo) mustEqual List (timelineEvent.copy(id = Some (kickoffId)))
6170 }
6271 " Add half-time event if status is HT" in new TestScope {
63- val generator = new SyntheticMatchEventGenerator (currentTime)
72+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
6473 generator.generate(List (timelineEvent), " match-id" , matchInfo.copy(matchStatus = " HT" )).drop(1 ).head.eventType mustEqual " half-time"
6574 }
6675 " Add second-half event if status is SHS" in new TestScope {
67- val generator = new SyntheticMatchEventGenerator (currentTime)
76+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
6877 generator.generate(List (timelineEvent), " match-id" , matchInfo.copy(matchStatus = " SHS" )).drop(1 ).head.eventType mustEqual " second-half"
6978 }
7079 " Add full-time event if match is result" in new TestScope {
71- val generator = new SyntheticMatchEventGenerator (currentTime)
80+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
7281 generator.generate(List (timelineEvent), " match-id" , matchInfo.copy(result = true , liveMatch = true )).drop(1 ).head.eventType mustEqual " full-time"
7382 }
7483
7584 " Add extra time event if status is ETS" in new TestScope {
76- val generator = new SyntheticMatchEventGenerator (currentTime)
85+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
7786 generator.generate(List (timelineEvent), " match-id" , matchInfo.copy(matchStatus = " ETS" )).drop(1 ).head.eventType mustEqual " extra-time-first-half"
7887 }
7988
8089 " Add extra time half time event if status is ETHT" in new TestScope {
81- val generator = new SyntheticMatchEventGenerator (currentTime)
90+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
8291 generator.generate(List (timelineEvent), " match-id" , matchInfo.copy(matchStatus = " ETHT" )).drop(1 ).head.eventType mustEqual " extra-time-half-time"
8392 }
8493
8594 " Add extra time second half event if status is ETSHS" in new TestScope {
86- val generator = new SyntheticMatchEventGenerator (currentTime)
95+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
8796 generator.generate(List (timelineEvent), " match-id" , matchInfo.copy(matchStatus = " ETSHS" )).drop(1 ).head.eventType mustEqual " extra-time-second-half"
8897 }
8998
9099 " Add penalty shootout event if status is PT" in new TestScope {
91- val generator = new SyntheticMatchEventGenerator (currentTime)
100+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
92101 generator.generate(List (timelineEvent), " match-id" , matchInfo.copy(matchStatus = " PT" )).drop(1 ).head.eventType mustEqual " penalties"
93102 }
94103
95104 " Add extra-time-to-be-played event if status is FTET" in new TestScope {
96- val generator = new SyntheticMatchEventGenerator (currentTime)
105+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
97106 generator.generate(List (timelineEvent), " match-id" , matchInfo.copy(matchStatus = " FTET" )).drop(1 ).head.eventType mustEqual " extra-time-to-be-played"
98107 }
99108
100109 " Add penalties-to-be-played event if status is FTPT" in new TestScope {
101- val generator = new SyntheticMatchEventGenerator (currentTime)
110+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
102111 generator.generate(List (timelineEvent), " match-id" , matchInfo.copy(matchStatus = " FTPT" )).drop(1 ).head.eventType mustEqual " penalties-to-be-played"
103112 }
104113
105114 " Add penalties-to-be-played event if status is ETFTPT" in new TestScope {
106- val generator = new SyntheticMatchEventGenerator (currentTime)
115+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
107116 generator.generate(List (timelineEvent), " match-id" , matchInfo.copy(matchStatus = " ETFTPT" )).drop(1 ).head.eventType mustEqual " penalties-to-be-played"
108117 }
109118
110119 " Add suspended event if status is Suspended" in new TestScope {
111- val generator = new SyntheticMatchEventGenerator (currentTime)
120+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
112121 generator.generate(List (timelineEvent), " match-id" , matchInfo.copy(matchStatus = " Suspended" )).drop(1 ).head.eventType mustEqual " suspended"
113122 }
114123
115124 " Add resumed event if status is Resumed" in new TestScope {
116- val generator = new SyntheticMatchEventGenerator (currentTime)
125+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
117126 generator.generate(List (timelineEvent), " match-id" , matchInfo.copy(matchStatus = " Resumed" )).drop(1 ).head.eventType mustEqual " resumed"
118127 }
119128
120129 " Add abandoned event if status is Abandoned" in new TestScope {
121- val generator = new SyntheticMatchEventGenerator (currentTime)
130+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
122131 generator.generate(List (timelineEvent), " match-id" , matchInfo.copy(matchStatus = " Abandoned" )).drop(1 ).head.eventType mustEqual " abandoned"
123132 }
124133
125134 " Add postponed event if status is Postponed" in new TestScope {
126- val generator = new SyntheticMatchEventGenerator (currentTime)
135+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
127136 generator.generate(List (timelineEvent), " match-id" , matchInfo.copy(matchStatus = " Postponed" )).drop(1 ).head.eventType mustEqual " postponed"
128137 }
129138
130139 " Add cancelled event if status is Cancelled" in new TestScope {
131- val generator = new SyntheticMatchEventGenerator (currentTime)
140+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
132141 generator.generate(List (timelineEvent), " match-id" , matchInfo.copy(matchStatus = " Cancelled" )).drop(1 ).head.eventType mustEqual " cancelled"
133142 }
134143
135144 }
136145
137146 " A SyntheticMatchEvent generator supporting Live Activities" should {
138147 " Add a createChannel event if match kick off is within 2 hrs" in new TestScope {
139- val generator = new SyntheticMatchEventGenerator (currentTime)
148+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
140149 generator.generate(List (), " match-id" , matchInfo.copy(date = ZonedDateTime .now.plusHours(1 ))).head.eventType mustEqual " create-channel"
141150 }
142151
143152 " Add a startLiveActivity event if match kick off is within 20min" in new TestScope {
144- val generator = new SyntheticMatchEventGenerator (currentTime)
153+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
145154 generator.generate(List (), " match-id" , matchInfo.copy(date = ZonedDateTime .now.plusMinutes(15 ))).map(_.eventType) must contain(" start-live-activity" )
146155 }
147156
148157 " Add id to first timeline event" in new TestScope {
149- val generator = new SyntheticMatchEventGenerator (currentTime)
158+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
150159 generator.generate(List (timelineEvent), " match-id" , matchInfo.copy(date = ZonedDateTime .now())) mustEqual List (timelineEvent.copy(id = Some (kickoffId)))
151160 }
152161
153162 " Add an endLiveActivity event if match info contains result" in new TestScope {
154- val generator = new SyntheticMatchEventGenerator (currentTime)
163+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
155164 generator.generate(List (timelineEvent), " match-id" , matchInfo.copy(result = true , liveMatch = false )).reverse.head.eventType mustEqual " end-live-activity"
156165 }
157166
158167 " Add a pre-match event if match kick off is within 20min" in new TestScope {
159- val generator = new SyntheticMatchEventGenerator (currentTime)
168+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer )
160169 val events = generator.generate(List (), " match-id" , matchInfo.copy(date = ZonedDateTime .now.plusMinutes(15 )))
161170 events.map(_.eventType) must contain(" pre-match" )
162171 }
163172 }
164173
165174 " A SyntheticMatchEvent generator supporting StateChangeEvents" should {
166175 " Create state change event if calculated match state differs" in new TestScope {
167- val generator = new SyntheticMatchEventGenerator (currentTime)
176+ // Report the state as different and allow the update to succeed so a state-change event is emitted.
177+ matchStateDiffer.isIdentical(any[String ], any[FootballMatchContentState ])(any[ExecutionContext ]) returns Future .successful(false )
178+ matchStateDiffer.updateState(any[String ], any[FootballMatchContentState ])(any[ExecutionContext ]) returns Future .unit
179+
180+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer)
168181 val events = generator.generate(List (timelineEvent), " match-id" , matchInfo)
169182 events.map(_.eventType) must contain(" state-change" )
170183 }
171184
185+ " Not create state change event if calculated match state is identical" in new TestScope {
186+ // Report the state as different and allow the update to succeed so a state-change event is emitted.
187+ matchStateDiffer.isIdentical(any[String ], any[FootballMatchContentState ])(any[ExecutionContext ]) returns Future .successful(true )
188+ matchStateDiffer.updateState(any[String ], any[FootballMatchContentState ])(any[ExecutionContext ]) returns Future .unit
189+
190+ val generator = new SyntheticMatchEventGenerator (currentTime, matchStateDiffer)
191+ val events = generator.generate(List (timelineEvent), " match-id" , matchInfo)
192+ events.map(_.eventType) must not contain(" state-change" )
193+ }
194+
172195 }
173196}
0 commit comments