diff --git a/providers/ofrep/README.md b/providers/ofrep/README.md index 6a4688d055..a31b1e3bde 100644 --- a/providers/ofrep/README.md +++ b/providers/ofrep/README.md @@ -72,3 +72,15 @@ Given below are the supported configurations: | proxySelector | ProxySelector | ProxySelector.getDefault() | The proxy selector used by HTTP Client. | executor | Executor | Thread Pool of size 5 | The executor used by HTTP Client. + +## Provider conformance (TCK) + +`OfrepTest` in `src/test/java/.../ofrep/tck/` runs the [OpenFeature Provider TCK](../../tools/tck/README.md) +against flagd's OFREP endpoint, using the flagd-testbed image and its control API. It needs Docker: + +```bash +mvn -Ptck -pl providers/ofrep -am test +``` + +CI runs it in the `Provider TCK` job. Set `tck.testFailureIgnore` to `true` in this module's pom to +report failures without failing the build. diff --git a/providers/ofrep/pom.xml b/providers/ofrep/pom.xml index dd5bc41f8d..08de121b4f 100644 --- a/providers/ofrep/pom.xml +++ b/providers/ofrep/pom.xml @@ -17,6 +17,14 @@ OFREP Provider https://openfeature.dev + + + [0.1.0,) + 2.0.4 + + false + + Rahul-Baradol @@ -81,5 +89,22 @@ 4.12.0 test + + + + dev.openfeature.contrib.tools + tck + ${tck.version} + test + + + + + org.testcontainers + testcontainers + ${testcontainers.version} + test + + diff --git a/providers/ofrep/src/test/java/dev/openfeature/contrib/providers/ofrep/tck/OfrepTest.java b/providers/ofrep/src/test/java/dev/openfeature/contrib/providers/ofrep/tck/OfrepTest.java new file mode 100644 index 0000000000..b0c9d8d20a --- /dev/null +++ b/providers/ofrep/src/test/java/dev/openfeature/contrib/providers/ofrep/tck/OfrepTest.java @@ -0,0 +1,86 @@ +package dev.openfeature.contrib.providers.ofrep.tck; + +import dev.openfeature.contrib.providers.ofrep.OfrepProvider; +import dev.openfeature.contrib.providers.ofrep.OfrepProviderOptions; +import dev.openfeature.contrib.tools.tck.BackendEndpoint; +import dev.openfeature.contrib.tools.tck.Capability; +import dev.openfeature.contrib.tools.tck.ContainerizedProviderTckTest; +import dev.openfeature.contrib.tools.tck.KnownDeviation; +import dev.openfeature.sdk.FeatureProvider; +import java.io.File; +import java.time.Duration; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +/** Runs the OpenFeature Provider TCK against the OFREP provider, backed by flagd's OFREP endpoint. */ +public class OfrepTest extends ContainerizedProviderTckTest { + + private static final int OFREP_PORT = 8016; + + /** Nothing listens here; outages on the Compose stack belong to the control API. */ + private static final int UNAVAILABLE_PORT = 9999; + + /** The flagd-testbed's own stack, so this suite and the flagd adoption share one image pin. */ + @Override + public File composeFile() { + return new File("../flagd/test-harness/docker-compose.yaml"); + } + + @Override + public String backendService() { + return "flagd"; + } + + @Override + public List backendPorts() { + return Collections.singletonList(OFREP_PORT); + } + + @Override + public FeatureProvider createProvider(BackendEndpoint endpoint) { + return OfrepProvider.constructProvider(OfrepProviderOptions.builder() + .baseUrl("http://" + endpoint.host() + ":" + endpoint.port(OFREP_PORT)) + .build()); + } + + @Override + public FeatureProvider createUnavailableProvider() { + return OfrepProvider.constructProvider(OfrepProviderOptions.builder() + .baseUrl("http://localhost:" + UNAVAILABLE_PORT) + .connectTimeout(Duration.ofMillis(500)) + .requestTimeout(Duration.ofMillis(500)) + .build()); + } + + /** + * {@inheritDoc} + * + *

The provider has no lifecycle of its own: no {@code initialize()}, no events, no state + * between calls, and an executor {@code shutdown()} never recreates. That withholds lifecycle, + * reinitialization, events, stale, configuration change and unavailable init. Numeric coercion + * is withheld because the provider keeps integers and doubles strictly apart, which the rule + * allows. Disabled flags is a defect; see {@link #knownDeviations()}. + */ + @Override + public Set capabilities() { + return Capability.declarableExcept( + Capability.LIFECYCLE, + Capability.REINITIALIZATION, + Capability.EVENTS, + Capability.STALE, + Capability.CONFIGURATION_CHANGE, + Capability.DISABLED_FLAGS, + Capability.UNAVAILABLE_INIT, + Capability.NUMERIC_COERCION); + } + + @Override + public List knownDeviations() { + return Collections.singletonList(KnownDeviation.untracked( + Capability.DISABLED_FLAGS, + "A value-less OFREP evaluation success (codeDefaultFlag) is reported as FLAG_NOT_FOUND " + + "instead of the code default with the server's reason; flagd answers a " + + "disabled flag that way.")); + } +}