CtrlK
BlogDocsLog inGet started
Tessl Logo

testland/openfeature-sdk-testing

Wraps OpenFeature (CNCF vendor-neutral SDK abstraction) testing patterns: the InMemoryProvider for hermetic tests without network calls, provider registration via OpenFeature.setProvider, the getBooleanValue/getBooleanDetails evaluation API with EvaluationDetails (value, variant, reason, errorCode), hooks for evaluation side-effects, and evaluation context for targeting-rule tests. Covers TypeScript, Java, and Python SDKs. Use when writing tests for code that resolves feature flags through the OpenFeature SDK regardless of the underlying flag management platform.

79

Quality

99%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files

multi-language-and-spec.mdreferences/

OpenFeature testing: Java / Python SDKs and specification tables

Companion reference for openfeature-sdk-testing. The SKILL.md spine shows the full TypeScript/Node.js flow; the flow is identical here, only the API names differ.

Java

Install (Maven, per github.com/open-feature/java-sdk README):

<dependency>
  <groupId>dev.openfeature</groupId>
  <artifactId>sdk</artifactId>
  <version>1.20.2</version>
</dependency>

Configure the InMemoryProvider:

import dev.openfeature.sdk.OpenFeatureAPI;
import dev.openfeature.sdk.Client;
import dev.openfeature.sdk.providers.memory.Flag;
import dev.openfeature.sdk.providers.memory.InMemoryProvider;

Map<String, Flag<?>> flags = new HashMap<>();
flags.put("show-new-ui", Flag.builder()
    .variant("on", true)
    .variant("off", false)
    .defaultVariant("on")
    .build());

OpenFeatureAPI api = OpenFeatureAPI.getInstance();
api.setProviderAndWait(new InMemoryProvider(flags));
Client client = api.getClient();

Evaluate flags:

boolean enabled = client.getBooleanValue("show-new-ui", false);

FlagEvaluationDetails<Boolean> details =
    client.getBooleanDetails("show-new-ui", false);
// details.getValue()    - resolved value
// details.getVariant()  - "on" or "off"
// details.getReason()   - "STATIC", "DEFAULT", etc.
// details.getErrorCode()- ErrorCode.FLAG_NOT_FOUND, TYPE_MISMATCH, etc.

Per-invocation evaluation context:

Map<String, Value> attrs = new HashMap<>();
attrs.put("email", new Value("user@example.com"));
EvaluationContext ctx = new ImmutableContext("user-42", attrs);
boolean value = client.getBooleanValue("beta-access", false, ctx);

Python

Install (per github.com/open-feature/python-sdk README):

pip install openfeature-sdk==0.10.0

Configure the InMemoryProvider:

from openfeature import api
from openfeature.provider.in_memory_provider import InMemoryFlag, InMemoryProvider

flags = {
    "show-new-ui": InMemoryFlag(
        default_variant="on",
        variants={"on": True, "off": False}
    ),
}

api.set_provider_and_wait(InMemoryProvider(flags))
client = api.get_client()

Evaluate flags:

enabled = client.get_boolean_value("show-new-ui", False)

details = client.get_boolean_details("show-new-ui", False)
# details.value       - resolved value
# details.variant     - "on" / "off"
# details.reason      - "STATIC", "DEFAULT", etc.
# details.error_code  - "FLAG_NOT_FOUND", "TYPE_MISMATCH", etc.

Per-invocation evaluation context:

from openfeature.evaluation_context import EvaluationContext
ctx = EvaluationContext(targeting_key="user-42",
                        attributes={"email": "user@example.com"})
details = client.get_boolean_details("beta-access", False, ctx)

EvaluationDetails and reason codes

Per the OpenFeature specification (openfeature.dev/specification/sections/flag-evaluation, Requirements 1.4.3-1.4.15), EvaluationDetails carries:

FieldTypeMeaning
valueTResolved flag value (spec req. 1.4.3)
flagKeystringThe requested flag identifier (1.4.5)
variantstringProvider-supplied variant name (1.4.6)
reasonstringResolution rationale (1.4.7)
errorCodeenumFailure classification (1.4.8)
errorMessagestringOptional context for the error (1.4.13)
flagMetadatamapImmutable provider-supplied data (1.4.14)

Canonical reason values (per openfeature.dev/specification/sections/providers, Requirement 2.2.5): STATIC, DEFAULT, TARGETING_MATCH, SPLIT, CACHED, DISABLED, UNKNOWN, STALE, ERROR.

Canonical error codes include FLAG_NOT_FOUND, TYPE_MISMATCH, PARSE_ERROR, TARGETING_KEY_MISSING, INVALID_CONTEXT, GENERAL, PROVIDER_NOT_READY, PROVIDER_FATAL.

Hook lifecycle stages and execution order

Per openfeature.dev/docs/reference/concepts/hooks and the specification (openfeature.dev/specification/sections/hooks, Requirement 4.3.1-4.3.8), the four stages are:

StageRuns when
beforeBefore flag resolution; can modify evaluation context
afterAfter successful resolution; can validate the returned value
errorOn resolution failure or unhandled before-hook error
finallyUnconditionally after all other stages

Execution order for before: API - Client - Invocation. For after, error, finally: reverse order (Invocation - Client - API), per specification Requirement 4.4.2.

SKILL.md

tile.json