diff --git a/cameleer3-server-app/src/test/java/com/cameleer3/server/core/license/LicenseGateTest.java b/cameleer3-server-app/src/test/java/com/cameleer3/server/core/license/LicenseGateTest.java new file mode 100644 index 00000000..00404d24 --- /dev/null +++ b/cameleer3-server-app/src/test/java/com/cameleer3/server/core/license/LicenseGateTest.java @@ -0,0 +1,41 @@ +package com.cameleer3.server.core.license; + +import org.junit.jupiter.api.Test; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Map; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +class LicenseGateTest { + + @Test + void noLicense_allFeaturesEnabled() { + LicenseGate gate = new LicenseGate(); + // No license loaded -> open mode + + assertThat(gate.isEnabled(Feature.debugger)).isTrue(); + assertThat(gate.isEnabled(Feature.replay)).isTrue(); + assertThat(gate.isEnabled(Feature.lineage)).isTrue(); + assertThat(gate.getTier()).isEqualTo("open"); + } + + @Test + void withLicense_onlyLicensedFeaturesEnabled() { + LicenseGate gate = new LicenseGate(); + LicenseInfo license = new LicenseInfo("MID", + Set.of(Feature.topology, Feature.lineage, Feature.correlation), + Map.of("max_agents", 10, "retention_days", 30), + Instant.now(), Instant.now().plus(365, ChronoUnit.DAYS)); + gate.load(license); + + assertThat(gate.isEnabled(Feature.topology)).isTrue(); + assertThat(gate.isEnabled(Feature.lineage)).isTrue(); + assertThat(gate.isEnabled(Feature.debugger)).isFalse(); + assertThat(gate.isEnabled(Feature.replay)).isFalse(); + assertThat(gate.getTier()).isEqualTo("MID"); + assertThat(gate.getLimit("max_agents", 0)).isEqualTo(10); + } +} diff --git a/cameleer3-server-core/src/main/java/com/cameleer3/server/core/license/LicenseGate.java b/cameleer3-server-core/src/main/java/com/cameleer3/server/core/license/LicenseGate.java new file mode 100644 index 00000000..da298960 --- /dev/null +++ b/cameleer3-server-core/src/main/java/com/cameleer3/server/core/license/LicenseGate.java @@ -0,0 +1,35 @@ +package com.cameleer3.server.core.license; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.atomic.AtomicReference; + +public class LicenseGate { + + private static final Logger log = LoggerFactory.getLogger(LicenseGate.class); + + private final AtomicReference current = new AtomicReference<>(LicenseInfo.open()); + + public void load(LicenseInfo license) { + current.set(license); + log.info("License loaded: tier={}, features={}, expires={}", + license.tier(), license.features(), license.expiresAt()); + } + + public boolean isEnabled(Feature feature) { + return current.get().hasFeature(feature); + } + + public String getTier() { + return current.get().tier(); + } + + public int getLimit(String key, int defaultValue) { + return current.get().getLimit(key, defaultValue); + } + + public LicenseInfo getCurrent() { + return current.get(); + } +}