Loading .classpathdeleted 100644 → 0 +0 −40 Original line number Diff line number Diff line <?xml version="1.0" encoding="UTF-8"?> <classpath> <classpathentry kind="src" output="target/classes" path="src/main/java"> <attributes> <attribute name="optional" value="true"/> <attribute name="maven.pomderived" value="true"/> </attributes> </classpathentry> <classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"> <attributes> <attribute name="maven.pomderived" value="true"/> <attribute name="optional" value="true"/> </attributes> </classpathentry> <classpathentry kind="src" output="target/test-classes" path="src/test/java"> <attributes> <attribute name="optional" value="true"/> <attribute name="maven.pomderived" value="true"/> <attribute name="test" value="true"/> </attributes> </classpathentry> <classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"> <attributes> <attribute name="maven.pomderived" value="true"/> <attribute name="test" value="true"/> <attribute name="optional" value="true"/> </attributes> </classpathentry> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"> <attributes> <attribute name="maven.pomderived" value="true"/> </attributes> </classpathentry> <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> <attributes> <attribute name="maven.pomderived" value="true"/> </attributes> </classpathentry> <classpathentry kind="output" path="target/classes"/> </classpath> .settings/org.eclipse.core.resources.prefsdeleted 100644 → 0 +0 −6 Original line number Diff line number Diff line eclipse.preferences.version=1 encoding//src/main/java=utf-8 encoding//src/main/resources=UTF-8 encoding//src/test/java=utf-8 encoding//src/test/resources=UTF-8 encoding/<project>=UTF-8 pom.xml +18 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,19 @@ </distributionManagement> <dependencyManagement> <dependencies> <!-- Spring Boot BOM --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot-version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.projectlombok</groupId> Loading @@ -50,5 +63,10 @@ <artifactId>org.etsi.osl.model.tmf</artifactId> <version>${org.etsi.osl.model.tmf.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project> No newline at end of file src/test/java/org/etsi/osl/domain/model/kubernetes/KubernetesCRV1ApplyStateTest.java 0 → 100644 +170 −0 Original line number Diff line number Diff line package org.etsi.osl.domain.model.kubernetes; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import org.etsi.osl.tmf.ri639.model.ResourceAdministrativeStateType; import org.etsi.osl.tmf.ri639.model.ResourceCreate; import org.etsi.osl.tmf.ri639.model.ResourceHealth; import org.etsi.osl.tmf.ri639.model.ResourceOperationalStateType; import org.etsi.osl.tmf.ri639.model.ResourceStatusType; import org.etsi.osl.tmf.ri639.model.ResourceUpdate; import org.etsi.osl.tmf.ri639.model.ResourceUsageStateType; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; /** * The ITU-T X.731 state that {@link KubernetesCRV1#toResourceCreate()} declares on the resource, * from what the producer (the cridge watcher) reported. * * <p>Two contracts have to hold at once: * * <ul> * <li>the operationalState/administrativeState pair is spelled out exactly as * {@code Resource.applyHealth} spells it, so that {@code Resource.deriveHealth()} on the inventory * side reads back the verdict the producer gave — that pair is what * {@code Service.findNextStateBasedOnResourceList} folds into the service state; * <li>{@code resourceStatus} (pool bookkeeping) and the state attributes are independent: neither * one is derived from the other. * </ul> */ public class KubernetesCRV1ApplyStateTest { private static KubernetesCRV1.KubernetesCRV1Builder aCR() { // the spec UUID is the only thing toResourceCreate() refuses to work without return KubernetesCRV1.builder().osl_KUBCRV1_RSPEC_UUID("rspec-uuid").name("a-cr"); } private static void assertState(ResourceUpdate rs, ResourceOperationalStateType oper, ResourceAdministrativeStateType admin) { assertEquals(oper, rs.getOperationalState(), "operationalState"); assertEquals(admin, rs.getAdministrativeState(), "administrativeState"); } /** * A CR whose producer said nothing about its state. Both attributes stay unset: on the inventory * side that derives as {@code PENDING}, which neither promotes nor demotes the supported service. * In particular there is no {@code operationalState=ENABLE} default any more — that used to be * declared unconditionally, and with {@code administrativeState} unset it was PENDING anyway. */ @Test public void nothingReportedLeavesBothAttributesUnset() { ResourceCreate rs = aCR().build().toResourceCreate(); assertState(rs, null, null); assertNull(rs.getUsageState()); } /** The {@code healthValue} → attribute-pair translation, verdict by verdict. */ @ParameterizedTest(name = "health={0} -> oper={1}, admin={2}") @CsvSource({ "UP, ENABLE, UNLOCKED", "DOWN, DISABLE, UNLOCKED", "HELD, ENABLE, LOCKED", "GONE, DISABLE, SHUTDOWN", "PENDING, , ", }) public void healthValueIsSpelledOutAsTheX731Pair(ResourceHealth health, ResourceOperationalStateType expectedOper, ResourceAdministrativeStateType expectedAdmin) { ResourceCreate rs = aCR().healthValue(health).build().toResourceCreate(); assertState(rs, expectedOper, expectedAdmin); } /** * When no verdict is given the producer may still report the attributes one by one; each is * applied on its own and the others are left untouched. */ @Test public void individualAttributesApplyWhenNoVerdictWasGiven() { ResourceCreate operOnly = aCR() .operationalStateValue(ResourceOperationalStateType.ENABLE) .build().toResourceCreate(); assertState(operOnly, ResourceOperationalStateType.ENABLE, null); ResourceCreate all = aCR() .operationalStateValue(ResourceOperationalStateType.DISABLE) .administrativeStateValue(ResourceAdministrativeStateType.LOCKED) .usageStateValue(ResourceUsageStateType.BUSY) .build().toResourceCreate(); assertState(all, ResourceOperationalStateType.DISABLE, ResourceAdministrativeStateType.LOCKED); assertEquals(ResourceUsageStateType.BUSY, all.getUsageState()); } /** * A verdict is authoritative: individual operational/administrative values reported alongside * it do not override the pair it implies. (This pins the precedence the implementation and its * Javadoc agree on; the field-level comment on {@code healthValue} currently claims the * opposite.) */ @Test public void healthValueWinsOverIndividualOperAndAdminValues() { ResourceCreate rs = aCR() .healthValue(ResourceHealth.UP) .operationalStateValue(ResourceOperationalStateType.DISABLE) .administrativeStateValue(ResourceAdministrativeStateType.LOCKED) .build().toResourceCreate(); assertState(rs, ResourceOperationalStateType.ENABLE, ResourceAdministrativeStateType.UNLOCKED); } // /** // * Usage state is orthogonal to health — {@link ResourceHealth} deliberately does not consult it — // * so a reported {@code usageStateValue} must survive a {@code healthValue} being present. // */ // @Test // public void usageStateIsAppliedEvenWhenAVerdictWasGiven() { // ResourceCreate rs = aCR() // .healthValue(ResourceHealth.UP) // .usageStateValue(ResourceUsageStateType.BUSY) // .build().toResourceCreate(); // assertState(rs, ResourceOperationalStateType.ENABLE, ResourceAdministrativeStateType.UNLOCKED); // assertEquals(ResourceUsageStateType.BUSY, rs.getUsageState()); // } /** * The watcher stamps {@link KubernetesCRV1#OSL_LABEL_DELETED} on a CR it saw disappear from the * cluster. That is GONE whatever else was reported, including a stale UP verdict. */ @Test public void deletedLabelIsGoneWhateverElseWasReported() { KubernetesCRV1 cr = aCR() .healthValue(ResourceHealth.UP) .operationalStateValue(ResourceOperationalStateType.ENABLE) .administrativeStateValue(ResourceAdministrativeStateType.UNLOCKED) .build(); cr.getProperties().put(KubernetesCRV1.OSL_LABEL_DELETED, "DELETED"); ResourceCreate rs = cr.toResourceCreate(); assertState(rs, ResourceOperationalStateType.DISABLE, ResourceAdministrativeStateType.SHUTDOWN); } /** * {@code statusValue} is pool bookkeeping. It is passed through to {@code resourceStatus} and * must play no part in the health attributes — an {@code ALARM} does not make the CR DOWN, and an * {@code AVAILABLE} does not make it UP. */ @ParameterizedTest(name = "resourceStatus={0} does not touch health") @CsvSource({"ALARM", "AVAILABLE", "RESERVED", "UNKNOWN"}) public void resourceStatusIsPassedThroughAndNeverDrivesHealth(ResourceStatusType status) { ResourceCreate silent = aCR().statusValue(status).build().toResourceCreate(); assertEquals(status, silent.getResourceStatus()); assertState(silent, null, null); ResourceCreate up = aCR().statusValue(status).healthValue(ResourceHealth.UP) .build().toResourceCreate(); assertEquals(status, up.getResourceStatus()); assertState(up, ResourceOperationalStateType.ENABLE, ResourceAdministrativeStateType.UNLOCKED); } /** The update path is the create path; the watcher uses both depending on what it already knows. */ @Test public void toResourceUpdateDeclaresTheSameState() { ResourceUpdate rs = aCR().healthValue(ResourceHealth.DOWN).build().toResourceUpdate(); assertState(rs, ResourceOperationalStateType.DISABLE, ResourceAdministrativeStateType.UNLOCKED); } } Loading
.classpathdeleted 100644 → 0 +0 −40 Original line number Diff line number Diff line <?xml version="1.0" encoding="UTF-8"?> <classpath> <classpathentry kind="src" output="target/classes" path="src/main/java"> <attributes> <attribute name="optional" value="true"/> <attribute name="maven.pomderived" value="true"/> </attributes> </classpathentry> <classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"> <attributes> <attribute name="maven.pomderived" value="true"/> <attribute name="optional" value="true"/> </attributes> </classpathentry> <classpathentry kind="src" output="target/test-classes" path="src/test/java"> <attributes> <attribute name="optional" value="true"/> <attribute name="maven.pomderived" value="true"/> <attribute name="test" value="true"/> </attributes> </classpathentry> <classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"> <attributes> <attribute name="maven.pomderived" value="true"/> <attribute name="test" value="true"/> <attribute name="optional" value="true"/> </attributes> </classpathentry> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"> <attributes> <attribute name="maven.pomderived" value="true"/> </attributes> </classpathentry> <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> <attributes> <attribute name="maven.pomderived" value="true"/> </attributes> </classpathentry> <classpathentry kind="output" path="target/classes"/> </classpath>
.settings/org.eclipse.core.resources.prefsdeleted 100644 → 0 +0 −6 Original line number Diff line number Diff line eclipse.preferences.version=1 encoding//src/main/java=utf-8 encoding//src/main/resources=UTF-8 encoding//src/test/java=utf-8 encoding//src/test/resources=UTF-8 encoding/<project>=UTF-8
pom.xml +18 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,19 @@ </distributionManagement> <dependencyManagement> <dependencies> <!-- Spring Boot BOM --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot-version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.projectlombok</groupId> Loading @@ -50,5 +63,10 @@ <artifactId>org.etsi.osl.model.tmf</artifactId> <version>${org.etsi.osl.model.tmf.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project> No newline at end of file
src/test/java/org/etsi/osl/domain/model/kubernetes/KubernetesCRV1ApplyStateTest.java 0 → 100644 +170 −0 Original line number Diff line number Diff line package org.etsi.osl.domain.model.kubernetes; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import org.etsi.osl.tmf.ri639.model.ResourceAdministrativeStateType; import org.etsi.osl.tmf.ri639.model.ResourceCreate; import org.etsi.osl.tmf.ri639.model.ResourceHealth; import org.etsi.osl.tmf.ri639.model.ResourceOperationalStateType; import org.etsi.osl.tmf.ri639.model.ResourceStatusType; import org.etsi.osl.tmf.ri639.model.ResourceUpdate; import org.etsi.osl.tmf.ri639.model.ResourceUsageStateType; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; /** * The ITU-T X.731 state that {@link KubernetesCRV1#toResourceCreate()} declares on the resource, * from what the producer (the cridge watcher) reported. * * <p>Two contracts have to hold at once: * * <ul> * <li>the operationalState/administrativeState pair is spelled out exactly as * {@code Resource.applyHealth} spells it, so that {@code Resource.deriveHealth()} on the inventory * side reads back the verdict the producer gave — that pair is what * {@code Service.findNextStateBasedOnResourceList} folds into the service state; * <li>{@code resourceStatus} (pool bookkeeping) and the state attributes are independent: neither * one is derived from the other. * </ul> */ public class KubernetesCRV1ApplyStateTest { private static KubernetesCRV1.KubernetesCRV1Builder aCR() { // the spec UUID is the only thing toResourceCreate() refuses to work without return KubernetesCRV1.builder().osl_KUBCRV1_RSPEC_UUID("rspec-uuid").name("a-cr"); } private static void assertState(ResourceUpdate rs, ResourceOperationalStateType oper, ResourceAdministrativeStateType admin) { assertEquals(oper, rs.getOperationalState(), "operationalState"); assertEquals(admin, rs.getAdministrativeState(), "administrativeState"); } /** * A CR whose producer said nothing about its state. Both attributes stay unset: on the inventory * side that derives as {@code PENDING}, which neither promotes nor demotes the supported service. * In particular there is no {@code operationalState=ENABLE} default any more — that used to be * declared unconditionally, and with {@code administrativeState} unset it was PENDING anyway. */ @Test public void nothingReportedLeavesBothAttributesUnset() { ResourceCreate rs = aCR().build().toResourceCreate(); assertState(rs, null, null); assertNull(rs.getUsageState()); } /** The {@code healthValue} → attribute-pair translation, verdict by verdict. */ @ParameterizedTest(name = "health={0} -> oper={1}, admin={2}") @CsvSource({ "UP, ENABLE, UNLOCKED", "DOWN, DISABLE, UNLOCKED", "HELD, ENABLE, LOCKED", "GONE, DISABLE, SHUTDOWN", "PENDING, , ", }) public void healthValueIsSpelledOutAsTheX731Pair(ResourceHealth health, ResourceOperationalStateType expectedOper, ResourceAdministrativeStateType expectedAdmin) { ResourceCreate rs = aCR().healthValue(health).build().toResourceCreate(); assertState(rs, expectedOper, expectedAdmin); } /** * When no verdict is given the producer may still report the attributes one by one; each is * applied on its own and the others are left untouched. */ @Test public void individualAttributesApplyWhenNoVerdictWasGiven() { ResourceCreate operOnly = aCR() .operationalStateValue(ResourceOperationalStateType.ENABLE) .build().toResourceCreate(); assertState(operOnly, ResourceOperationalStateType.ENABLE, null); ResourceCreate all = aCR() .operationalStateValue(ResourceOperationalStateType.DISABLE) .administrativeStateValue(ResourceAdministrativeStateType.LOCKED) .usageStateValue(ResourceUsageStateType.BUSY) .build().toResourceCreate(); assertState(all, ResourceOperationalStateType.DISABLE, ResourceAdministrativeStateType.LOCKED); assertEquals(ResourceUsageStateType.BUSY, all.getUsageState()); } /** * A verdict is authoritative: individual operational/administrative values reported alongside * it do not override the pair it implies. (This pins the precedence the implementation and its * Javadoc agree on; the field-level comment on {@code healthValue} currently claims the * opposite.) */ @Test public void healthValueWinsOverIndividualOperAndAdminValues() { ResourceCreate rs = aCR() .healthValue(ResourceHealth.UP) .operationalStateValue(ResourceOperationalStateType.DISABLE) .administrativeStateValue(ResourceAdministrativeStateType.LOCKED) .build().toResourceCreate(); assertState(rs, ResourceOperationalStateType.ENABLE, ResourceAdministrativeStateType.UNLOCKED); } // /** // * Usage state is orthogonal to health — {@link ResourceHealth} deliberately does not consult it — // * so a reported {@code usageStateValue} must survive a {@code healthValue} being present. // */ // @Test // public void usageStateIsAppliedEvenWhenAVerdictWasGiven() { // ResourceCreate rs = aCR() // .healthValue(ResourceHealth.UP) // .usageStateValue(ResourceUsageStateType.BUSY) // .build().toResourceCreate(); // assertState(rs, ResourceOperationalStateType.ENABLE, ResourceAdministrativeStateType.UNLOCKED); // assertEquals(ResourceUsageStateType.BUSY, rs.getUsageState()); // } /** * The watcher stamps {@link KubernetesCRV1#OSL_LABEL_DELETED} on a CR it saw disappear from the * cluster. That is GONE whatever else was reported, including a stale UP verdict. */ @Test public void deletedLabelIsGoneWhateverElseWasReported() { KubernetesCRV1 cr = aCR() .healthValue(ResourceHealth.UP) .operationalStateValue(ResourceOperationalStateType.ENABLE) .administrativeStateValue(ResourceAdministrativeStateType.UNLOCKED) .build(); cr.getProperties().put(KubernetesCRV1.OSL_LABEL_DELETED, "DELETED"); ResourceCreate rs = cr.toResourceCreate(); assertState(rs, ResourceOperationalStateType.DISABLE, ResourceAdministrativeStateType.SHUTDOWN); } /** * {@code statusValue} is pool bookkeeping. It is passed through to {@code resourceStatus} and * must play no part in the health attributes — an {@code ALARM} does not make the CR DOWN, and an * {@code AVAILABLE} does not make it UP. */ @ParameterizedTest(name = "resourceStatus={0} does not touch health") @CsvSource({"ALARM", "AVAILABLE", "RESERVED", "UNKNOWN"}) public void resourceStatusIsPassedThroughAndNeverDrivesHealth(ResourceStatusType status) { ResourceCreate silent = aCR().statusValue(status).build().toResourceCreate(); assertEquals(status, silent.getResourceStatus()); assertState(silent, null, null); ResourceCreate up = aCR().statusValue(status).healthValue(ResourceHealth.UP) .build().toResourceCreate(); assertEquals(status, up.getResourceStatus()); assertState(up, ResourceOperationalStateType.ENABLE, ResourceAdministrativeStateType.UNLOCKED); } /** The update path is the create path; the watcher uses both depending on what it already knows. */ @Test public void toResourceUpdateDeclaresTheSameState() { ResourceUpdate rs = aCR().healthValue(ResourceHealth.DOWN).build().toResourceUpdate(); assertState(rs, ResourceOperationalStateType.DISABLE, ResourceAdministrativeStateType.UNLOCKED); } }