From 0b3e9fa301f490c171264d0398cb1d93aabdd0a2 Mon Sep 17 00:00:00 2001 From: Carmel Eve <39550338+carmeleve@users.noreply.github.com> Date: Fri, 13 Mar 2020 07:39:53 +0000 Subject: [PATCH] Handle scenario where message fragments never arrive (#56) Co-authored-by: Ian Griffiths Co-authored-by: Carmel Eve --- .../NmeaAisMessageStreamProcessorBindings.cs | 10 + .../NmeaLineToAisStreamAdapterSpecs.feature | 29 ++ ...NmeaLineToAisStreamAdapterSpecs.feature.cs | 289 ++++++++++++------ .../NmeaLineToAisStreamAdapterSpecsSteps.cs | 29 +- .../Ais/Net/NmeaLineToAisStreamAdapter.cs | 75 ++++- .../Ais.Net/Ais/Net/NmeaParserOptions.cs | 50 +++ docs/adr/0002-missing-fragment-handling.md | 17 ++ 7 files changed, 379 insertions(+), 120 deletions(-) create mode 100644 docs/adr/0002-missing-fragment-handling.md diff --git a/Solutions/Ais.Net.Specs/Ais/Net/Specs/NmeaAisMessageStreamProcessorBindings.cs b/Solutions/Ais.Net.Specs/Ais/Net/Specs/NmeaAisMessageStreamProcessorBindings.cs index ce329ed..3a54ee5 100644 --- a/Solutions/Ais.Net.Specs/Ais/Net/Specs/NmeaAisMessageStreamProcessorBindings.cs +++ b/Solutions/Ais.Net.Specs/Ais/Net/Specs/NmeaAisMessageStreamProcessorBindings.cs @@ -98,6 +98,16 @@ public void ThenTheMessageErrorReportShouldIncludeAnExceptionReportingThatItHasR Assert.AreEqual(expectedStart, e.Message.Substring(0, expectedStart.Length)); } + [Then("the message error report (.*) should include an exception reporting that it received an incomplete set of fragments for a message")] + public void ThenTheMessageErrorReportShouldIncludeAnExceptionReportingThatItReceivedAnIncompleteSetOfFragmentsForAMessage(int errorCallNumber) + { + NmeaAisMessageStreamProcessorBindings.ErrorReport call = this.OnErrorCalls[errorCallNumber]; + Assert.IsInstanceOf(call.Error); + + var e = (ArgumentException)call.Error; + Assert.AreEqual("Received incomplete fragmented message.", e.Message); + } + [Then("the message error report (.*) should include the line number (.*)")] public void ThenTheMessageErrorReportShouldIncludeTheLineNumber(int errorCallNumber, int lineNumber) { diff --git a/Solutions/Ais.Net.Specs/Ais/Net/Specs/NmeaLineToAisStreamAdapterSpecs.feature b/Solutions/Ais.Net.Specs/Ais/Net/Specs/NmeaLineToAisStreamAdapterSpecs.feature index 732dd10..e896e82 100644 --- a/Solutions/Ais.Net.Specs/Ais/Net/Specs/NmeaLineToAisStreamAdapterSpecs.feature +++ b/Solutions/Ais.Net.Specs/Ais/Net/Specs/NmeaLineToAisStreamAdapterSpecs.feature @@ -88,6 +88,8 @@ Scenario: Interleaved multi-fragment messages And in ais message 1 the timestamp from the first NMEA line should be 1567686150 Scenario: Interleaved single and multi-fragment messages + # This test interleaves more extensively than we ever see in reality, so we have to extend our reassembly window + Given I have configured a MaximumUnmatchedFragmentAge of 10 # ais.kystverket.no When the line to message adapter receives '\s:42,c:1567684904*38\!AIVDM,1,1,,B,33m9UtPP@50wwE:VJW6LS67H01<@,0*3C' # ais.kystverket.no @@ -157,6 +159,8 @@ Scenario: Interleaved single and multi-fragment messages And in ais message 9 the timestamp from the first NMEA line should be 1567693618 Scenario: Progress reports + # This test interleaves more extensively than we ever see in reality, so we have to extend our reassembly window + Given I have configured a MaximumUnmatchedFragmentAge of 10 # ais.kystverket.no When the line to message adapter receives '\s:42,c:1567684904*38\!AIVDM,1,1,,B,33m9UtPP@50wwE:VJW6LS67H01<@,0*3C' # ais.kystverket.no @@ -238,6 +242,31 @@ Scenario: Line stream parser passes the same sentence of a two-part message twic And the message error report 0 should include an exception reporting that it has received two message fragments with the same group id and position And the message error report 0 should include the line number 2 +Scenario: Two-fragment message fragments received too many sentences in the middle + Given I have configured a MaximumUnmatchedFragmentAge of 1 + # ais.kystverket.no + When the line to message adapter receives '\g:1-2-8055,s:99,c:1567685556*4E\!AIVDM,2,1,6,B,53oGfN42=WRDhlHn221<4i@Dr22222222222220`1@O6640Ht50Skp4mR`4l,0*72' + # ais.kystverket.no + And the line to message adapter receives '\s:42,c:1567684904*38\!AIVDM,1,1,,B,33m9UtPP@50wwE:VJW6LS67H01<@,0*3C' + # ais.kystverket.no + And the line to message adapter receives '\s:3,c:1567692251*01\!AIVDM,1,1,,A,13m9WS001d0K==pR=D?HB6WD0pJV,0*54,0*63' + # ais.kystverket.no + And the line to message adapter receives '\g:2-2-8055*55\!AIVDM,2,2,6,B,j`888888880,2*2B' + Then INmeaAisMessageStreamProcessor.OnNext should have been called 2 times + Then INmeaAisMessageStreamProcessor.OnError should have been called 1 time + # ais.kystverket.no + And in ais message 0 the payload should be '33m9UtPP@50wwE:VJW6LS67H01<@' with padding of 0 + And in ais message 0 the source from the first NMEA line should be 42 + And in ais message 0 the timestamp from the first NMEA line should be 1567684904 + # ais.kystverket.no + And in ais message 1 the payload should be '13m9WS001d0K==pR=D?HB6WD0pJV' with padding of 0 + And in ais message 1 the source from the first NMEA line should be 3 + And in ais message 1 the timestamp from the first NMEA line should be 1567692251 + # ais.kystverket.no + And the message error report 0 should include the problematic line '\g:1-2-8055,s:99,c:1567685556*4E\!AIVDM,2,1,6,B,53oGfN42=WRDhlHn221<4i@Dr22222222222220`1@O6640Ht50Skp4mR`4l,0*72' + And the message error report 0 should include an exception reporting that it received an incomplete set of fragments for a message + And the message error report 0 should include the line number 1 + # TODO: diff --git a/Solutions/Ais.Net.Specs/Ais/Net/Specs/NmeaLineToAisStreamAdapterSpecs.feature.cs b/Solutions/Ais.Net.Specs/Ais/Net/Specs/NmeaLineToAisStreamAdapterSpecs.feature.cs index 2408a21..74ff7df 100644 --- a/Solutions/Ais.Net.Specs/Ais/Net/Specs/NmeaLineToAisStreamAdapterSpecs.feature.cs +++ b/Solutions/Ais.Net.Specs/Ais/Net/Specs/NmeaLineToAisStreamAdapterSpecs.feature.cs @@ -432,158 +432,161 @@ public virtual void InterleavedSingleAndMulti_FragmentMessages() { this.ScenarioStart(); #line 92 + testRunner.Given("I have configured a MaximumUnmatchedFragmentAge of 10", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); +#line hidden +#line 94 testRunner.When("the line to message adapter receives \'\\s:42,c:1567684904*38\\!AIVDM,1,1,,B,33m9UtP" + "P@50wwE:VJW6LS67H01<@,0*3C\'", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line hidden -#line 94 +#line 96 testRunner.And("the line to message adapter receives \'\\g:1-3-3451,s:27,c:1567686150*40\\!AIVDM,3,1" + ",9,A,544MR0827oeaD