github.com/Financial-Times/publish-availability-monitor@v1.12.0/messageHandler_test.go (about) 1 package main 2 3 import ( 4 "testing" 5 6 "github.com/Financial-Times/go-logger/v2" 7 "github.com/Financial-Times/kafka-client-go/v4" 8 "github.com/Financial-Times/publish-availability-monitor/content" 9 "github.com/stretchr/testify/assert" 10 ) 11 12 const syntheticTID = "SYNTHETIC-REQ-MONe4d2885f-1140-400b-9407-921e1c7378cd" 13 const carouselRepublishTID = "tid_ofcysuifp0_carousel_1488384556" 14 const carouselUnconventionalRepublishTID = "republish_-10bd337c-66d4-48d9-ab8a-e8441fa2ec98_carousel_1493606135" 15 const carouselGeneratedTID = "tid_ofcysuifp0_carousel_1488384556_gentx" 16 const naturalTID = "tid_xltcnbckvq" 17 18 func TestIsIgnorableMessage(t *testing.T) { 19 tests := map[string]struct { 20 TransactionID string 21 ExpectedResult bool 22 }{ 23 "normal message should not be ignored": { 24 TransactionID: naturalTID, 25 ExpectedResult: false, 26 }, 27 "synthetic message should be ignored": { 28 TransactionID: syntheticTID, 29 ExpectedResult: true, 30 }, 31 "carousel republish message should be ignored": { 32 TransactionID: carouselRepublishTID, 33 ExpectedResult: true, 34 }, 35 "carousel unconventional republish message should be ignored": { 36 TransactionID: carouselUnconventionalRepublishTID, 37 ExpectedResult: true, 38 }, 39 "carousel generated message should be ignored": { 40 TransactionID: carouselGeneratedTID, 41 ExpectedResult: true, 42 }, 43 } 44 45 for name, test := range tests { 46 t.Run(name, func(t *testing.T) { 47 h := kafkaMessageHandler{} 48 kafkaMessage := kafka.FTMessage{ 49 Headers: map[string]string{ 50 "X-Request-Id": test.TransactionID, 51 }, 52 } 53 54 got := h.isIgnorableMessage(kafkaMessage) 55 56 if got != test.ExpectedResult { 57 t.Fatalf("expected %v, got %v", test.ExpectedResult, got) 58 } 59 }) 60 } 61 } 62 63 func TestTestIsIgnorableMessage_SyntheticE2ETest(t *testing.T) { 64 e2eTestUUIDs := []string{"e4d2885f-1140-400b-9407-921e1c7378cd"} 65 log := logger.NewUPPLogger("publish-availability-monitor", "INFO") 66 67 mh := NewKafkaMessageHandler(nil, nil, nil, nil, nil, e2eTestUUIDs, log) 68 kmh := mh.(*kafkaMessageHandler) 69 70 kafkaMessage := kafka.FTMessage{ 71 Headers: map[string]string{ 72 "X-Request-Id": syntheticTID, 73 }, 74 } 75 76 assert.Equal(t, false, kmh.isIgnorableMessage(kafkaMessage)) 77 } 78 79 func TestUnmarshalContent_InvalidMessageMissingHeader_Error(t *testing.T) { 80 h := kafkaMessageHandler{} 81 if _, err := h.unmarshalContent(invalidMessageWrongHeader); err == nil { 82 t.Error("Expected failure, but message with missing system ID successfully unmarshalled!") 83 } 84 } 85 86 func TestUnmarshalContent_InvalidMessageWrongSystemId_Error(t *testing.T) { 87 h := kafkaMessageHandler{} 88 if _, err := h.unmarshalContent(invalidMessageWrongSystemID); err == nil { 89 t.Error("Expected failure, but message with wrong system ID successfully unmarshalled!") 90 } 91 } 92 93 func TestUnmarshalContent_ValidVideoMessage(t *testing.T) { 94 testCases := []struct { 95 videoMessage kafka.FTMessage 96 }{ 97 {validVideoMsg}, 98 {validVideoMsg2}, 99 } 100 101 h := kafkaMessageHandler{} 102 log := logger.NewUPPLogger("test", "PANIC") 103 104 for _, testCase := range testCases { 105 resultContent, err := h.unmarshalContent(testCase.videoMessage) 106 if err != nil { 107 t.Errorf("Expected success, but error occurred [%v]", err) 108 return 109 } 110 valRes := resultContent.Validate("", "", "", "", log) 111 assert.False(t, valRes.IsMarkedDeleted, "Expected published content.") 112 } 113 } 114 115 func TestUnmarshalContent_ValidDeletedVideoMessage(t *testing.T) { 116 h := kafkaMessageHandler{} 117 resultContent, err := h.unmarshalContent(validDeleteVideoMsg) 118 if err != nil { 119 t.Errorf("Expected success, but error occurred [%v]", err) 120 return 121 } 122 log := logger.NewUPPLogger("test", "PANIC") 123 124 valRes := resultContent.Validate("", "", "", "", log) 125 assert.True(t, valRes.IsMarkedDeleted, "Expected deleted content.") 126 } 127 128 func TestUnmarshalContent_InvalidVideoMessage(t *testing.T) { 129 h := kafkaMessageHandler{} 130 resultContent, err := h.unmarshalContent(invalidVideoMsg) 131 if err != nil { 132 t.Errorf("Expected success, but error occurred [%v]", err) 133 return 134 } 135 log := logger.NewUPPLogger("test", "PANIC") 136 137 valRes := resultContent.Validate("", "", "", "", log) 138 assert.False(t, valRes.IsValid, "Expected invalid content.") 139 } 140 141 func TestUnmarshalContent_VideoBinaryContentSet(t *testing.T) { 142 h := kafkaMessageHandler{} 143 resultContent, err := h.unmarshalContent(validVideoMsg) 144 assert.NoError(t, err) 145 146 video, ok := resultContent.(content.Video) 147 assert.True(t, ok) 148 149 assert.Equal(t, []byte(validVideoMsg.Body), video.BinaryContent) 150 } 151 152 func TestUnmarshalContent_GenericContent(t *testing.T) { 153 h := kafkaMessageHandler{} 154 155 resultContent, err := h.unmarshalContent(validGenericContentMessage) 156 assert.NoError(t, err) 157 158 genericContent, ok := resultContent.(content.GenericContent) 159 assert.True(t, ok) 160 161 assert.Equal(t, "077f5ac2-0491-420e-a5d0-982e0f86204b", genericContent.UUID) 162 assert.Equal(t, validGenericContentMessage.Headers["Content-Type"], genericContent.Type) 163 assert.Equal(t, []byte(validGenericContentMessage.Body), genericContent.BinaryContent) 164 assert.False(t, genericContent.Deleted) 165 } 166 167 func TestUnmarshalContent_DeletedGenericContent(t *testing.T) { 168 h := kafkaMessageHandler{} 169 170 resultContent, err := h.unmarshalContent(validDeletedGenericContentMessage) 171 assert.NoError(t, err) 172 173 genericContent, ok := resultContent.(content.GenericContent) 174 assert.True(t, ok) 175 176 assert.Equal(t, "077f5ac2-0491-420e-a5d0-982e0f86204b", genericContent.GetUUID()) 177 assert.Equal(t, validDeletedGenericContentMessage.Headers["Content-Type"], genericContent.GetType()) 178 assert.Equal(t, []byte(validDeletedGenericContentMessage.Body), genericContent.BinaryContent) 179 assert.True(t, genericContent.Deleted) 180 } 181 182 func TestUnmarshalContent_GenericContent_Audio(t *testing.T) { 183 h := kafkaMessageHandler{} 184 185 resultContent, err := h.unmarshalContent(validGenericAudioMessage) 186 assert.NoError(t, err) 187 188 genericContent, ok := resultContent.(content.GenericContent) 189 assert.True(t, ok) 190 191 assert.Equal(t, "be003650-6c8f-4665-8640-9cbf292bb580", genericContent.UUID) 192 assert.Equal(t, validGenericAudioMessage.Headers["Content-Type"], genericContent.Type) 193 assert.Equal(t, []byte(validGenericAudioMessage.Body), genericContent.BinaryContent) 194 } 195 196 var invalidMessageWrongHeader = kafka.FTMessage{ 197 Headers: map[string]string{ 198 "Foobar-System-Id": "http://cmdb.ft.com/systems/cct", 199 }, 200 Body: "{}", 201 } 202 var invalidMessageWrongSystemID = kafka.FTMessage{ 203 Headers: map[string]string{ 204 "Origin-System-Id": "web-foobar", 205 }, 206 Body: "{}", 207 } 208 209 var validVideoMsg = kafka.FTMessage{ 210 Headers: map[string]string{ 211 "Origin-System-Id": "http://cmdb.ft.com/systems/next-video-editor", 212 }, 213 Body: `{ 214 "id": "e28b12f7-9796-3331-b030-05082f0b8157" 215 }`, 216 } 217 218 var validVideoMsg2 = kafka.FTMessage{ 219 Headers: map[string]string{ 220 "Origin-System-Id": "http://cmdb.ft.com/systems/next-video-editor", 221 }, 222 Body: `{ 223 "id": "e28b12f7-9796-3331-b030-05082f0b8157", 224 "deleted": false 225 }`, 226 } 227 228 var validDeleteVideoMsg = kafka.FTMessage{ 229 Headers: map[string]string{ 230 "Origin-System-Id": "http://cmdb.ft.com/systems/next-video-editor", 231 }, 232 Body: `{ 233 "id": "e28b12f7-9796-3331-b030-05082f0b8157", 234 "deleted": true 235 }`, 236 } 237 238 var invalidVideoMsg = kafka.FTMessage{ 239 Headers: map[string]string{ 240 "Origin-System-Id": "http://cmdb.ft.com/systems/next-video-editor", 241 }, 242 Body: `{ 243 "uuid": "e28b12f7-9796-3331-b030-05082f0b8157", 244 "something_else": "something else" 245 }`, 246 } 247 248 var validGenericContentMessage = kafka.FTMessage{ 249 Headers: map[string]string{ 250 "Origin-System-Id": "http://cmdb.ft.com/systems/cct", 251 "X-Request-Id": "tid_0123wxyz", 252 "Content-Type": "application/vnd.ft-upp-article-internal", 253 }, 254 Body: `{ 255 "uuid": "077f5ac2-0491-420e-a5d0-982e0f86204b", 256 "title": "A title", 257 "type": "Article", 258 "byline": "A byline", 259 "identifiers": [ 260 { 261 "authority": "an authority", 262 "identifierValue": "some identifier value" 263 }, 264 { 265 "authority": "another authority", 266 "identifierValue": "some other identifier value" 267 } 268 ], 269 "publishedDate": "2014-12-23T20:45:54.000Z", 270 "firstPublishedDate": "2014-12-22T20:45:54.000Z", 271 "bodyXML": "<body>Lorem ipsum</body>", 272 "editorialDesk": "some string editorial desk identifier", 273 "description": "Some descriptive explanation for this content", 274 "mainImage": "0000aa3c-0056-506b-2b73-ed90e21b3e64", 275 "standout": { 276 "editorsChoice": false, 277 "exclusive": false, 278 "scoop": false 279 }, 280 "webUrl": "http://some.external.url.com/content", 281 "canBeSyndicated" : "verify", 282 "accessLevel" : "premium", 283 "canBeDistributed": "no", 284 "someUnknownProperty" : " is totally fine, we don't validate for unknown fields/properties" 285 }`, 286 } 287 288 var validDeletedGenericContentMessage = kafka.FTMessage{ 289 Headers: map[string]string{ 290 "Origin-System-Id": "http://cmdb.ft.com/systems/cct", 291 "X-Request-Id": "tid_0123wxyz", 292 "Content-Type": "application/vnd.ft-upp-article-internal", 293 }, 294 Body: `{ 295 "uuid": "077f5ac2-0491-420e-a5d0-982e0f86204b", 296 "title": "A title", 297 "type": "Article", 298 "byline": "A byline", 299 "identifiers": [ 300 { 301 "authority": "an authority", 302 "identifierValue": "some identifier value" 303 }, 304 { 305 "authority": "another authority", 306 "identifierValue": "some other identifier value" 307 } 308 ], 309 "publishedDate": "2014-12-23T20:45:54.000Z", 310 "firstPublishedDate": "2014-12-22T20:45:54.000Z", 311 "bodyXML": "<body>Lorem ipsum</body>", 312 "deleted": true 313 }`, 314 } 315 316 var validGenericAudioMessage = kafka.FTMessage{ 317 Headers: map[string]string{ 318 "Origin-System-Id": "http://cmdb.ft.com/systems/next-video-editor", 319 "X-Request-Id": "tid_0123wxyz", 320 "Content-Type": "application/vnd.ft-upp-audio", 321 }, 322 Body: `{ 323 "title":"Is bitcoin a fraud?", 324 "byline":"News features and analysis from Financial Times reporters around the world. FT News in Focus is produced by Fiona Symon.", 325 "canBeSyndicated":"yes", 326 "firstPublishedDate":"2017-09-19T17:58:51.000Z", 327 "publishedDate":"2017-09-19T17:58:51.000Z", 328 "uuid":"be003650-6c8f-4665-8640-9cbf292bb580", 329 "type":"Audio", 330 "body":"<body><p>The value of bitcoin fell sharply last week after Jamie Dimon, head of JPMorgan Chase, suggested the digital currency craze would suffer the same fate as the tulip mania of the 17th century. Patrick Jenkins discusses whether he is right with the FT's Laura Noonan and Izabella Kaminska. Music by Kevin MacLeod</p></body>", 331 "mainImage":"56e9f220-6c64-4b6a-afcd-b57e1ceec807", 332 "identifiers":[ 333 { 334 "authority":"http://www.acast.com/", 335 "identifierValue":"https://rss.acast.com/ft-news" 336 }, 337 { 338 "authority":"http://www.acast.com/", 339 "identifierValue":"https://www.acast.com/ft-news/isbitcoinafraud-" 340 }, 341 { 342 "authority":"http://api.ft.com/system/NEXT-VIDEO-EDITOR", 343 "identifierValue":"be003650-6c8f-4665-8640-9cbf292bb580" 344 } 345 ], 346 "dataSource":[ 347 { 348 "binaryUrl":"https://media.acast.com/ft-news/isbitcoinafraud-/media.mp3", 349 "duration":412000, 350 "mediaType":"audio/mpeg" 351 } 352 ] 353 }`, 354 }