From 7685c996375fffa56188d29147cd646432c69cd7 Mon Sep 17 00:00:00 2001 From: Divine Threepwood Date: Wed, 18 Feb 2026 22:30:22 +0100 Subject: [PATCH 01/14] implement equals check tests and fix color equals check. --- .../provider/ColorStateProviderService.java | 91 ++++- .../ColorStateProviderServiceTest.java | 56 --- .../provider/ColorStateProviderServiceTest.kt | 346 ++++++++++++++++++ 3 files changed, 428 insertions(+), 65 deletions(-) delete mode 100644 module/dal/lib/src/test/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderServiceTest.java create mode 100644 module/dal/lib/src/test/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderServiceTest.kt diff --git a/module/dal/lib/src/main/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderService.java b/module/dal/lib/src/main/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderService.java index 792fa1832b..ee1ddb2c4c 100644 --- a/module/dal/lib/src/main/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderService.java +++ b/module/dal/lib/src/main/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderService.java @@ -169,21 +169,94 @@ static Boolean equalServiceStates(final ColorState colorStateA, final ColorState final HSBColor hsbColorA = colorStateA.getColor().getHsbColor(); final HSBColor hsbColorB = colorStateB.getColor().getHsbColor(); + // Helper: compare hues with wrap-around (0 == 360) + // margin in degrees + final double HUE_MARGIN = 1.0; + final double SATURATION_MARGIN = 0.01; + final double BRIGHTNESS_MARGIN = 0.01; - boolean hueEquals = true; - boolean saturationEquals = true; - boolean brightnessEquals = true; + // normalize angle to [0,360) + java.util.function.DoubleUnaryOperator normalize = (v) -> { + double r = v % 360.0; + if (r < 0) r += 360.0; + return r; + }; - if(hsbColorA.hasHue() && hsbColorB.hasHue()) { - hueEquals = OperationService.equals(hsbColorA.getHue(), hsbColorB.getHue(), 1.0); + java.util.function.BiPredicate hueEqualsWithWrap = (ha, hb) -> { + double aNorm = normalize.applyAsDouble(ha); + double bNorm = normalize.applyAsDouble(hb); + double diff = Math.abs(aNorm - bNorm); + if (diff > 180.0) { + diff = 360.0 - diff; // shortest distance on circle + } + return diff <= HUE_MARGIN; + }; + + boolean hueEquals; + if (hsbColorA.hasHue() && hsbColorB.hasHue()) { + hueEquals = hueEqualsWithWrap.test(hsbColorA.getHue(), hsbColorB.getHue()); + } else if (!hsbColorA.hasHue() && !hsbColorB.hasHue()) { + // both undefined -> treat as equal + hueEquals = true; + } else { + // one missing: if the present color is 'neutral' (saturation == 0 or brightness == 0 or both undefined) the hue is irrelevant + final HSBColor present = hsbColorA.hasHue() ? hsbColorA : hsbColorB; + boolean presentIsNeutral = false; + // If both saturation and brightness are missing, treat as neutral (no chroma information) + if (!present.hasSaturation() && !present.hasBrightness()) { + presentIsNeutral = true; + } + // If saturation is present and effectively 0 -> neutral + if (!presentIsNeutral && present.hasSaturation()) { + presentIsNeutral = OperationService.equals(present.getSaturation(), 0d, SATURATION_MARGIN); + } + // If not neutral yet and brightness is present and effectively 0 -> neutral + if (!presentIsNeutral && present.hasBrightness()) { + presentIsNeutral = OperationService.equals(present.getBrightness(), 0d, BRIGHTNESS_MARGIN); + } + hueEquals = presentIsNeutral; } - if(hsbColorA.hasSaturation() && hsbColorB.hasSaturation()) { - saturationEquals = OperationService.equals(hsbColorA.getSaturation(), hsbColorB.getSaturation(), 0.01); + boolean saturationEquals; + if (hsbColorA.hasSaturation() && hsbColorB.hasSaturation()) { + saturationEquals = OperationService.equals(hsbColorA.getSaturation(), hsbColorB.getSaturation(), SATURATION_MARGIN); + } else if (!hsbColorA.hasSaturation() && !hsbColorB.hasSaturation()) { + saturationEquals = true; + } else { + // one missing: consider equal if the present saturation is effectively 0 (neutral) + // or if the present has no saturation but brightness is present and 0 -> neutral + final HSBColor present = hsbColorA.hasSaturation() ? hsbColorA : hsbColorB; + boolean presentIsNeutral = false; + if (present.hasSaturation()) { + presentIsNeutral = OperationService.equals(present.getSaturation(), 0d, SATURATION_MARGIN); + } else if (present.hasBrightness()) { + presentIsNeutral = OperationService.equals(present.getBrightness(), 0d, BRIGHTNESS_MARGIN); + } else { + // no saturation and no brightness information -> treat as neutral + presentIsNeutral = true; + } + saturationEquals = presentIsNeutral; } - if(hsbColorA.hasBrightness() && hsbColorB.hasBrightness()) { - brightnessEquals = OperationService.equals(hsbColorA.getBrightness(), hsbColorB.getBrightness(), 0.01); + boolean brightnessEquals; + if (hsbColorA.hasBrightness() && hsbColorB.hasBrightness()) { + brightnessEquals = OperationService.equals(hsbColorA.getBrightness(), hsbColorB.getBrightness(), BRIGHTNESS_MARGIN); + } else if (!hsbColorA.hasBrightness() && !hsbColorB.hasBrightness()) { + brightnessEquals = true; + } else { + // one missing: consider equal if the present brightness is effectively 0 (off/neutral) + // or if the present has no brightness but saturation is present and 0 -> neutral + final HSBColor present = hsbColorA.hasBrightness() ? hsbColorA : hsbColorB; + boolean presentIsNeutral = false; + if (present.hasBrightness()) { + presentIsNeutral = OperationService.equals(present.getBrightness(), 0d, BRIGHTNESS_MARGIN); + } else if (present.hasSaturation()) { + presentIsNeutral = OperationService.equals(present.getSaturation(), 0d, SATURATION_MARGIN); + } else { + // no brightness and no saturation information -> treat as neutral + presentIsNeutral = true; + } + brightnessEquals = presentIsNeutral; } return hueEquals && saturationEquals && brightnessEquals; diff --git a/module/dal/lib/src/test/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderServiceTest.java b/module/dal/lib/src/test/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderServiceTest.java deleted file mode 100644 index c7a9b9d05d..0000000000 --- a/module/dal/lib/src/test/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderServiceTest.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.openbase.bco.dal.lib.layer.service.provider; - -/*- - * #%L - * BCO DAL Library - * %% - * Copyright (C) 2014 - 2021 openbase.org - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ - -import static org.junit.jupiter.api.Assertions.*; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.Timeout; -import org.openbase.jps.core.JPService; -import org.openbase.jps.exception.JPServiceException; -import org.openbase.jul.exception.VerificationFailedException; -import org.openbase.jul.exception.printer.ExceptionPrinter; -import org.openbase.type.domotic.state.ColorStateType.ColorState; -import org.openbase.type.domotic.state.ColorStateType.ColorState.Builder; - -public class ColorStateProviderServiceTest { - - @Test - @Timeout(10) - public void verifyColorState() throws VerificationFailedException, JPServiceException { - - JPService.setupJUnitTestMode(); - - final Builder builder = ColorState.newBuilder(); - builder.getColorBuilder().getHsbColorBuilder().setHue(240); - builder.getColorBuilder().getHsbColorBuilder().setSaturation(100); - builder.getColorBuilder().getHsbColorBuilder().setBrightness(50); - - ExceptionPrinter.setBeQuit(true); - final ColorState verifiedColorState = ColorStateProviderService.verifyColorState(builder.build()); - ExceptionPrinter.setBeQuit(false); - - assertEquals(builder.getColorBuilder().getHsbColorBuilder().getHue(), verifiedColorState.getColor().getHsbColor().getHue(), 0.00001, "Hue value invalid!"); - assertEquals(1d, verifiedColorState.getColor().getHsbColor().getSaturation(), 0.00001, "Hue value invalid!"); - assertEquals(0.5d, verifiedColorState.getColor().getHsbColor().getBrightness(), 0.00001, "Hue value invalid!"); - } -} diff --git a/module/dal/lib/src/test/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderServiceTest.kt b/module/dal/lib/src/test/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderServiceTest.kt new file mode 100644 index 0000000000..f2a1e9a584 --- /dev/null +++ b/module/dal/lib/src/test/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderServiceTest.kt @@ -0,0 +1,346 @@ +package org.openbase.bco.dal.lib.layer.service.provider + +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.Timeout +import org.openbase.jps.core.JPService +import org.openbase.jps.exception.JPServiceException +import org.openbase.jul.exception.VerificationFailedException +import org.openbase.jul.exception.printer.ExceptionPrinter +import org.openbase.type.domotic.state.ColorStateType.ColorState + +/*- +* #%L +* BCO DAL Library +* %% +* Copyright (C) 2014 - 2021 openbase.org +* %% +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as +* published by the Free Software Foundation, either version 3 of the +* License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Lesser Public License for more details. +* +* You should have received a copy of the GNU General Lesser Public +* License along with this program. If not, see +* . +* #L% +*/ + +class ColorStateProviderServiceTest { + @Test + @Timeout(10) + @Throws(VerificationFailedException::class, JPServiceException::class) + fun verifyColorState() { + JPService.setupJUnitTestMode() + + val builder = ColorState.newBuilder() + builder.getColorBuilder().getHsbColorBuilder().setHue(240.0) + builder.getColorBuilder().getHsbColorBuilder().setSaturation(100.0) + builder.getColorBuilder().getHsbColorBuilder().setBrightness(50.0) + + ExceptionPrinter.setBeQuit(true) + val verifiedColorState = ColorStateProviderService.verifyColorState(builder.build()) + ExceptionPrinter.setBeQuit(false) + + Assertions.assertEquals( + builder.getColorBuilder().getHsbColorBuilder().getHue(), + verifiedColorState.getColor().getHsbColor().getHue(), + 0.00001, + "Hue value invalid!" + ) + Assertions.assertEquals( + 1.0, + verifiedColorState.getColor().getHsbColor().getSaturation(), + 0.00001, + "Hue value invalid!" + ) + Assertions.assertEquals( + 0.5, + verifiedColorState.getColor().getHsbColor().getBrightness(), + 0.00001, + "Hue value invalid!" + ) + } + + @Test + @Timeout(10) + @Throws(VerificationFailedException::class, JPServiceException::class) + fun `should handle color state comparison with equal state`() { + JPService.setupJUnitTestMode() + + ColorStateProviderService.equalServiceStates( + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(100.0) + setBrightness(50.0) + } + }.build(), + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(100.0) + setBrightness(50.0) + } + }.build(), + ) shouldBe true + + ColorStateProviderService.equalServiceStates( + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(0.0) + setSaturation(100.0) + setBrightness(50.0) + } + }.build(), + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(360.0) + setSaturation(100.0) + setBrightness(50.0) + } + }.build(), + ) shouldBe true + } + + @Test + @Timeout(10) + @Throws(VerificationFailedException::class, JPServiceException::class) + fun `should handle color state comparison with non equal state`() { + JPService.setupJUnitTestMode() + + ColorStateProviderService.equalServiceStates( + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(100.0) + setBrightness(50.0) + } + }.build(), + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(50.0) + setBrightness(50.0) + } + }.build(), + ) shouldBe false + + ColorStateProviderService.equalServiceStates( + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(100.0) + setBrightness(50.0) + } + }.build(), + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(100.0) + setBrightness(100.0) + } + }.build(), + ) shouldBe false + + ColorStateProviderService.equalServiceStates( + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(100.0) + setBrightness(50.0) + } + }.build(), + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(30.0) + setSaturation(0.0) + setBrightness(50.0) + } + }.build(), + ) shouldBe false + + ColorStateProviderService.equalServiceStates( + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(100.0) + setBrightness(50.0) + } + }.build(), + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(50.0) + setBrightness(1.0) + } + }.build(), + ) shouldBe false + + ColorStateProviderService.equalServiceStates( + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(100.0) + setBrightness(50.0) + } + }.build(), + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(10.0) + setSaturation(100.0) + setBrightness(20.0) + } + }.build(), + ) shouldBe false + + ColorStateProviderService.equalServiceStates( + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(100.0) + setBrightness(50.0) + } + }.build(), + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(233.0) + setSaturation(23.0) + setBrightness(12.0) + } + }.build(), + ) shouldBe false + + } + + @Test + @Timeout(10) + @Throws(VerificationFailedException::class, JPServiceException::class) + fun `should handle color state comparison with neutral state`() { + JPService.setupJUnitTestMode() + + ColorStateProviderService.equalServiceStates( + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(100.0) + setBrightness(50.0) + } + }.build(), + ColorState.newBuilder().build(), + ) shouldBe false + + ColorStateProviderService.equalServiceStates( + ColorState.newBuilder().build(), + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(100.0) + setBrightness(50.0) + } + }.build(), + ) shouldBe false + + ColorStateProviderService.equalServiceStates( + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setSaturation(100.0) + setBrightness(50.0) + } + }.build(), + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(100.0) + setBrightness(50.0) + } + }.build(), + ) shouldBe false + + ColorStateProviderService.equalServiceStates( + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setBrightness(50.0) + } + }.build(), + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(100.0) + setBrightness(50.0) + } + }.build(), + ) shouldBe false + + ColorStateProviderService.equalServiceStates( + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(100.0) + } + }.build(), + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(100.0) + setBrightness(50.0) + } + }.build(), + ) shouldBe false + + ColorStateProviderService.equalServiceStates( + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(100.0) + setBrightness(50.0) + } + }.build(), + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setSaturation(100.0) + setBrightness(50.0) + } + }.build(), + ) shouldBe false + + ColorStateProviderService.equalServiceStates( + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(100.0) + setBrightness(50.0) + } + }.build(), + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setBrightness(50.0) + } + }.build(), + ) shouldBe false + + ColorStateProviderService.equalServiceStates( + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(100.0) + setBrightness(50.0) + } + }.build(), + ColorState.newBuilder().apply { + getColorBuilder().getHsbColorBuilder().apply { + setHue(240.0) + setSaturation(100.0) + } + }.build(), + ) shouldBe false + } +} From fb0e868e71eebc068e08bbb5c1d00ca0e289efb1 Mon Sep 17 00:00:00 2001 From: Divine Threepwood Date: Wed, 18 Feb 2026 22:34:44 +0100 Subject: [PATCH 02/14] upgrade jul --- lib/jul | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jul b/lib/jul index 9d9befebe1..624961115a 160000 --- a/lib/jul +++ b/lib/jul @@ -1 +1 @@ -Subproject commit 9d9befebe197fd170f73518483ce213bef661653 +Subproject commit 624961115af6d25863de263b70c857320d0fc7a4 From 3ad5f9f677f33844385333fc8791001bf335999c Mon Sep 17 00:00:00 2001 From: Divine Threepwood Date: Wed, 18 Feb 2026 23:07:39 +0100 Subject: [PATCH 03/14] fix addon commit message contains no addon name. --- .github/workflows/update-addon-version.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-addon-version.yaml b/.github/workflows/update-addon-version.yaml index 988d4f2fb2..129d0be867 100644 --- a/.github/workflows/update-addon-version.yaml +++ b/.github/workflows/update-addon-version.yaml @@ -95,7 +95,7 @@ jobs: git config user.name "$GIT_USERNAME" git config user.email "$GIT_EMAIL" git add config.yaml - git commit -m "Update add-on $ADDONS_DIR version to $VERSION" || { + git commit -m "Update add-on $ADDON_DIR version to $VERSION" || { echo "No changes to commit" exit 0 } From 6b1726a9217b0b1425f0a6fb61fabfa0917e66e7 Mon Sep 17 00:00:00 2001 From: Divine Threepwood Date: Tue, 10 Mar 2026 21:54:04 +0100 Subject: [PATCH 04/14] cleanup code and address revise --- .../service/provider/ColorStateProviderService.java | 12 +++++++----- .../provider/ColorStateProviderServiceTest.kt | 6 +----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/module/dal/lib/src/main/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderService.java b/module/dal/lib/src/main/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderService.java index ee1ddb2c4c..3126cd4f78 100644 --- a/module/dal/lib/src/main/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderService.java +++ b/module/dal/lib/src/main/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderService.java @@ -22,9 +22,9 @@ * #L% */ +import org.jetbrains.annotations.NotNull; import org.openbase.bco.dal.lib.layer.service.operation.OperationService; import org.openbase.jul.annotation.RPCMethod; -import org.openbase.jul.exception.CouldNotPerformException; import org.openbase.jul.exception.CouldNotTransformException; import org.openbase.jul.exception.NotAvailableException; import org.openbase.jul.exception.VerificationFailedException; @@ -38,6 +38,9 @@ import org.openbase.type.vision.RGBColorType.RGBColor; import org.slf4j.LoggerFactory; +import java.util.function.DoubleUnaryOperator; +import java.util.function.BiPredicate; + import static org.openbase.type.domotic.service.ServiceTemplateType.ServiceTemplate.ServiceType.COLOR_STATE_SERVICE; /** @@ -164,8 +167,7 @@ static Boolean isCompatible(final ColorState colorState, final PowerState powerS } static Boolean equalServiceStates(final ColorState colorStateA, final ColorState colorStateB) { - //TODO: explain this (required because of openhab) and put margins into constants - + final HSBColor hsbColorA = colorStateA.getColor().getHsbColor(); final HSBColor hsbColorB = colorStateB.getColor().getHsbColor(); @@ -176,13 +178,13 @@ static Boolean equalServiceStates(final ColorState colorStateA, final ColorState final double BRIGHTNESS_MARGIN = 0.01; // normalize angle to [0,360) - java.util.function.DoubleUnaryOperator normalize = (v) -> { + DoubleUnaryOperator normalize = (v) -> { double r = v % 360.0; if (r < 0) r += 360.0; return r; }; - java.util.function.BiPredicate hueEqualsWithWrap = (ha, hb) -> { + BiPredicate hueEqualsWithWrap = (ha, hb) -> { double aNorm = normalize.applyAsDouble(ha); double bNorm = normalize.applyAsDouble(hb); double diff = Math.abs(aNorm - bNorm); diff --git a/module/dal/lib/src/test/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderServiceTest.kt b/module/dal/lib/src/test/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderServiceTest.kt index f2a1e9a584..8dd28e294b 100644 --- a/module/dal/lib/src/test/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderServiceTest.kt +++ b/module/dal/lib/src/test/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderServiceTest.kt @@ -35,8 +35,7 @@ import org.openbase.type.domotic.state.ColorStateType.ColorState class ColorStateProviderServiceTest { @Test @Timeout(10) - @Throws(VerificationFailedException::class, JPServiceException::class) - fun verifyColorState() { + fun `should fix color values once they are defined out of range`() { JPService.setupJUnitTestMode() val builder = ColorState.newBuilder() @@ -70,7 +69,6 @@ class ColorStateProviderServiceTest { @Test @Timeout(10) - @Throws(VerificationFailedException::class, JPServiceException::class) fun `should handle color state comparison with equal state`() { JPService.setupJUnitTestMode() @@ -111,7 +109,6 @@ class ColorStateProviderServiceTest { @Test @Timeout(10) - @Throws(VerificationFailedException::class, JPServiceException::class) fun `should handle color state comparison with non equal state`() { JPService.setupJUnitTestMode() @@ -221,7 +218,6 @@ class ColorStateProviderServiceTest { @Test @Timeout(10) - @Throws(VerificationFailedException::class, JPServiceException::class) fun `should handle color state comparison with neutral state`() { JPService.setupJUnitTestMode() From a76d46e22a299cf28b583b759f28fc80d7cb4bc5 Mon Sep 17 00:00:00 2001 From: Divine Threepwood Date: Tue, 10 Mar 2026 22:40:02 +0100 Subject: [PATCH 05/14] fix formatting --- .../lib/layer/service/provider/ColorStateProviderService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/dal/lib/src/main/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderService.java b/module/dal/lib/src/main/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderService.java index 3126cd4f78..bb9b9052c3 100644 --- a/module/dal/lib/src/main/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderService.java +++ b/module/dal/lib/src/main/java/org/openbase/bco/dal/lib/layer/service/provider/ColorStateProviderService.java @@ -167,7 +167,7 @@ static Boolean isCompatible(final ColorState colorState, final PowerState powerS } static Boolean equalServiceStates(final ColorState colorStateA, final ColorState colorStateB) { - + final HSBColor hsbColorA = colorStateA.getColor().getHsbColor(); final HSBColor hsbColorB = colorStateB.getColor().getHsbColor(); From e4e71debae606793745d0f52728b259f7c0bfe6b Mon Sep 17 00:00:00 2001 From: Divine Threepwood Date: Tue, 10 Mar 2026 23:06:14 +0100 Subject: [PATCH 06/14] improve test performance --- buildSrc/src/main/kotlin/org.openbase.bco.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/org.openbase.bco.gradle.kts b/buildSrc/src/main/kotlin/org.openbase.bco.gradle.kts index fd3ae12c73..00532734ea 100644 --- a/buildSrc/src/main/kotlin/org.openbase.bco.gradle.kts +++ b/buildSrc/src/main/kotlin/org.openbase.bco.gradle.kts @@ -53,7 +53,7 @@ tasks.withType { logging.captureStandardOutput(LogLevel.WARN) maxHeapSize = "7G" failFast = false - setForkEvery(1) + forkEvery = 100 } publishing { From aa7e5787ded956df7710294cafcd9d25fac53926 Mon Sep 17 00:00:00 2001 From: Divine Threepwood Date: Wed, 18 Mar 2026 22:11:33 +0100 Subject: [PATCH 07/14] contiune on module test failure --- .github/workflows/build-and-test.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 690728d1ea..3b2446a7a9 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -122,7 +122,7 @@ jobs: run: ./prepare.sh - name: "test backend" - run: ./gradlew --build-cache check + run: ./gradlew --build-cache --continue check - name: Upload test reports uses: actions/upload-artifact@v4 @@ -130,4 +130,3 @@ jobs: with: name: Test Reports path: "**/build/reports" - From df3c09fa19d9195ec00ddbcc865fa74bab785cbf Mon Sep 17 00:00:00 2001 From: Divine Threepwood Date: Wed, 18 Mar 2026 22:11:48 +0100 Subject: [PATCH 08/14] avoid on each test fork --- buildSrc/src/main/kotlin/org.openbase.bco.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/org.openbase.bco.gradle.kts b/buildSrc/src/main/kotlin/org.openbase.bco.gradle.kts index 00532734ea..028366f412 100644 --- a/buildSrc/src/main/kotlin/org.openbase.bco.gradle.kts +++ b/buildSrc/src/main/kotlin/org.openbase.bco.gradle.kts @@ -53,7 +53,6 @@ tasks.withType { logging.captureStandardOutput(LogLevel.WARN) maxHeapSize = "7G" failFast = false - forkEvery = 100 } publishing { From 34ff0b12dedf7179812eb63d671cdb50c06a7805 Mon Sep 17 00:00:00 2001 From: Divine Threepwood Date: Wed, 18 Mar 2026 22:12:40 +0100 Subject: [PATCH 09/14] patch jul with test container fixes --- lib/jul | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jul b/lib/jul index 624961115a..743b0ca2a1 160000 --- a/lib/jul +++ b/lib/jul @@ -1 +1 @@ -Subproject commit 624961115af6d25863de263b70c857320d0fc7a4 +Subproject commit 743b0ca2a10593112a707ea30c80a12106b5cf6e From 114452df0b5c89c5405c5c4ebda3774a898b0beb Mon Sep 17 00:00:00 2001 From: Divine Threepwood Date: Wed, 18 Mar 2026 22:33:01 +0100 Subject: [PATCH 10/14] upgrade jul to 3.7.3 --- lib/jul | 2 +- versions.properties | 100 +++++++++++++------------------------------- 2 files changed, 30 insertions(+), 72 deletions(-) diff --git a/lib/jul b/lib/jul index 743b0ca2a1..66adfc9142 160000 --- a/lib/jul +++ b/lib/jul @@ -1 +1 @@ -Subproject commit 743b0ca2a10593112a707ea30c80a12106b5cf6e +Subproject commit 66adfc9142ba9b3ee45e8022770c0304529f0792 diff --git a/versions.properties b/versions.properties index 5a79e9c922..d68c133a5b 100644 --- a/versions.properties +++ b/versions.properties @@ -72,9 +72,9 @@ version.com.google.guava..guava=28.0-jre ## # available=31.0.1-android ## # available=31.0.1-jre -version.org.openbase..jul.communication.mqtt.test=3.7.2 +version.org.openbase..jul.communication.mqtt.test=3.7.3 -version.org.openbase..jul.transformation=3.7.2 +version.org.openbase..jul.transformation=3.7.3 version.org.testcontainers..junit-jupiter=1.21.4 @@ -96,74 +96,32 @@ plugin.io.spring.dependency-management=1.1.2 version.kotlin=2.0.0 -version.org.openbase..jul.communication.controller=3.7.2 -## # available=3.0.0 -## # available=3.0.1 -## # available=3.0.2 - -version.org.openbase..jul.communication.mqtt=3.7.2 -## # available=3.0.0 -## # available=3.0.1 -## # available=3.0.2 - -version.org.openbase..jul.exception=3.7.2 -## # available=3.0.0 -## # available=3.0.1 -## # available=3.0.2 - -version.org.openbase..jul.extension.protobuf=3.7.2 -## # available=3.0.0 -## # available=3.0.1 -## # available=3.0.2 - -version.org.openbase..jul.extension.type.processing=3.7.2 -## # available=3.0.0 -## # available=3.0.1 -## # available=3.0.2 - -version.org.openbase..jul.extension.type.storage=3.7.2 -## # available=3.0.0 -## # available=3.0.1 -## # available=3.0.2 - -version.org.openbase..jul.extension.type.transform=3.7.2 -## # available=3.0.0 -## # available=3.0.1 -## # available=3.0.2 - -version.org.openbase..jul.extension.type.util=3.7.2 -## # available=3.0.0 -## # available=3.0.1 -## # available=3.0.2 - -version.org.openbase..jul.pattern.launch=3.7.2 -## # available=3.0.0 -## # available=3.0.1 -## # available=3.0.2 - -version.org.openbase..jul.pattern.trigger=3.7.2 -## # available=3.0.0 -## # available=3.0.1 -## # available=3.0.2 - -version.org.openbase..jul.processing=3.7.2 -## # available=3.0.0 -## # available=3.0.1 -## # available=3.0.2 - -version.org.openbase..jul.storage=3.7.2 -## # available=3.0.0 -## # available=3.0.1 -## # available=3.0.2 - -version.org.openbase..jul.visual.javafx=3.7.2 -## # available=3.0.0 -## # available=3.0.1 -## # available=3.0.2 - -version.org.openbase..jul.visual.swing=3.7.2 -## # available=3.0.0 -## # available=3.0.1 -## # available=3.0.2 +version.org.openbase..jul.communication.controller=3.7.3 + +version.org.openbase..jul.communication.mqtt=3.7.3 + +version.org.openbase..jul.exception=3.7.3 + +version.org.openbase..jul.extension.protobuf=3.7.3 + +version.org.openbase..jul.extension.type.processing=3.7.3 + +version.org.openbase..jul.extension.type.storage=3.7.3 + +version.org.openbase..jul.extension.type.transform=3.7.3 + +version.org.openbase..jul.extension.type.util=3.7.3 +\ +version.org.openbase..jul.pattern.launch=3.7.3 + +version.org.openbase..jul.pattern.trigger=3.7.3 + +version.org.openbase..jul.processing=3.7.3 + +version.org.openbase..jul.storage=3.7.3 + +version.org.openbase..jul.visual.javafx=3.7.3 + +version.org.openbase..jul.visual.swing=3.7.3 version.rxjava2.rxjava=2.2.21 From a55a8e6f37de8a09e53f2353ce81dec9fcae6131 Mon Sep 17 00:00:00 2001 From: Divine Threepwood Date: Wed, 18 Mar 2026 22:44:06 +0100 Subject: [PATCH 11/14] cleanup --- module/authentication/test/build.gradle.kts | 4 ---- versions.properties | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/module/authentication/test/build.gradle.kts b/module/authentication/test/build.gradle.kts index 75188b4844..eedc92c474 100644 --- a/module/authentication/test/build.gradle.kts +++ b/module/authentication/test/build.gradle.kts @@ -2,10 +2,6 @@ plugins { id("org.openbase.bco") } -configurations { - -} - dependencies { api(project(":bco.authentication.core")) api(project(":bco.authentication.lib")) diff --git a/versions.properties b/versions.properties index d68c133a5b..3a30180d11 100644 --- a/versions.properties +++ b/versions.properties @@ -111,7 +111,7 @@ version.org.openbase..jul.extension.type.storage=3.7.3 version.org.openbase..jul.extension.type.transform=3.7.3 version.org.openbase..jul.extension.type.util=3.7.3 -\ + version.org.openbase..jul.pattern.launch=3.7.3 version.org.openbase..jul.pattern.trigger=3.7.3 From 8baced0242b6c15dd95a2297932063b2b6ab6584 Mon Sep 17 00:00:00 2001 From: Divine Threepwood Date: Thu, 19 Mar 2026 00:27:48 +0100 Subject: [PATCH 12/14] improve auth test --- .../lib/future/AuthenticationFutureList.kt | 9 +++++++++ .../authentication/test/AuthenticationFutureListTest.kt | 1 + 2 files changed, 10 insertions(+) diff --git a/module/authentication/lib/src/main/java/org/openbase/bco/authentication/lib/future/AuthenticationFutureList.kt b/module/authentication/lib/src/main/java/org/openbase/bco/authentication/lib/future/AuthenticationFutureList.kt index b9ac4c2a55..8f9ee7db34 100644 --- a/module/authentication/lib/src/main/java/org/openbase/bco/authentication/lib/future/AuthenticationFutureList.kt +++ b/module/authentication/lib/src/main/java/org/openbase/bco/authentication/lib/future/AuthenticationFutureList.kt @@ -81,4 +81,13 @@ object AuthenticationFutureList { notificationCondition.await() } } + + fun reset() { + synchronized(authenticatedFuturesLock) { + synchronized(incomingFuturesLock) { + incomingFutures.clear() + authenticatedFutures.clear() + } + } + } } diff --git a/module/authentication/test/src/test/java/org/openbase/bco/authentication/test/AuthenticationFutureListTest.kt b/module/authentication/test/src/test/java/org/openbase/bco/authentication/test/AuthenticationFutureListTest.kt index b7781c6a0c..82917ab05c 100644 --- a/module/authentication/test/src/test/java/org/openbase/bco/authentication/test/AuthenticationFutureListTest.kt +++ b/module/authentication/test/src/test/java/org/openbase/bco/authentication/test/AuthenticationFutureListTest.kt @@ -45,6 +45,7 @@ class AuthenticationFutureListTest { @Timeout(5) @Test fun testScheduledTask() { + AuthenticationFutureList.reset() val lock = ReentrantLock() val condition: Condition = lock.newCondition() From 5c61eff42d1a37683112c8228bd5aa3dd41be90b Mon Sep 17 00:00:00 2001 From: Divine Threepwood Date: Thu, 19 Mar 2026 00:28:20 +0100 Subject: [PATCH 13/14] improve message manager thread safety --- .../bco/dal/control/message/MessageManager.kt | 1 + .../bco/dal/remote/action/RemoteAction.java | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/message/MessageManager.kt b/module/dal/control/src/main/java/org/openbase/bco/dal/control/message/MessageManager.kt index b0cd960f05..eed9c963f6 100644 --- a/module/dal/control/src/main/java/org/openbase/bco/dal/control/message/MessageManager.kt +++ b/module/dal/control/src/main/java/org/openbase/bco/dal/control/message/MessageManager.kt @@ -41,6 +41,7 @@ class MessageManager : Launchable, VoidInitializable { fun removeOutdatedMessages(auth: AuthToken? = null) { logger.trace("removeOutdatedMessages") Registries.getMessageRegistry().userMessages + .toList() .filterNot { message -> message.conditionList.any { condition -> Units.getUnit(condition.unitId, true).let { unit -> diff --git a/module/dal/remote/src/main/java/org/openbase/bco/dal/remote/action/RemoteAction.java b/module/dal/remote/src/main/java/org/openbase/bco/dal/remote/action/RemoteAction.java index 0ea35e8516..85ac8b26e7 100644 --- a/module/dal/remote/src/main/java/org/openbase/bco/dal/remote/action/RemoteAction.java +++ b/module/dal/remote/src/main/java/org/openbase/bco/dal/remote/action/RemoteAction.java @@ -619,7 +619,7 @@ public boolean isRunning() { try { if (getActionDescription().getIntermediary()) { - for (final RemoteAction impactedRemoteAction : impactedRemoteActions) { + for (final RemoteAction impactedRemoteAction : impactedRemoteActions.stream().toList()) { if (impactedRemoteAction.isRunning()) { return true; } @@ -650,7 +650,7 @@ public boolean isDone() { try { if (getActionDescription().getIntermediary()) { - for (final RemoteAction impactedRemoteAction : impactedRemoteActions) { + for (final RemoteAction impactedRemoteAction : impactedRemoteActions.stream().toList()) { if (!impactedRemoteAction.isDone()) { return false; } @@ -854,7 +854,7 @@ private void cleanup() { // cleanup synchronisation and observation tasks actionDescriptionObservable.reset(); - for (RemoteAction impactedRemoteAction : impactedRemoteActions) { + for (RemoteAction impactedRemoteAction : impactedRemoteActions.stream().toList()) { impactedRemoteAction.removeActionDescriptionObserver(impactActionObserver); } impactedRemoteActions.clear(); @@ -955,7 +955,7 @@ public void waitUntilDone() throws CouldNotPerformException, InterruptedExceptio try { if (getActionDescription().getIntermediary()) { - for (final RemoteAction impactedRemoteAction : impactedRemoteActions) { + for (final RemoteAction impactedRemoteAction : impactedRemoteActions.stream().toList()) { impactedRemoteAction.waitUntilDone(); } return; @@ -1006,7 +1006,7 @@ public void waitForActionState(final ActionState.State actionState, final long t try { if (actionDescription.getIntermediary()) { - for (final RemoteAction impactedRemoteAction : impactedRemoteActions) { + for (final RemoteAction impactedRemoteAction : impactedRemoteActions.stream().toList()) { impactedRemoteAction.waitForActionState(actionState, timeSplit.getTime(), timeSplit.getTimeUnit()); } return; @@ -1091,7 +1091,7 @@ public void waitForRegistration() throws CouldNotPerformException, InterruptedEx } if (getActionDescription().getIntermediary()) { - for (final RemoteAction impactedRemoteAction : impactedRemoteActions) { + for (final RemoteAction impactedRemoteAction : impactedRemoteActions.stream().toList()) { impactedRemoteAction.waitForRegistration(); } } @@ -1130,7 +1130,7 @@ public void waitForRegistration(final long timeout, final TimeUnit timeUnit) thr } if (getActionDescription().getIntermediary()) { - for (final RemoteAction impactedRemoteAction : impactedRemoteActions) { + for (final RemoteAction impactedRemoteAction : impactedRemoteActions.stream().toList()) { impactedRemoteAction.waitForRegistration(timeSplit.getTime(), timeSplit.getTimeUnit()); } } @@ -1147,7 +1147,7 @@ public boolean isRegistrationDone() { } if (actionDescription.getIntermediary()) { - for (final RemoteAction impactedRemoteAction : impactedRemoteActions) { + for (final RemoteAction impactedRemoteAction : impactedRemoteActions.stream().toList()) { if (!impactedRemoteAction.isRegistrationDone()) { return false; } From 572a1e90da987f0b6f82a55d39926cb42597b947 Mon Sep 17 00:00:00 2001 From: Divine Threepwood Date: Thu, 19 Mar 2026 00:32:02 +0100 Subject: [PATCH 14/14] update jule --- lib/jul | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jul b/lib/jul index 66adfc9142..b5b7d12b09 160000 --- a/lib/jul +++ b/lib/jul @@ -1 +1 @@ -Subproject commit 66adfc9142ba9b3ee45e8022770c0304529f0792 +Subproject commit b5b7d12b09b3d38dec3a33a539a7b2ba75b366d0