feat(license): rewrite LicenseGate around state + effective limits
LicenseGate now exposes getState() (delegates to LicenseStateMachine), getEffectiveLimits() (merged over DefaultTierLimits in ACTIVE/GRACE, defaults-only in ABSENT/EXPIRED/INVALID), markInvalid(reason), and clear(). Internal snapshot is an immutable record-like class swapped atomically so concurrent reads see a consistent license+reason pair. Removes the transient openSentinel() and getTier() introduced by earlier tasks (no production consumers). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,30 +3,62 @@ package com.cameleer.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.UUID;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class LicenseGateTest {
|
||||
|
||||
@Test
|
||||
void noLicense_returnsOpenTier() {
|
||||
void absent_byDefault() {
|
||||
LicenseGate gate = new LicenseGate();
|
||||
assertThat(gate.getTier()).isEqualTo("open");
|
||||
assertThat(gate.getLimit("max_apps", 99)).isEqualTo(99);
|
||||
assertThat(gate.getState()).isEqualTo(LicenseState.ABSENT);
|
||||
assertThat(gate.getEffectiveLimits().get("max_apps"))
|
||||
.isEqualTo(DefaultTierLimits.DEFAULTS.get("max_apps"));
|
||||
assertThat(gate.getCurrent()).isNull();
|
||||
assertThat(gate.getInvalidReason()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void loaded_exposesLimits() {
|
||||
void load_setsActiveAndMergesLimits() {
|
||||
LicenseGate gate = new LicenseGate();
|
||||
LicenseInfo info = new LicenseInfo(java.util.UUID.randomUUID(), "acme", "MID",
|
||||
Map.of("max_agents", 10, "retention_days", 30),
|
||||
Instant.now(), Instant.now().plus(365, ChronoUnit.DAYS), 0);
|
||||
LicenseInfo info = new LicenseInfo(UUID.randomUUID(), "acme", "label",
|
||||
Map.of("max_apps", 50), Instant.now(),
|
||||
Instant.now().plusSeconds(86400), 0);
|
||||
gate.load(info);
|
||||
|
||||
assertThat(gate.getTier()).isEqualTo("MID");
|
||||
assertThat(gate.getLimit("max_agents", 0)).isEqualTo(10);
|
||||
assertThat(gate.getLimit("missing", 7)).isEqualTo(7);
|
||||
assertThat(gate.getState()).isEqualTo(LicenseState.ACTIVE);
|
||||
assertThat(gate.getEffectiveLimits().get("max_apps")).isEqualTo(50);
|
||||
assertThat(gate.getEffectiveLimits().get("max_users"))
|
||||
.isEqualTo(DefaultTierLimits.DEFAULTS.get("max_users"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void markInvalid_overridesActive() {
|
||||
LicenseGate gate = new LicenseGate();
|
||||
LicenseInfo info = new LicenseInfo(UUID.randomUUID(), "acme", null,
|
||||
Map.of("max_apps", 50), Instant.now(),
|
||||
Instant.now().plusSeconds(86400), 0);
|
||||
gate.load(info);
|
||||
|
||||
gate.markInvalid("signature failed");
|
||||
assertThat(gate.getState()).isEqualTo(LicenseState.INVALID);
|
||||
assertThat(gate.getEffectiveLimits().get("max_apps"))
|
||||
.isEqualTo(DefaultTierLimits.DEFAULTS.get("max_apps"));
|
||||
assertThat(gate.getInvalidReason()).isEqualTo("signature failed");
|
||||
}
|
||||
|
||||
@Test
|
||||
void clear_returnsToAbsent() {
|
||||
LicenseGate gate = new LicenseGate();
|
||||
LicenseInfo info = new LicenseInfo(UUID.randomUUID(), "acme", null,
|
||||
Map.of(), Instant.now(),
|
||||
Instant.now().plusSeconds(86400), 0);
|
||||
gate.load(info);
|
||||
gate.clear();
|
||||
|
||||
assertThat(gate.getState()).isEqualTo(LicenseState.ABSENT);
|
||||
assertThat(gate.getCurrent()).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user