feat: implement LicenseGate for feature checking
- Thread-safe AtomicReference-based license holder - Defaults to open mode (all features enabled) when no license loaded - Runtime license loading with feature/limit queries - Unit tests for open mode and licensed mode
This commit is contained in:
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<LicenseInfo> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user