diff --git a/src/main/java/io/mapsmessaging/api/MessageBuilder.java b/src/main/java/io/mapsmessaging/api/MessageBuilder.java index 1a1446079..0b4d9b157 100644 --- a/src/main/java/io/mapsmessaging/api/MessageBuilder.java +++ b/src/main/java/io/mapsmessaging/api/MessageBuilder.java @@ -75,6 +75,7 @@ public MessageBuilder() { } public MessageBuilder(Message previousMessage) { + long now = System.currentTimeMillis(); id = 0; meta = new LinkedHashMap<>(previousMessage.getMeta()); dataMap = new LinkedHashMap<>(previousMessage.getDataMap()); @@ -83,7 +84,11 @@ public MessageBuilder(Message previousMessage) { retain = previousMessage.isRetain(); storeOffline = previousMessage.isStoreOffline(); payloadUTF8 = previousMessage.isUTF8(); - expiry = (previousMessage.getExpiry() - System.currentTimeMillis()); + delayed = previousMessage.getDelayed() - now; + expiry = previousMessage.getExpiry() - now; + if (expiry > 0 && delayed > 0) { + expiry -= delayed; + } creation = previousMessage.getCreation(); contentType = previousMessage.getContentType(); responseTopic = previousMessage.getResponseTopic(); @@ -94,7 +99,6 @@ public MessageBuilder(Message previousMessage) { correlationData = previousMessage.getCorrelationData(); } qualityOfService = previousMessage.getQualityOfService(); - delayed = (previousMessage.getDelayed() - System.currentTimeMillis() ); schemaId = previousMessage.getSchemaId(); } diff --git a/src/main/java/io/mapsmessaging/config/destination/MessageOverrideConfig.java b/src/main/java/io/mapsmessaging/config/destination/MessageOverrideConfig.java index 58f577dac..cdbd3db0e 100644 --- a/src/main/java/io/mapsmessaging/config/destination/MessageOverrideConfig.java +++ b/src/main/java/io/mapsmessaging/config/destination/MessageOverrideConfig.java @@ -89,7 +89,7 @@ public static ConfigurationProperties toConfigurationProperties(MessageOverrideD properties.put("priority", config.getPriority()); } if (config.getQualityOfService() != null) { - properties.put("qos", config.getQualityOfService()); + properties.put("qos", config.getQualityOfService().name()); } if (config.getResponseTopic() != null) { properties.put("responseTopic", config.getResponseTopic()); diff --git a/src/test/java/io/mapsmessaging/api/MessageBuilderTest.java b/src/test/java/io/mapsmessaging/api/MessageBuilderTest.java index 74ede91ac..33cdc2a35 100644 --- a/src/test/java/io/mapsmessaging/api/MessageBuilderTest.java +++ b/src/test/java/io/mapsmessaging/api/MessageBuilderTest.java @@ -164,4 +164,44 @@ void copyConstructor_preservesNullResponseTopic() { Assertions.assertNull(copy.getResponseTopic()); } + + @Test + void copyConstructor_preservesAbsoluteExpiryAndDelay() { + Message original = new MessageBuilder().setExpiry(120_000).setDelayed(2_000).build(); + + Message copy = new MessageBuilder(original).build(); + + Assertions.assertTrue(Math.abs(copy.getExpiry() - original.getExpiry()) <= 50); + Assertions.assertTrue(Math.abs(copy.getDelayed() - original.getDelayed()) <= 50); + } + + @Test + void copyConstructor_preservesAbsoluteExpiryWithoutDelay() { + Message original = new MessageBuilder().setExpiry(120_000).build(); + + Message copy = new MessageBuilder(original).build(); + + Assertions.assertTrue(Math.abs(copy.getExpiry() - original.getExpiry()) <= 50); + Assertions.assertEquals(0, copy.getDelayed()); + } + + @Test + void copyConstructor_preservesAbsoluteDelayWithoutExpiry() { + Message original = new MessageBuilder().setDelayed(2_000).build(); + + Message copy = new MessageBuilder(original).build(); + + Assertions.assertEquals(0, copy.getExpiry()); + Assertions.assertTrue(Math.abs(copy.getDelayed() - original.getDelayed()) <= 50); + } + + @Test + void copyConstructor_preservesAbsentExpiryAndDelay() { + Message original = new MessageBuilder().build(); + + Message copy = new MessageBuilder(original).build(); + + Assertions.assertEquals(0, copy.getExpiry()); + Assertions.assertEquals(0, copy.getDelayed()); + } } diff --git a/src/test/java/io/mapsmessaging/config/destination/MessageOverrideConfigTest.java b/src/test/java/io/mapsmessaging/config/destination/MessageOverrideConfigTest.java index 188ea9b17..dda5d22a7 100644 --- a/src/test/java/io/mapsmessaging/config/destination/MessageOverrideConfigTest.java +++ b/src/test/java/io/mapsmessaging/config/destination/MessageOverrideConfigTest.java @@ -49,6 +49,7 @@ void configurationRoundTrip_preservesCanonicalKeysAndValues() { Assertions.assertTrue(saved.containsKey("qos")); Assertions.assertFalse(saved.containsKey("qualityOfService")); + Assertions.assertEquals(QualityOfService.AT_LEAST_ONCE.name(), saved.getProperty("qos", null)); Assertions.assertEquals(5000L, reloaded.getExpiry()); Assertions.assertEquals(QualityOfService.AT_LEAST_ONCE, reloaded.getQualityOfService()); Assertions.assertTrue(reloaded.getStoreOffline()); diff --git a/src/test/java/io/mapsmessaging/state/mavlink/model/impl/usv/SticklebackArdupilotUsvModelMissionTest.java b/src/test/java/io/mapsmessaging/state/mavlink/model/impl/usv/SticklebackArdupilotUsvModelMissionTest.java index 45d9f7e56..d5c0d4c07 100644 --- a/src/test/java/io/mapsmessaging/state/mavlink/model/impl/usv/SticklebackArdupilotUsvModelMissionTest.java +++ b/src/test/java/io/mapsmessaging/state/mavlink/model/impl/usv/SticklebackArdupilotUsvModelMissionTest.java @@ -130,22 +130,6 @@ void rejectsUnsupportedMissionItemsAndFields() { null)))) .valid()); - assertFalse( - model - .validateMission( - new MissionPlan( - List.of( - new PlanItem( - PlanItemType.WAYPOINT, - new GeoPosition(59.434079d, 24.747487d, null, null), - null, - null, - null, - null, - 10.0d, - null)))) - .valid()); - assertFalse( model .validateMission( @@ -163,6 +147,24 @@ void rejectsUnsupportedMissionItemsAndFields() { .valid()); } + @Test + void acceptsFiniteResolvedAltitude() { + PlanItem waypoint = + new PlanItem( + PlanItemType.WAYPOINT, + new GeoPosition(59.434079d, 24.747487d, null, null), + null, + null, + null, + null, + 10.0d, + null); + MissionPlan missionPlan = new MissionPlan(List.of(waypoint)); + + assertTrue(model.validateMission(missionPlan).valid()); + assertEquals(10.0f, item(model.buildMission(CONTEXT, missionPlan), 1).getAltitude()); + } + private static PlanItem waypoint(double latitude, double longitude) { return new PlanItem(PlanItemType.WAYPOINT, new GeoPosition(latitude, longitude, null, null), null, null, null, null, null, null); } @@ -178,4 +180,4 @@ private static PlanItem positionItem(PlanItemType type) { private static MavlinkMissionItemInt item(UxvModelCommandSet commandSet, int index) { return (MavlinkMissionItemInt) commandSet.messages().get(index); } -} \ No newline at end of file +} diff --git a/src/test/java/io/mapsmessaging/state/mavlink/model/impl/usv/SticklebackArdupilotUsvModelTest.java b/src/test/java/io/mapsmessaging/state/mavlink/model/impl/usv/SticklebackArdupilotUsvModelTest.java index 5cd5ea4f6..4232cc59f 100644 --- a/src/test/java/io/mapsmessaging/state/mavlink/model/impl/usv/SticklebackArdupilotUsvModelTest.java +++ b/src/test/java/io/mapsmessaging/state/mavlink/model/impl/usv/SticklebackArdupilotUsvModelTest.java @@ -56,18 +56,13 @@ void repositionUsesFixedRelativeAltitudeWithoutMutatingSurfacePosition() { UxvModelCommandSet commandSet = model.reposition(CONTEXT, new RepositionRequest(position, null, null)); - assertEquals(3, commandSet.messages().size()); - - MavlinkCommandInt reposition = assertInstanceOf(MavlinkCommandInt.class, commandSet.messages().get(0)); - assertEquals(MavlinkCommandIntFactory.MAV_CMD_DO_REPOSITION, reposition.getCommand()); - assertEquals(MavlinkCommandIntFactory.MAV_FRAME_GLOBAL_RELATIVE_ALT_INT, reposition.getFrame()); - assertEquals((float) SticklebackArdupilotUsvModel.MAX_ALTITUDE_METERS, reposition.getAltitude()); + assertEquals(2, commandSet.messages().size()); - MavlinkCommandLong guidedMode = assertInstanceOf(MavlinkCommandLong.class, commandSet.messages().get(1)); + MavlinkCommandLong guidedMode = assertInstanceOf(MavlinkCommandLong.class, commandSet.messages().get(0)); assertEquals(MavlinkCommandLongFactory.MAV_CMD_DO_SET_MODE, guidedMode.getCommand()); assertEquals(MavlinkCommandLongFactory.ARDUPLANE_MODE_GUIDED, guidedMode.getParam2()); - MavlinkMissionItem guidedWaypoint = assertInstanceOf(MavlinkMissionItem.class, commandSet.messages().get(2)); + MavlinkMissionItem guidedWaypoint = assertInstanceOf(MavlinkMissionItem.class, commandSet.messages().get(1)); assertEquals(MavlinkMissionItemFactory.MAV_FRAME_GLOBAL_RELATIVE_ALT, guidedWaypoint.getFrame()); assertEquals((float) SticklebackArdupilotUsvModel.MAX_ALTITUDE_METERS, guidedWaypoint.getAltitude()); assertEquals(2, guidedWaypoint.getCurrent()); @@ -77,7 +72,7 @@ void repositionUsesFixedRelativeAltitudeWithoutMutatingSurfacePosition() { } @Test - void repositionUsesResolvedAltitudeForEveryCommand() { + void repositionUsesResolvedAltitudeForGuidedWaypoint() { SticklebackArdupilotUsvModel model = new SticklebackArdupilotUsvModel(); GeoPosition position = new GeoPosition(59.4673d, 24.828353d, 123.0d, null); @@ -85,11 +80,8 @@ void repositionUsesResolvedAltitudeForEveryCommand() { model.reposition( CONTEXT, new RepositionRequest(position, null, null, 7.5d)); - MavlinkCommandInt reposition = - assertInstanceOf(MavlinkCommandInt.class, commandSet.messages().get(0)); MavlinkMissionItem guidedWaypoint = - assertInstanceOf(MavlinkMissionItem.class, commandSet.messages().get(2)); - assertEquals(7.5f, reposition.getAltitude()); + assertInstanceOf(MavlinkMissionItem.class, commandSet.messages().get(1)); assertEquals(7.5f, guidedWaypoint.getAltitude()); assertEquals(123.0d, position.getAltitudeMslMeters()); } @@ -116,9 +108,9 @@ void repositionAcceptsNegativeResolvedAltitude() { model.reposition( CONTEXT, new RepositionRequest(position, null, null, -10.0d)); - MavlinkCommandInt reposition = - assertInstanceOf(MavlinkCommandInt.class, commandSet.messages().get(0)); - assertEquals(-10.0f, reposition.getAltitude()); + MavlinkMissionItem guidedWaypoint = + assertInstanceOf(MavlinkMissionItem.class, commandSet.messages().get(1)); + assertEquals(-10.0f, guidedWaypoint.getAltitude()); } @Test