diff --git a/api/src/main/java/com/oviva/spicegen/api/CheckPermission.java b/api/src/main/java/com/oviva/spicegen/api/CheckPermission.java index 2052674..321e474 100644 --- a/api/src/main/java/com/oviva/spicegen/api/CheckPermission.java +++ b/api/src/main/java/com/oviva/spicegen/api/CheckPermission.java @@ -1,92 +1,30 @@ package com.oviva.spicegen.api; -import java.util.Objects; +import com.oviva.spicegen.api.internal.CheckPermissionImpl; -public final class CheckPermission { +public interface CheckPermission { - private final ObjectRef resource; - private final String permission; - private final SubjectRef subject; - - private final Consistency consistency; - - private CheckPermission(Builder builder) { - resource = builder.resource; - permission = builder.permission; - subject = builder.subject; - consistency = builder.consistency; - } - - public static Builder newBuilder() { - return new Builder(); - } - - public ObjectRef resource() { - return resource; - } - - public String permission() { - return permission; - } - - public SubjectRef subject() { - return subject; + static Builder newBuilder() { + return new CheckPermissionImpl.Builder(); } - public Consistency consistency() { - return consistency; - } + ObjectRef resource(); - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - var that = (CheckPermission) o; - return Objects.equals(resource, that.resource) - && Objects.equals(permission, that.permission) - && Objects.equals(subject, that.subject) - && Objects.equals(consistency, that.consistency); - } - - @Override - public int hashCode() { - return Objects.hash(resource, permission, subject, consistency); - } + String permission(); - public static final class Builder { - private ObjectRef resource; - private String permission; - private SubjectRef subject; - private Consistency consistency = Consistency.fullyConsistent(); + SubjectRef subject(); - private Builder() {} + Consistency consistency(); - public Builder resource(ObjectRef resource) { - this.resource = resource; - return this; - } + interface Builder { + Builder resource(ObjectRef resource); - public Builder permission(String permission) { - this.permission = permission; - return this; - } + Builder permission(String permission); - public Builder subject(SubjectRef subject) { - this.subject = subject; - return this; - } + Builder subject(SubjectRef subject); - public Builder consistency(Consistency consistency) { - this.consistency = consistency; - return this; - } + Builder consistency(Consistency consistency); - public CheckPermission build() { - return new CheckPermission(this); - } + CheckPermission build(); } } diff --git a/api/src/main/java/com/oviva/spicegen/api/Consistency.java b/api/src/main/java/com/oviva/spicegen/api/Consistency.java index b0aa6c5..e642910 100644 --- a/api/src/main/java/com/oviva/spicegen/api/Consistency.java +++ b/api/src/main/java/com/oviva/spicegen/api/Consistency.java @@ -1,57 +1,25 @@ package com.oviva.spicegen.api; -import java.util.Objects; +import com.oviva.spicegen.api.internal.ConsistencyImpl; -public final class Consistency { +public interface Consistency { - private static Consistency FULLY_CONSISTENT = new Consistency(Requirement.FULLY_CONSISTENT, null); - private final Requirement requirement; + String consistencyToken(); - private final String consistencyToken; + Requirement requirement(); - private Consistency(Requirement requirement, String consistencyToken) { - this.requirement = requirement; - this.consistencyToken = consistencyToken; + static Consistency fullyConsistent() { + return ConsistencyImpl.fullyConsistent(); } - public String consistencyToken() { - return consistencyToken; - } - - public Requirement requirement() { - return requirement; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - var that = (Consistency) o; - return requirement == that.requirement - && Objects.equals(consistencyToken, that.consistencyToken); - } - - @Override - public int hashCode() { - return Objects.hash(requirement, consistencyToken); - } - - public static Consistency fullyConsistent() { - return FULLY_CONSISTENT; - } - - public static Consistency atLeastAsFreshAs(String consistencyToken) { + static Consistency atLeastAsFreshAs(String consistencyToken) { if (consistencyToken == null) { - return FULLY_CONSISTENT; + return ConsistencyImpl.fullyConsistent(); } - return new Consistency(Requirement.AT_LEAST_AS_FRESH, consistencyToken); + return new ConsistencyImpl(Consistency.Requirement.AT_LEAST_AS_FRESH, consistencyToken); } - public enum Requirement { + enum Requirement { FULLY_CONSISTENT, AT_LEAST_AS_FRESH } diff --git a/api/src/main/java/com/oviva/spicegen/api/Precondition.java b/api/src/main/java/com/oviva/spicegen/api/Precondition.java index c3b5def..5004129 100644 --- a/api/src/main/java/com/oviva/spicegen/api/Precondition.java +++ b/api/src/main/java/com/oviva/spicegen/api/Precondition.java @@ -1,63 +1,36 @@ package com.oviva.spicegen.api; -public final class Precondition { +import com.oviva.spicegen.api.internal.PreconditionImpl; - private final Condition condition; - private final RelationshipFilter filter; +public interface Precondition { - private Precondition(Builder builder) { - condition = builder.condition; - filter = builder.filter; - } + Condition condition(); - public static Precondition mustMatch(RelationshipFilter filter) { - return new Precondition(Condition.MUST_MATCH, filter); - } + RelationshipFilter filter(); - public static Precondition mustNotMatch(RelationshipFilter filter) { - return new Precondition(Condition.MUST_NOT_MATCH, filter); + static Precondition mustMatch(RelationshipFilter filter) { + return new PreconditionImpl(Condition.MUST_MATCH, filter); } - public static Builder newBuilder() { - return new Builder(); + static Precondition mustNotMatch(RelationshipFilter filter) { + return new PreconditionImpl(Condition.MUST_NOT_MATCH, filter); } - private Precondition(Condition condition, RelationshipFilter filter) { - this.condition = condition; - this.filter = filter; - } - - public Condition condition() { - return condition; - } - - public RelationshipFilter filter() { - return filter; - } - - public enum Condition { + enum Condition { MUST_MATCH, MUST_NOT_MATCH } - public static final class Builder { - private Condition condition; - private RelationshipFilter filter; + static Builder newBuilder() { + return new PreconditionImpl.Builder(); + } - private Builder() {} + interface Builder { - public Builder condition(Condition val) { - condition = val; - return this; - } + Precondition.Builder condition(Condition condition); - public Builder filter(RelationshipFilter val) { - filter = val; - return this; - } + Precondition.Builder filter(RelationshipFilter filter); - public Precondition build() { - return new Precondition(this); - } + Precondition build(); } } diff --git a/api/src/main/java/com/oviva/spicegen/api/RelationshipFilter.java b/api/src/main/java/com/oviva/spicegen/api/RelationshipFilter.java index 423cb04..8ec17ab 100644 --- a/api/src/main/java/com/oviva/spicegen/api/RelationshipFilter.java +++ b/api/src/main/java/com/oviva/spicegen/api/RelationshipFilter.java @@ -1,137 +1,56 @@ package com.oviva.spicegen.api; +import com.oviva.spicegen.api.internal.RelationshipFilterImpl; import java.util.Optional; -public final class RelationshipFilter { +public interface RelationshipFilter { - private final String resourceKind; - - /** optional */ - private final String resourceId; - - /** optional */ - private final String relation; - - /** optional */ - private final SubjectFilter subjectFilter; - - private RelationshipFilter(Builder builder) { - resourceKind = builder.resourceKind; - resourceId = builder.resourceId; - relation = builder.relation; - subjectFilter = builder.subjectFilter; + static Builder newBuilder() { + return new RelationshipFilterImpl.Builder(); } - public static Builder newBuilder() { - return new Builder(); - } - - public String resourceKind() { - return resourceKind; - } - - public Optional resourceId() { - return Optional.ofNullable(resourceId); - } - - public Optional relation() { - return Optional.ofNullable(relation); - } - - public Optional subjectFilter() { - return Optional.ofNullable(subjectFilter); - } + String resourceKind(); - public static class SubjectFilter { + Optional resourceId(); - private final String subjectKind; + Optional relation(); - /** optional */ - private final String subjectId; + Optional subjectFilter(); - /** optional */ - private final String relation; + interface SubjectFilter { - private SubjectFilter(Builder builder) { - subjectKind = builder.subjectKind; - subjectId = builder.subjectId; - relation = builder.relation; + static Builder newBuilder() { + return new RelationshipFilterImpl.SubjectFilterImpl.Builder(); } - public static Builder newBuilder() { - return new Builder(); - } - - public String subjectKind() { - return subjectKind; - } + String subjectKind(); - public Optional subjectId() { - return Optional.ofNullable(subjectId); - } - - public Optional relation() { - return Optional.ofNullable(relation); - } + Optional subjectId(); - public static final class Builder { - private String subjectKind; - private String subjectId; - private String relation; + Optional relation(); - private Builder() {} + interface Builder { - public Builder subjectKind(String val) { - subjectKind = val; - return this; - } + Builder subjectKind(String val); - public Builder subjectId(String val) { - subjectId = val; - return this; - } + Builder subjectId(String val); - public Builder relation(String val) { - relation = val; - return this; - } + Builder relation(String val); - public SubjectFilter build() { - return new SubjectFilter(this); - } + SubjectFilter build(); } } - public static final class Builder { - private String resourceKind; - private String resourceId; - private String relation; - private SubjectFilter subjectFilter; + interface Builder { - private Builder() {} + Builder resourceKind(String val); - public Builder resourceKind(String val) { - resourceKind = val; - return this; - } - - public Builder resourceId(String val) { - resourceId = val; - return this; - } + Builder resourceId(String val); - public Builder relation(String val) { - relation = val; - return this; - } + Builder relation(String val); - public Builder subjectFilter(SubjectFilter val) { - subjectFilter = val; - return this; - } + Builder subjectFilter(SubjectFilter val); - public RelationshipFilter build() { - return new RelationshipFilter(this); - } + RelationshipFilter build(); } } diff --git a/api/src/main/java/com/oviva/spicegen/api/UpdateRelationship.java b/api/src/main/java/com/oviva/spicegen/api/UpdateRelationship.java index dee938b..cc71cfe 100644 --- a/api/src/main/java/com/oviva/spicegen/api/UpdateRelationship.java +++ b/api/src/main/java/com/oviva/spicegen/api/UpdateRelationship.java @@ -1,81 +1,28 @@ package com.oviva.spicegen.api; -import java.util.Objects; +import com.oviva.spicegen.api.internal.UpdateRelationshipImpl; -public final class UpdateRelationship { - private final ObjectRef resource; +public interface UpdateRelationship { - private final String relation; - - private final SubjectRef subject; - - private final Operation operation; - - private UpdateRelationship( - ObjectRef resource, String relation, SubjectRef subject, Operation operation) { - this.resource = resource; - this.relation = relation; - this.subject = subject; - this.operation = operation; - } - - public static UpdateRelationship ofUpdate( - ObjectRef resource, String relation, ObjectRef subject) { - return new UpdateRelationship( + static UpdateRelationship ofUpdate(ObjectRef resource, String relation, ObjectRef subject) { + return new UpdateRelationshipImpl( resource, relation, SubjectRef.ofObject(subject), Operation.UPDATE); } - public static UpdateRelationship ofDelete( - ObjectRef resource, String relation, ObjectRef subject) { - return new UpdateRelationship( + static UpdateRelationship ofDelete(ObjectRef resource, String relation, ObjectRef subject) { + return new UpdateRelationshipImpl( resource, relation, SubjectRef.ofObject(subject), Operation.DELETE); } - public SubjectRef subject() { - return subject; - } + SubjectRef subject(); - public ObjectRef resource() { - return resource; - } + ObjectRef resource(); - public String relation() { - return relation; - } + String relation(); - public Operation operation() { - return operation; - } - - @Override - public String toString() { - var res = resource != null ? resource.toString() : ""; - var rel = relation != null ? relation : ""; - var sub = subject != null ? subject.toString() : ""; - return operation.name() + "(" + res + "#" + rel + "@" + sub + ")"; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - var that = (UpdateRelationship) o; - return Objects.equals(resource, that.resource) - && Objects.equals(relation, that.relation) - && Objects.equals(subject, that.subject) - && operation == that.operation; - } - - @Override - public int hashCode() { - return Objects.hash(resource, relation, subject, operation); - } + Operation operation(); - public enum Operation { + enum Operation { UPDATE, DELETE diff --git a/api/src/main/java/com/oviva/spicegen/api/UpdateRelationships.java b/api/src/main/java/com/oviva/spicegen/api/UpdateRelationships.java index c189976..3012535 100644 --- a/api/src/main/java/com/oviva/spicegen/api/UpdateRelationships.java +++ b/api/src/main/java/com/oviva/spicegen/api/UpdateRelationships.java @@ -1,62 +1,27 @@ package com.oviva.spicegen.api; -import java.util.ArrayList; +import com.oviva.spicegen.api.internal.UpdateRelationshipsImpl; import java.util.List; -public final class UpdateRelationships { +public interface UpdateRelationships { - private final List preconditions; - private final List updates; - - public static UpdateRelationshipsBuilder newBuilder() { - return new UpdateRelationshipsBuilder(); - } - - private UpdateRelationships(List updates, List preconditions) { - this.updates = List.copyOf(updates); - this.preconditions = List.copyOf(preconditions); - } - - public List updates() { - return updates; - } - - public List preconditions() { - return preconditions; + static Builder newBuilder() { + return new UpdateRelationshipsImpl.Builder(); } - public static final class UpdateRelationshipsBuilder { - private List preconditions = new ArrayList<>(); - private List updates = new ArrayList<>(); - - private UpdateRelationshipsBuilder() {} + List updates(); - public static UpdateRelationshipsBuilder newBuilder() { - return new UpdateRelationshipsBuilder(); - } + List preconditions(); - public UpdateRelationshipsBuilder preconditions(List preconditions) { - this.preconditions = preconditions; - return this; - } + interface Builder { + Builder preconditions(List preconditions); - public UpdateRelationshipsBuilder precondition(Precondition precondition) { - this.preconditions.add(precondition); - return this; - } + Builder precondition(Precondition precondition); - public UpdateRelationshipsBuilder updates(List updates) { - this.updates = updates; - return this; - } + Builder updates(List updates); - public UpdateRelationshipsBuilder update(UpdateRelationship updates) { - this.updates.add(updates); - return this; - } + Builder update(UpdateRelationship updates); - public UpdateRelationships build() { - return new UpdateRelationships(updates, preconditions); - } + UpdateRelationships build(); } } diff --git a/api/src/main/java/com/oviva/spicegen/api/internal/CheckPermissionImpl.java b/api/src/main/java/com/oviva/spicegen/api/internal/CheckPermissionImpl.java new file mode 100644 index 0000000..e5d92d4 --- /dev/null +++ b/api/src/main/java/com/oviva/spicegen/api/internal/CheckPermissionImpl.java @@ -0,0 +1,71 @@ +package com.oviva.spicegen.api.internal; + +import com.oviva.spicegen.api.CheckPermission; +import com.oviva.spicegen.api.Consistency; +import com.oviva.spicegen.api.ObjectRef; +import com.oviva.spicegen.api.SubjectRef; + +public record CheckPermissionImpl( + ObjectRef resource, String permission, SubjectRef subject, Consistency consistency) + implements CheckPermission { + + private CheckPermissionImpl(Builder builder) { + this(builder.resource, builder.permission, builder.subject, builder.consistency); + } + + public static Builder newBuilder() { + return new Builder(); + } + + public ObjectRef resource() { + return resource; + } + + public String permission() { + return permission; + } + + public SubjectRef subject() { + return subject; + } + + public Consistency consistency() { + return consistency; + } + + public static final class Builder implements CheckPermission.Builder { + private ObjectRef resource; + private String permission; + private SubjectRef subject; + private Consistency consistency = Consistency.fullyConsistent(); + + @Override + public Builder resource(ObjectRef resource) { + this.resource = resource; + return this; + } + + @Override + public Builder permission(String permission) { + this.permission = permission; + return this; + } + + @Override + public Builder subject(SubjectRef subject) { + this.subject = subject; + return this; + } + + @Override + public Builder consistency(Consistency consistency) { + this.consistency = consistency; + return this; + } + + @Override + public CheckPermission build() { + return new CheckPermissionImpl(this); + } + } +} diff --git a/api/src/main/java/com/oviva/spicegen/api/internal/ConsistencyImpl.java b/api/src/main/java/com/oviva/spicegen/api/internal/ConsistencyImpl.java new file mode 100644 index 0000000..3330dd8 --- /dev/null +++ b/api/src/main/java/com/oviva/spicegen/api/internal/ConsistencyImpl.java @@ -0,0 +1,14 @@ +package com.oviva.spicegen.api.internal; + +import com.oviva.spicegen.api.Consistency; + +public record ConsistencyImpl(Consistency.Requirement requirement, String consistencyToken) + implements Consistency { + + private static final ConsistencyImpl FULLY_CONSISTENT = + new ConsistencyImpl(Consistency.Requirement.FULLY_CONSISTENT, null); + + public static ConsistencyImpl fullyConsistent() { + return FULLY_CONSISTENT; + } +} diff --git a/api/src/main/java/com/oviva/spicegen/api/internal/PreconditionImpl.java b/api/src/main/java/com/oviva/spicegen/api/internal/PreconditionImpl.java new file mode 100644 index 0000000..fa045db --- /dev/null +++ b/api/src/main/java/com/oviva/spicegen/api/internal/PreconditionImpl.java @@ -0,0 +1,37 @@ +package com.oviva.spicegen.api.internal; + +import com.oviva.spicegen.api.Precondition; +import com.oviva.spicegen.api.RelationshipFilter; + +public record PreconditionImpl(Precondition.Condition condition, RelationshipFilter filter) + implements Precondition { + + private PreconditionImpl(Builder builder) { + this(builder.condition, builder.filter); + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static final class Builder implements Precondition.Builder { + private Precondition.Condition condition; + private RelationshipFilter filter; + + @Override + public Builder condition(Precondition.Condition val) { + condition = val; + return this; + } + + @Override + public Builder filter(RelationshipFilter val) { + filter = val; + return this; + } + + public PreconditionImpl build() { + return new PreconditionImpl(this); + } + } +} diff --git a/api/src/main/java/com/oviva/spicegen/api/internal/RelationshipFilterImpl.java b/api/src/main/java/com/oviva/spicegen/api/internal/RelationshipFilterImpl.java new file mode 100644 index 0000000..9bc5323 --- /dev/null +++ b/api/src/main/java/com/oviva/spicegen/api/internal/RelationshipFilterImpl.java @@ -0,0 +1,100 @@ +package com.oviva.spicegen.api.internal; + +import com.oviva.spicegen.api.RelationshipFilter; +import java.util.Optional; + +public record RelationshipFilterImpl( + String resourceKind, + Optional resourceId, + Optional relation, + Optional subjectFilter) + implements RelationshipFilter { + + private RelationshipFilterImpl(Builder builder) { + this( + builder.resourceKind, + Optional.ofNullable(builder.resourceId), + Optional.ofNullable(builder.relation), + Optional.ofNullable(builder.subjectFilter)); + } + + public String resourceKind() { + return resourceKind; + } + + public record SubjectFilterImpl( + String subjectKind, Optional subjectId, Optional relation) + implements SubjectFilter { + + private SubjectFilterImpl(Builder builder) { + this( + builder.subjectKind, + Optional.ofNullable(builder.subjectId), + Optional.ofNullable(builder.relation)); + } + + public String subjectKind() { + return subjectKind; + } + + public static final class Builder implements SubjectFilter.Builder { + private String subjectKind; + private String subjectId; + private String relation; + + public Builder subjectKind(String val) { + subjectKind = val; + return this; + } + + public Builder subjectId(String val) { + subjectId = val; + return this; + } + + public Builder relation(String val) { + relation = val; + return this; + } + + public SubjectFilterImpl build() { + return new SubjectFilterImpl(this); + } + } + } + + public static final class Builder implements RelationshipFilter.Builder { + private String resourceKind; + private String resourceId; + private String relation; + private SubjectFilter subjectFilter; + + @Override + public Builder resourceKind(String val) { + resourceKind = val; + return this; + } + + @Override + public Builder resourceId(String val) { + resourceId = val; + return this; + } + + @Override + public Builder relation(String val) { + relation = val; + return this; + } + + @Override + public Builder subjectFilter(SubjectFilter val) { + this.subjectFilter = val; + return this; + } + + public RelationshipFilterImpl build() { + return new RelationshipFilterImpl(this); + } + } +} diff --git a/api/src/main/java/com/oviva/spicegen/api/internal/UpdateRelationshipImpl.java b/api/src/main/java/com/oviva/spicegen/api/internal/UpdateRelationshipImpl.java new file mode 100644 index 0000000..1daf5bb --- /dev/null +++ b/api/src/main/java/com/oviva/spicegen/api/internal/UpdateRelationshipImpl.java @@ -0,0 +1,17 @@ +package com.oviva.spicegen.api.internal; + +import com.oviva.spicegen.api.ObjectRef; +import com.oviva.spicegen.api.SubjectRef; +import com.oviva.spicegen.api.UpdateRelationship; + +public record UpdateRelationshipImpl( + ObjectRef resource, String relation, SubjectRef subject, Operation operation) + implements UpdateRelationship { + @Override + public String toString() { + var res = resource != null ? resource.toString() : ""; + var rel = relation != null ? relation : ""; + var sub = subject != null ? subject.toString() : ""; + return operation.name() + "(" + res + "#" + rel + "@" + sub + ")"; + } +} diff --git a/api/src/main/java/com/oviva/spicegen/api/internal/UpdateRelationshipsImpl.java b/api/src/main/java/com/oviva/spicegen/api/internal/UpdateRelationshipsImpl.java new file mode 100644 index 0000000..0856a99 --- /dev/null +++ b/api/src/main/java/com/oviva/spicegen/api/internal/UpdateRelationshipsImpl.java @@ -0,0 +1,58 @@ +package com.oviva.spicegen.api.internal; + +import com.oviva.spicegen.api.Precondition; +import com.oviva.spicegen.api.UpdateRelationship; +import com.oviva.spicegen.api.UpdateRelationships; +import java.util.ArrayList; +import java.util.List; + +public record UpdateRelationshipsImpl( + List preconditions, List updates) + implements UpdateRelationships { + + public static Builder newBuilder() { + return new Builder(); + } + + public List updates() { + return updates; + } + + public List preconditions() { + return preconditions; + } + + public static final class Builder implements UpdateRelationships.Builder { + private List preconditions = new ArrayList<>(); + private List updates = new ArrayList<>(); + + @Override + public UpdateRelationships.Builder preconditions(List preconditions) { + this.preconditions = preconditions; + return this; + } + + @Override + public UpdateRelationships.Builder precondition(Precondition precondition) { + this.preconditions.add(precondition); + return this; + } + + @Override + public UpdateRelationships.Builder updates(List updates) { + this.updates = updates; + return this; + } + + @Override + public UpdateRelationships.Builder update(UpdateRelationship updates) { + this.updates.add(updates); + return this; + } + + @Override + public UpdateRelationships build() { + return new UpdateRelationshipsImpl(preconditions, updates); + } + } +} diff --git a/api/src/test/java/com/oviva/spicegen/api/UpdateRelationshipsTest.java b/api/src/test/java/com/oviva/spicegen/api/UpdateRelationshipsTest.java index 4633521..7346046 100644 --- a/api/src/test/java/com/oviva/spicegen/api/UpdateRelationshipsTest.java +++ b/api/src/test/java/com/oviva/spicegen/api/UpdateRelationshipsTest.java @@ -34,10 +34,7 @@ public void test_updateRelationshipsBuilder() { var preconditions = getPreconditionList(); var updateRelationships = - UpdateRelationships.UpdateRelationshipsBuilder.newBuilder() - .updates(updates) - .preconditions(preconditions) - .build(); + UpdateRelationships.newBuilder().updates(updates).preconditions(preconditions).build(); assertEquals(updateRelationships.updates(), updates); assertEquals(updateRelationships.preconditions(), preconditions); @@ -65,7 +62,7 @@ public void test_updateRelationshipsBuilder_withAddOperations() { var updateRelationship = UpdateRelationship.ofUpdate(resource, ADMINISTRATOR, subject); var updateRelationships = - UpdateRelationships.UpdateRelationshipsBuilder.newBuilder() + UpdateRelationships.newBuilder() .precondition(precondition) .update(updateRelationship) .build(); diff --git a/spicedb-binding/pom.xml b/spicedb-binding/pom.xml index 6ba783a..2d04dcf 100644 --- a/spicedb-binding/pom.xml +++ b/spicedb-binding/pom.xml @@ -64,6 +64,11 @@ testcontainers test + + org.testcontainers + postgresql + test + org.testcontainers junit-jupiter diff --git a/spicedb-binding/src/main/docker/compose.dev.yaml b/spicedb-binding/src/main/docker/compose.dev.yaml deleted file mode 100644 index 511ba25..0000000 --- a/spicedb-binding/src/main/docker/compose.dev.yaml +++ /dev/null @@ -1,43 +0,0 @@ -version: "3.9" -services: - spicedb: - image: quay.io/authzed/spicedb - ports: - - "127.0.0.1::8080" - - "127.0.0.1::50051" - - "127.0.0.1::9090" - command: - - 'serve' - - '--grpc-preshared-key=t0ken' - - '--datastore-engine=postgres' - - '--datastore-conn-uri=postgres://spicedb-pg:5432/spicedb?sslmode=disable&user=postgres&password=root' - depends_on: - spicedb-pg: - condition: service_healthy - spicedb-migrator: - condition: service_completed_successfully - spicedb-migrator: - image: quay.io/authzed/spicedb - command: - - 'migrate' - - 'head' - - '--datastore-engine' - - 'postgres' - - '--datastore-conn-uri' - - 'postgres://spicedb-pg:5432/spicedb?sslmode=disable&user=postgres&password=root' - depends_on: - spicedb-pg: - condition: service_healthy - spicedb-pg: - image: postgres:14 - ports: - - "127.0.0.1::5432" - environment: - POSTGRES_DB: 'spicedb' - POSTGRES_PASSWORD: 'root' - healthcheck: - test: "psql 'postgres://spicedb-pg:5432/spicedb?sslmode=disable&user=postgres&password=root' --quiet --output=/dev/null -c 'SELECT 1;'" - interval: 1s - timeout: 1s - retries: 3 - start_period: 10s \ No newline at end of file diff --git a/spicedb-binding/src/test/java/com/oviva/spicegen/spicedbbinding/SpiceDbPermissionServiceBuilderTest.java b/spicedb-binding/src/test/java/com/oviva/spicegen/spicedbbinding/SpiceDbPermissionServiceBuilderTest.java index 15fb96d..7b73709 100644 --- a/spicedb-binding/src/test/java/com/oviva/spicegen/spicedbbinding/SpiceDbPermissionServiceBuilderTest.java +++ b/spicedb-binding/src/test/java/com/oviva/spicegen/spicedbbinding/SpiceDbPermissionServiceBuilderTest.java @@ -1,6 +1,6 @@ package com.oviva.spicegen.spicedbbinding; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import com.authzed.api.v1.PermissionsServiceGrpc; import com.authzed.grpcutil.BearerToken; @@ -27,6 +27,6 @@ public void test_spiceDbPermissionServiceBuilder() { .permissionsBlockingStub(permissionsService) .build(); - assertTrue(svc instanceof PermissionService); + assertInstanceOf(PermissionService.class, svc); } } diff --git a/spicedb-binding/src/test/java/com/oviva/spicegen/spicedbbinding/internal/SpiceDbContractTestContextProvider.java b/spicedb-binding/src/test/java/com/oviva/spicegen/spicedbbinding/internal/SpiceDbContractTestContextProvider.java index 410dd83..6df6103 100644 --- a/spicedb-binding/src/test/java/com/oviva/spicegen/spicedbbinding/internal/SpiceDbContractTestContextProvider.java +++ b/spicedb-binding/src/test/java/com/oviva/spicegen/spicedbbinding/internal/SpiceDbContractTestContextProvider.java @@ -6,17 +6,23 @@ import com.oviva.spicegen.spicedbbinding.test.GenericTypedParameterResolver; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; -import java.io.File; +import java.time.Duration; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Stream; import org.junit.jupiter.api.extension.*; -import org.testcontainers.containers.DockerComposeContainer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.Network; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy; +import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; import org.testcontainers.utility.DockerImageName; public class SpiceDbContractTestContextProvider implements TestTemplateInvocationContextProvider { + private static Logger logger = LoggerFactory.getLogger(SpiceDbContractTestContextProvider.class); private static final String TOKEN = "t0ken"; private static final int GRPC_PORT = 50051; @@ -35,14 +41,10 @@ public Stream provideTestTemplateInvocationContex private TestTemplateInvocationContext inMemorySpiceDB() { var spicedb = - new GenericContainer<>(DockerImageName.parse("quay.io/authzed/spicedb:v1.32.0")) - .withCommand("serve", "--grpc-preshared-key", TOKEN) - .withExposedPorts( - GRPC_PORT, // grpc - 8080, // dashboard - 9090 // metrics - ); - + createSpicedbBaseContainer("serve", "--grpc-preshared-key", TOKEN) + .withExposedPorts(GRPC_PORT) + .waitingFor( + new LogMessageWaitStrategy().withRegEx(".*\"grpc server started serving\".*")); spicedb.start(); var host = spicedb.getHost(); @@ -61,22 +63,45 @@ private TestTemplateInvocationContext inMemorySpiceDB() { private TestTemplateInvocationContext postgresSpiceDB() { - var spiceDbServiceName = "spicedb_1"; - var environment = - new DockerComposeContainer<>(new File("src/main/docker/compose.dev.yaml")) - .withExposedService(spiceDbServiceName, GRPC_PORT); - - environment.start(); + var net = Network.newNetwork(); + + var migrator = + createSpicedbBaseContainer( + "migrate", + "head", + "--datastore-engine", + "postgres", + "--datastore-conn-uri", + "postgres://spicedb-pg:5432/spicedb?sslmode=disable&user=postgres&password=root") + .withStartupCheckStrategy( + new OneShotStartupCheckStrategy().withTimeout(Duration.ofSeconds(5))) + .withNetwork(net); + + var spicedb = createPostgeresSpicedbContainer(net); + + var db = + new PostgreSQLContainer<>(DockerImageName.parse("postgres").withTag("14")) + .withDatabaseName("spicedb") + .withPassword("root") + .withUsername("postgres") + .withNetworkAliases("spicedb-pg") + .withNetwork(net); + + db.start(); + migrator.start(); + spicedb.start(); - var host = environment.getServiceHost(spiceDbServiceName, GRPC_PORT); - var port = environment.getServicePort(spiceDbServiceName, GRPC_PORT); + var host = spicedb.getHost(); + var port = spicedb.getMappedPort(GRPC_PORT); var services = createServices(host, port); return createContext( "postgres backed SpiceDB", services, () -> { quitelyShutdown(services.channel()); - environment.stop(); + migrator.stop(); + spicedb.stop(); + db.stop(); }); } @@ -113,6 +138,29 @@ public List getAdditionalExtensions() { }; } + private GenericContainer createPostgeresSpicedbContainer(Network net) { + + return createSpicedbBaseContainer( + "serve", + "--grpc-preshared-key=%s".formatted(TOKEN), + "--datastore-engine=postgres", + "--datastore-conn-uri=postgres://spicedb-pg:5432/spicedb?sslmode=disable&user=postgres&password=root") + .waitingFor(new LogMessageWaitStrategy().withRegEx(".*\"grpc server started serving\".*")) + .withExposedPorts( + GRPC_PORT, // grpc + 8080, // dashboard + 9090 // metrics + ) + .withNetwork(net); + } + + private GenericContainer createSpicedbBaseContainer(String... args) { + + return new GenericContainer<>(DockerImageName.parse("quay.io/authzed/spicedb:v1.32.0")) + .withCommand(args) + .withLogConsumer(f -> logger.info("spicedb {}: {}", args[0], f.getUtf8String())); + } + public TestServices createServices(String host, int port) { var channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext().build();