|
29 | 29 | import org.eclipse.ditto.policies.model.PolicyEntry; |
30 | 30 | import org.eclipse.ditto.policies.model.PolicyId; |
31 | 31 | import org.eclipse.ditto.policies.model.PoliciesResourceType; |
| 32 | +import org.eclipse.ditto.policies.model.ResourceKey; |
32 | 33 | import org.eclipse.ditto.policies.model.Subject; |
33 | 34 | import org.eclipse.ditto.policies.model.SubjectId; |
| 35 | +import org.eclipse.ditto.policies.model.enforcers.SubjectClassification; |
34 | 36 | import org.junit.Test; |
35 | 37 |
|
36 | 38 | public final class PolicyEnforcerTest { |
@@ -131,6 +133,67 @@ public void forNamespaceWithNullPolicyReturnsSameInstance() { |
131 | 133 | assertThat(enforcer.forNamespace("any.ns")).isSameAs(enforcer); |
132 | 134 | } |
133 | 135 |
|
| 136 | + @Test |
| 137 | + public void classifyReadSubjectsMatchesDirectEnforcerClassification() { |
| 138 | + final Policy policy = PoliciesModelFactory.newPolicyBuilder(PolicyId.of("test:policy")) |
| 139 | + .set(newScopedEntry("global", "google:global-user", Collections.emptyList())) |
| 140 | + .build(); |
| 141 | + final PolicyEnforcer policyEnforcer = PolicyEnforcer.of(policy); |
| 142 | + final ResourceKey root = PoliciesResourceType.thingResource("/"); |
| 143 | + |
| 144 | + final SubjectClassification memoized = policyEnforcer.classifyReadSubjects(root); |
| 145 | + final SubjectClassification direct = policyEnforcer.getEnforcer() |
| 146 | + .classifySubjects(root, PoliciesModelFactory.newPermissions(Permission.READ)); |
| 147 | + |
| 148 | + assertThat(memoized.getUnrestricted()).isEqualTo(direct.getUnrestricted()); |
| 149 | + assertThat(memoized.getPartialOnly()).isEqualTo(direct.getPartialOnly()); |
| 150 | + assertThat(memoized.getEffectedGranted()).isEqualTo(direct.getEffectedGranted()); |
| 151 | + } |
| 152 | + |
| 153 | + @Test |
| 154 | + public void classifyReadSubjectsMemoizesRepeatedCallsForSameResource() { |
| 155 | + final Policy policy = PoliciesModelFactory.newPolicyBuilder(PolicyId.of("test:policy")) |
| 156 | + .set(newScopedEntry("global", "google:global-user", Collections.emptyList())) |
| 157 | + .build(); |
| 158 | + final PolicyEnforcer policyEnforcer = PolicyEnforcer.of(policy); |
| 159 | + final ResourceKey root = PoliciesResourceType.thingResource("/"); |
| 160 | + |
| 161 | + // A second call for the same resource must return the memoized instance, not re-walk the policy tree. |
| 162 | + final SubjectClassification first = policyEnforcer.classifyReadSubjects(root); |
| 163 | + final SubjectClassification second = policyEnforcer.classifyReadSubjects(root); |
| 164 | + |
| 165 | + assertThat(second).isSameAs(first); |
| 166 | + } |
| 167 | + |
| 168 | + @Test |
| 169 | + public void getRootResourceReadClassificationDelegatesToClassifyReadSubjects() { |
| 170 | + final Policy policy = PoliciesModelFactory.newPolicyBuilder(PolicyId.of("test:policy")) |
| 171 | + .set(newScopedEntry("global", "google:global-user", Collections.emptyList())) |
| 172 | + .build(); |
| 173 | + final PolicyEnforcer policyEnforcer = PolicyEnforcer.of(policy); |
| 174 | + |
| 175 | + assertThat(policyEnforcer.getRootResourceReadClassification()) |
| 176 | + .isSameAs(policyEnforcer.classifyReadSubjects(PoliciesResourceType.thingResource("/"))); |
| 177 | + } |
| 178 | + |
| 179 | + @Test |
| 180 | + public void classifyReadSubjectsStaysCorrectUnderBoundedCache() { |
| 181 | + final Policy policy = PoliciesModelFactory.newPolicyBuilder(PolicyId.of("test:policy")) |
| 182 | + .set(newScopedEntry("global", "google:global-user", Collections.emptyList())) |
| 183 | + .build(); |
| 184 | + // Tiny bound: cache correctness must not depend on capacity — a miss simply recomputes an equal result. |
| 185 | + final PolicyEnforcer bounded = PolicyEnforcer.of(policy, 100, 1); |
| 186 | + final ResourceKey a = PoliciesResourceType.thingResource("/features/a"); |
| 187 | + final ResourceKey b = PoliciesResourceType.thingResource("/features/b"); |
| 188 | + |
| 189 | + final SubjectClassification classificationA = bounded.classifyReadSubjects(a); |
| 190 | + bounded.classifyReadSubjects(b); |
| 191 | + final SubjectClassification classificationAgain = bounded.classifyReadSubjects(a); |
| 192 | + |
| 193 | + assertThat(classificationAgain.getUnrestricted()).isEqualTo(classificationA.getUnrestricted()); |
| 194 | + assertThat(classificationAgain.getPartialOnly()).isEqualTo(classificationA.getPartialOnly()); |
| 195 | + } |
| 196 | + |
134 | 197 | private static PolicyEntry newScopedEntry(final String label, final String subjectId, final List<String> namespaces) { |
135 | 198 | return PoliciesModelFactory.newPolicyEntry(label, |
136 | 199 | Collections.singletonList(Subject.newInstance(SubjectId.newInstance(subjectId))), |
|
0 commit comments