diff --git a/space-client/src/main/java/io/github/pgmarc/space/contracts/AddOn.java b/space-client/src/main/java/io/github/pgmarc/space/contracts/AddOn.java index 0e54a89..3bebbc6 100644 --- a/space-client/src/main/java/io/github/pgmarc/space/contracts/AddOn.java +++ b/space-client/src/main/java/io/github/pgmarc/space/contracts/AddOn.java @@ -31,4 +31,12 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(name, quantity); } + + @Override + public String toString() { + return "AddOn{" + + "name='" + name + '\'' + + ", quantity=" + quantity + + '}'; + } } diff --git a/space-client/src/main/java/io/github/pgmarc/space/contracts/Service.java b/space-client/src/main/java/io/github/pgmarc/space/contracts/Service.java index 67697c3..04bd601 100644 --- a/space-client/src/main/java/io/github/pgmarc/space/contracts/Service.java +++ b/space-client/src/main/java/io/github/pgmarc/space/contracts/Service.java @@ -46,11 +46,6 @@ public static Builder builder(String name, String version) { return new Builder(name, version); } - @Override - public String toString() { - return name + ": " + version + " plan" + plan + " addOns " + addOns; - } - @Override public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; @@ -63,6 +58,16 @@ public int hashCode() { return Objects.hash(name, version, addOns, plan); } + @Override + public String toString() { + return "Service{" + + "name='" + name + '\'' + + ", version='" + version + '\'' + + ", addOns=" + addOns + + ", plan='" + plan + '\'' + + '}'; + } + public static final class Builder { private final String name; diff --git a/space-client/src/main/java/io/github/pgmarc/space/contracts/Subscription.java b/space-client/src/main/java/io/github/pgmarc/space/contracts/Subscription.java index 2796ac8..8dc2c34 100644 --- a/space-client/src/main/java/io/github/pgmarc/space/contracts/Subscription.java +++ b/space-client/src/main/java/io/github/pgmarc/space/contracts/Subscription.java @@ -1,15 +1,10 @@ package io.github.pgmarc.space.contracts; -import java.time.*; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; +import java.time.LocalDateTime; +import java.time.Period; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.*; import java.util.stream.Collectors; public final class Subscription { @@ -24,12 +19,12 @@ public final class Subscription { private Subscription(Builder builder) { this.userContact = builder.userContact; + this.services = builder.services; this.startDate = builder.startDate; this.endDate = builder.endDate; this.renewalPeriod = builder.renewalPeriod; - this.services = Collections.unmodifiableMap(builder.services); - this.history = Collections.unmodifiableList(builder.history); - this.usageLevels = Collections.unmodifiableMap(builder.usageLevels); + this.history = builder.history; + this.usageLevels = builder.usageLevels; } public static Builder builder(UserContact userContact, ZonedDateTime startDate, ZonedDateTime endDate, @@ -41,6 +36,14 @@ public static Builder builder(UserContact userContact, ZonedDateTime startDate, return new Builder(userContact, startDate, endDate).subscribeAll(services); } + public String getUserId() { + return userContact.getUserId(); + } + + public String getUsername() { + return userContact.getUsername(); + } + public LocalDateTime getStartDate() { return startDate.toLocalDateTime(); } @@ -58,7 +61,8 @@ public boolean isAutoRenewable() { } public Optional getRenewalDate() { - return Optional.ofNullable(isAutoRenewable() ? endDate.plus(renewalPeriod).toLocalDateTime() : null); + return Optional.ofNullable(renewalPeriod) + .map( renewalPeriod -> endDate.plus(renewalPeriod).toLocalDateTime()); } /** @@ -84,33 +88,52 @@ public boolean isExpired(LocalDateTime date) { return startDate.isBefore(utcDate) && endDate.isBefore(utcDate); } - - public String getUserId() { - return userContact.getUserId(); + public Map getServicesMap() { + return Collections.unmodifiableMap(services); } - public String getUsername() { - return userContact.getUsername(); + public Collection getServices() { + return Collections.unmodifiableCollection(services.values()); } public Optional getService(String serviceName) { return Optional.ofNullable(this.services.get(serviceName)); } - public Map getServicesMap() { - return services; + public List getHistory() { + return Collections.unmodifiableList(history); } - public Set getServices() { - return Set.copyOf(services.values()); + public Map> getUsageLevels() { + return Collections.unmodifiableMap(usageLevels); } - public List getHistory() { - return history; + public Optional> getServiceUsageLevels(String service) { + Objects.requireNonNull(service, "service name must not be null"); + return Optional.ofNullable(usageLevels.get(service)); } - public Map> getUsageLevels() { - return usageLevels; + public Optional getUsageLevel(String service, String usageLimit) { + Objects.requireNonNull(service, "service name must not be null"); + Objects.requireNonNull(usageLimit, "usage limit name must not be null"); + if (!usageLevels.containsKey(service)) { + return Optional.empty(); + } + return Optional.ofNullable(usageLevels.get(service).get(usageLimit)); + + } + + @Override + public String toString() { + return "Subscription{" + + "userContact=" + userContact + + ", services=" + services + + ", startDate=" + startDate + + ", endDate=" + endDate + + ", renewalPeriod=" + renewalPeriod + + ", history=" + history + + ", usageLevels=" + usageLevels + + '}'; } public enum Keys { @@ -256,5 +279,26 @@ public static Snapshot of(ZonedDateTime startDateTime, ZonedDateTime endDateTime Map services) { return new Snapshot(startDateTime, endDateTime, services); } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + Snapshot snapshot = (Snapshot) o; + return Objects.equals(starDateTime, snapshot.starDateTime) && Objects.equals(endDateTime, snapshot.endDateTime) && Objects.equals(services, snapshot.services); + } + + @Override + public int hashCode() { + return Objects.hash(starDateTime, endDateTime, services); + } + + @Override + public String toString() { + return "Snapshot{" + + "starDateTime=" + starDateTime + + ", endDateTime=" + endDateTime + + ", services=" + services + + '}'; + } } } diff --git a/space-client/src/main/java/io/github/pgmarc/space/contracts/SubscriptionRequest.java b/space-client/src/main/java/io/github/pgmarc/space/contracts/SubscriptionRequest.java index b4ad24a..2bf56e1 100644 --- a/space-client/src/main/java/io/github/pgmarc/space/contracts/SubscriptionRequest.java +++ b/space-client/src/main/java/io/github/pgmarc/space/contracts/SubscriptionRequest.java @@ -1,6 +1,6 @@ package io.github.pgmarc.space.contracts; -import java.time.Duration; +import java.time.Period; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -11,12 +11,12 @@ public final class SubscriptionRequest { private final UserContact userContact; private final Set services; - private final Duration renewalDays; + private final Period renewalPeriod; private SubscriptionRequest(Builder builder) { this.userContact = builder.userContact; - this.renewalDays = builder.renewalDays; - this.services = Collections.unmodifiableSet(builder.services); + this.renewalPeriod = builder.renewalPeriod; + this.services = builder.services; } public static Builder builder(UserContact userContact) { @@ -27,12 +27,12 @@ public UserContact getUserContact() { return userContact; } - public Set getServices() { - return services; + public Collection getServices() { + return Collections.unmodifiableCollection(services); } - public Duration getRenewalDays() { - return renewalDays; + public Period getRenewalPeriod() { + return renewalPeriod; } public static final class Builder { @@ -40,7 +40,7 @@ public static final class Builder { private final UserContact userContact; private final Set services = new HashSet<>(); private Service.Builder serviceBuilder; - private Duration renewalDays; + private Period renewalPeriod; private Builder(UserContact userContact) { this.userContact = userContact; @@ -53,12 +53,18 @@ public Builder subscribe(Service service) { public Builder subscribeAll(Collection services) { Objects.requireNonNull(services, "services must not be null"); + if (services.isEmpty()) { + throw new IllegalArgumentException("services must not be empty"); + } this.services.addAll(services); return this; } - public Builder renewIn(Duration renewalDays) { - this.renewalDays = renewalDays; + public Builder renewInDays(int days) { + if (days < 1) { + throw new IllegalArgumentException("renewal period given in days must be positive"); + } + this.renewalPeriod = Period.ofDays(days); return this; } diff --git a/space-client/src/main/java/io/github/pgmarc/space/contracts/UsageLevel.java b/space-client/src/main/java/io/github/pgmarc/space/contracts/UsageLevel.java index b980b43..10b43de 100644 --- a/space-client/src/main/java/io/github/pgmarc/space/contracts/UsageLevel.java +++ b/space-client/src/main/java/io/github/pgmarc/space/contracts/UsageLevel.java @@ -38,7 +38,7 @@ public String getName() { } public Optional getResetTimestamp() { - return resetTimestamp != null ? Optional.of(resetTimestamp.toLocalDateTime()) : Optional.empty(); + return Optional.ofNullable(resetTimestamp).map(ZonedDateTime::toLocalDateTime); } public boolean isRenewableUsageLimit() { @@ -51,8 +51,8 @@ public double getConsumption() { private static void validateUsageLevel(String name, double consumed) { Objects.requireNonNull(name, "usage limit name must not be null"); - if (consumed <= 0) { - throw new IllegalArgumentException("consumption must be greater than 0"); + if (consumed < 0) { + throw new IllegalArgumentException("usage level consumption must be positive"); } } @@ -76,4 +76,13 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(name, consumed, resetTimestamp); } + + @Override + public String toString() { + return "UsageLevel{" + + "name='" + name + '\'' + + ", consumed=" + consumed + + ", resetTimestamp=" + resetTimestamp + + '}'; + } } diff --git a/space-client/src/main/java/io/github/pgmarc/space/contracts/UserContact.java b/space-client/src/main/java/io/github/pgmarc/space/contracts/UserContact.java index 95f17b3..a19a344 100644 --- a/space-client/src/main/java/io/github/pgmarc/space/contracts/UserContact.java +++ b/space-client/src/main/java/io/github/pgmarc/space/contracts/UserContact.java @@ -21,12 +21,6 @@ private UserContact(Builder builder) { this.phone = builder.phone; } - public static Builder builder(String userId, String username) { - Objects.requireNonNull(userId, "userId must not be null"); - Objects.requireNonNull(username, "username must not be null"); - return new Builder(userId, username); - } - public String getUserId() { return userId; } @@ -51,35 +45,34 @@ public Optional getPhone() { return Optional.ofNullable(phone); } + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + UserContact that = (UserContact) o; + return Objects.equals(userId, that.userId) && Objects.equals(username, that.username); + } + @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((userId == null) ? 0 : userId.hashCode()); - result = prime * result + ((username == null) ? 0 : username.hashCode()); - return result; + return Objects.hash(userId, username); } @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - UserContact other = (UserContact) obj; - if (userId == null) { - if (other.userId != null) - return false; - } else if (!userId.equals(other.userId)) - return false; - if (username == null) { - if (other.username != null) - return false; - } else if (!username.equals(other.username)) - return false; - return true; + public String toString() { + return "UserContact{" + + "userId='" + userId + '\'' + + ", username='" + username + '\'' + + ", firstName='" + firstName + '\'' + + ", lastName='" + lastName + '\'' + + ", email='" + email + '\'' + + ", phone='" + phone + '\'' + + '}'; + } + + public static Builder builder(String userId, String username) { + Objects.requireNonNull(userId, "userId must not be null"); + Objects.requireNonNull(username, "username must not be null"); + return new Builder(userId, username); } public static class Builder { @@ -145,7 +138,7 @@ public enum Keys { private final String name; - private Keys(String name) { + Keys(String name) { this.name = name; } diff --git a/space-client/src/main/java/io/github/pgmarc/space/features/FeatureEvaluationResult.java b/space-client/src/main/java/io/github/pgmarc/space/features/FeatureEvaluationResult.java index 9f95e27..13afac7 100644 --- a/space-client/src/main/java/io/github/pgmarc/space/features/FeatureEvaluationResult.java +++ b/space-client/src/main/java/io/github/pgmarc/space/features/FeatureEvaluationResult.java @@ -39,6 +39,14 @@ public static FeatureEvaluationResult of(boolean available, Map qu return new FeatureEvaluationResult(available, quotas); } + @Override + public String toString() { + return "FeatureEvaluationResult{" + + "available=" + available + + ", quotas=" + quotas + + '}'; + } + public static final class Usage { private final Number used; @@ -60,6 +68,14 @@ public Number getLimit() { public static Usage of(Number used, Number limit) { return new Usage(used, limit); } + + @Override + public String toString() { + return "Usage{" + + "used=" + used + + ", limit=" + limit + + '}'; + } } } diff --git a/space-client/src/main/java/io/github/pgmarc/space/serializers/SubscriptionRequestSerializer.java b/space-client/src/main/java/io/github/pgmarc/space/serializers/SubscriptionRequestSerializer.java index 1d71f71..8c957b8 100644 --- a/space-client/src/main/java/io/github/pgmarc/space/serializers/SubscriptionRequestSerializer.java +++ b/space-client/src/main/java/io/github/pgmarc/space/serializers/SubscriptionRequestSerializer.java @@ -1,5 +1,6 @@ package io.github.pgmarc.space.serializers; +import java.time.temporal.ChronoUnit; import java.util.*; import org.json.JSONObject; @@ -18,14 +19,14 @@ public JSONObject toJson(SubscriptionRequest object) { JSONObject json = new JSONObject() .put(Subscription.Keys.USER_CONTACT.toString(), userContact(object.getUserContact())) .put(Subscription.Keys.BILLING_PERIOD.toString(), - Map.of("autoRenew", object.getRenewalDays() != null)) + Map.of("autoRenew", object.getRenewalPeriod() != null)) .put(Subscription.Keys.CONTRACTED_SERVICES.toString(), contractedServices(object.getServices())) .put(Subscription.Keys.SUBSCRIPTION_PLANS.toString(), subscriptionPlans(object.getServices())) .put(Subscription.Keys.SUBSCRIPTION_ADDONS.toString(), subscriptionAddOns(object.getServices())); - if (object.getRenewalDays() != null) { + if (object.getRenewalPeriod() != null) { json.getJSONObject(Subscription.Keys.BILLING_PERIOD.toString()) - .put("renewalDays", object.getRenewalDays().toDays()); + .put("renewalDays", object.getRenewalPeriod().getDays()); } return json; @@ -42,7 +43,7 @@ public Map userContact(UserContact userContact) { return res; } - public static Map contractedServices(Set services) { + public static Map contractedServices(Collection services) { Map res = new HashMap<>(); for (Service service : services) { res.put(service.getName(), service.getVersion()); @@ -50,7 +51,7 @@ public static Map contractedServices(Set services) { return Collections.unmodifiableMap(res); } - public static Map subscriptionPlans(Set services) { + public static Map subscriptionPlans(Collection services) { Map res = new HashMap<>(); for (Service service : services) { Optional plan = service.getPlan(); @@ -63,7 +64,7 @@ public static Map subscriptionPlans(Set services) { } - public static Map> subscriptionAddOns(Set services) { + public static Map> subscriptionAddOns(Collection services) { Map> res = new HashMap<>(); diff --git a/space-client/src/test/java/io/github/pgmarc/space/ContractsEndpointTest.java b/space-client/src/test/java/io/github/pgmarc/space/ContractsEndpointTest.java index 5183632..004f17c 100644 --- a/space-client/src/test/java/io/github/pgmarc/space/ContractsEndpointTest.java +++ b/space-client/src/test/java/io/github/pgmarc/space/ContractsEndpointTest.java @@ -68,7 +68,7 @@ void givenASubscriptionShouldBeCreated() { .build(); SubscriptionRequest subReq = SubscriptionRequest.builder(userContact) - .renewIn(Duration.ofDays(45)) + .renewInDays(renewalDays) .startService("zoom", "2025") .plan("ENTERPRISE") .addOn("extraSeats", 2) @@ -84,9 +84,9 @@ void givenASubscriptionShouldBeCreated() { Subscription subscription; try { subscription = endpoint.addContract(subReq); - assertThat(subscription.getServices()).isEqualTo(subReq.getServices()); + assertThat(subscription.getServices()).containsAll(subReq.getServices()); assertThat(subscription.getUserId()).isEqualTo(userId); - assertThat(subscription.getRenewalPeriod()).hasValue(Period.ofDays(45)); + assertThat(subscription.getRenewalPeriod()).hasValue(Period.ofDays(renewalDays)); assertThat(subscription.getHistory()).isEmpty(); } catch (IOException e) { fail(); diff --git a/space-client/src/test/java/io/github/pgmarc/space/FeaturesEndpointTest.java b/space-client/src/test/java/io/github/pgmarc/space/FeaturesEndpointTest.java index b2a50e8..0c93455 100644 --- a/space-client/src/test/java/io/github/pgmarc/space/FeaturesEndpointTest.java +++ b/space-client/src/test/java/io/github/pgmarc/space/FeaturesEndpointTest.java @@ -2,9 +2,9 @@ import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; import com.github.tomakehurst.wiremock.junit5.WireMockTest; +import io.github.pgmarc.space.features.FeatureEvaluationResult; import io.github.pgmarc.space.features.Revert; import io.github.pgmarc.space.features.UsageLimitConsumption; -import io.github.pgmarc.space.features.FeatureEvaluationResult; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import org.junit.jupiter.api.BeforeAll; @@ -13,8 +13,8 @@ import java.io.IOException; import static com.github.tomakehurst.wiremock.client.WireMock.*; - -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; @WireMockTest class FeaturesEndpointTest { @@ -149,7 +149,7 @@ void getPricingTokenByUserId() { ok().withBodyFile("pricing-token-response.json"))); try { - assertThat(endpoint.generatePricingTokenForUser(userId).length()).isEqualTo(879); + assertThat(endpoint.generatePricingTokenForUser(userId)).hasSize(879); } catch (IOException e) { fail(); } diff --git a/space-client/src/test/java/io/github/pgmarc/space/contracts/SubscriptionRequestTest.java b/space-client/src/test/java/io/github/pgmarc/space/contracts/SubscriptionRequestTest.java index 2f29fdc..1700a93 100644 --- a/space-client/src/test/java/io/github/pgmarc/space/contracts/SubscriptionRequestTest.java +++ b/space-client/src/test/java/io/github/pgmarc/space/contracts/SubscriptionRequestTest.java @@ -2,10 +2,11 @@ import static org.assertj.core.api.Assertions.*; -import java.time.Duration; import org.junit.jupiter.api.Test; +import java.util.Set; + class SubscriptionRequestTest { private static final UserContact TEST_USER_CONTACT = UserContact.builder("123456789", "alexdoe") @@ -14,7 +15,7 @@ class SubscriptionRequestTest { @Test void givenMultipleServicesInSubscriptionShouldCreate() { - long renewalDays = 30; + int renewalDays = 30; String service1Name = "Petclinic"; String service2Name = "Petclinic Labs"; @@ -25,12 +26,33 @@ void givenMultipleServicesInSubscriptionShouldCreate() { .builder(TEST_USER_CONTACT) .subscribe(service1) .subscribe(service2) - .renewIn(Duration.ofDays(renewalDays)) + .renewInDays(renewalDays) .build(); assertThat(sub.getServices()).contains(service1, service2); } + @Test + void givenNegativeRenewalDaysShouldThrow() { + SubscriptionRequest.Builder builder = SubscriptionRequest + .builder(TEST_USER_CONTACT); + Set emptyServices = Set.of(); + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> builder.renewInDays(0)) + .withMessage("renewal period given in days must be positive"); + + } + + @Test + void givenEmptyCollectionOfAddOnsShouldThrow() { + SubscriptionRequest.Builder builder = SubscriptionRequest + .builder(TEST_USER_CONTACT); + Set emptyServices = Set.of(); + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> builder.subscribeAll(emptyServices)) + .withMessage("services must not be empty"); + } + @Test void givenConsecutiveServiceCreationShouldThrow() { @@ -89,11 +111,10 @@ void whenNoRequiredParametersInputShouldThrow() { void givenOptionalRenewalDaysShouldNotThrow() { SubscriptionRequest subReq = SubscriptionRequest.builder(TEST_USER_CONTACT) - .renewIn(null) .startService("foo", "bar").plan("baz") .endService().build(); - assertThat(subReq.getRenewalDays()).isNull(); + assertThat(subReq.getRenewalPeriod()).isNull(); } @@ -101,7 +122,6 @@ void givenOptionalRenewalDaysShouldNotThrow() { void givenNoEndServiceShouldThrow() { SubscriptionRequest.Builder builder = SubscriptionRequest.builder(TEST_USER_CONTACT) - .renewIn(null) .startService("foo", "bar").plan("baz"); assertThatExceptionOfType(IllegalStateException.class) diff --git a/space-client/src/test/java/io/github/pgmarc/space/contracts/SubscriptionTest.java b/space-client/src/test/java/io/github/pgmarc/space/contracts/SubscriptionTest.java index 95bb911..2e78487 100644 --- a/space-client/src/test/java/io/github/pgmarc/space/contracts/SubscriptionTest.java +++ b/space-client/src/test/java/io/github/pgmarc/space/contracts/SubscriptionTest.java @@ -44,7 +44,8 @@ void givenSubscriptionShould() { Subscription subscription = Subscription.builder(contact, start, end, service) .renewInDays(renewalDays) - .addSnapshots(history).build(); + .addSnapshots(history) + .build(); assertThat(subscription.getUsername()).isEqualTo(username); assertThat(subscription.getStartDate()).isEqualTo(start.toLocalDateTime()); @@ -60,6 +61,69 @@ void givenSubscriptionShould() { assertThat(subscription.getHistory().get(0).getService(serviceName)).hasValue(snapshotService); } + @Test + void givenUsageLevelsShouldCreateSubscription() { + + String petclinic = "petclinic"; + String maxPets = "maxPets"; + double registeredPets = 3; + UsageLevel ulMaxPets = UsageLevel.of(maxPets, registeredPets); + + String petclinicAI = "petclinic-ai"; + String maxTokens = "maxTokens"; + ZonedDateTime reset = ZonedDateTime.parse("2025-02-01T00:00:00Z"); + UsageLevel ulMaxTokens = UsageLevel.of(maxTokens, 20, reset); + Map> usageLevels = + Map.of(petclinic, Map.of(maxPets, ulMaxPets), + petclinicAI, Map.of(maxTokens,ulMaxTokens)); + Subscription subscription = Subscription.builder(TEST_CONTACT, START, END, TEST_SERVICE) + .addUsageLevels(usageLevels) + .build(); + + assertThat(subscription.getServiceUsageLevels(petclinic)).isNotEmpty(); + assertThat(subscription.getUsageLevel(petclinic, maxPets)).hasValue(ulMaxPets); + } + + @Test + void givenNullServiceShouldBeEmptyServiceUsageLevels() { + + String petclinic = "petclinic"; + String maxPets = "maxPets"; + double registeredPets = 3; + UsageLevel ulMaxPets = UsageLevel.of(maxPets, registeredPets); + + Map> usageLevels = Map.of(petclinic, Map.of(maxPets, ulMaxPets)); + Subscription subscription = Subscription.builder(TEST_CONTACT, START, END, TEST_SERVICE) + .addUsageLevels(usageLevels) + .build(); + + assertThatExceptionOfType(NullPointerException.class) + .isThrownBy(() -> subscription.getServiceUsageLevels(null)) + .withMessage("service name must not be null"); + } + + @Test + void givenNullUsageLimitShouldBeEmptyUsageLevel() { + + String petclinic = "petclinic"; + String maxPets = "maxPets"; + double registeredPets = 3; + UsageLevel ulMaxPets = UsageLevel.of(maxPets, registeredPets); + + Map> usageLevels = Map.of(petclinic, Map.of(maxPets, ulMaxPets)); + Subscription subscription = Subscription.builder(TEST_CONTACT, START, END, TEST_SERVICE) + .addUsageLevels(usageLevels) + .build(); + + assertThatExceptionOfType(NullPointerException.class) + .isThrownBy(() -> subscription.getUsageLevel(null, maxPets)) + .withMessage("service name must not be null"); + + assertThatExceptionOfType(NullPointerException.class) + .isThrownBy(() -> subscription.getUsageLevel(petclinic, null)) + .withMessage("usage limit name must not be null"); + } + @Test void givenRenewalPeriodInDaysShouldCreate() { diff --git a/space-client/src/test/java/io/github/pgmarc/space/contracts/SubscriptionUpdateRequestTest.java b/space-client/src/test/java/io/github/pgmarc/space/contracts/SubscriptionUpdateRequestTest.java index 1aee6ca..0ba58ce 100644 --- a/space-client/src/test/java/io/github/pgmarc/space/contracts/SubscriptionUpdateRequestTest.java +++ b/space-client/src/test/java/io/github/pgmarc/space/contracts/SubscriptionUpdateRequestTest.java @@ -2,6 +2,7 @@ import org.junit.jupiter.api.Test; +import java.util.Collection; import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; @@ -70,9 +71,11 @@ void givenServiceCollectionShouldCreate() { @Test void givenEmptyCollectionOfServicesShouldThrow() { - SubscriptionUpdateRequest.Builder builder = SubscriptionUpdateRequest.builder(); + Collection emptyServices = Set.of(); + SubscriptionUpdateRequest.Builder builder = SubscriptionUpdateRequest + .builder(); assertThatExceptionOfType(IllegalArgumentException.class) - .isThrownBy(() -> builder.subscribeAll(Set.of())) + .isThrownBy(() -> builder.subscribeAll(emptyServices)) .withMessage("services must not be empty"); } } diff --git a/space-client/src/test/java/io/github/pgmarc/space/contracts/UsageLevelTest.java b/space-client/src/test/java/io/github/pgmarc/space/contracts/UsageLevelTest.java index 4a2ebc5..70c5331 100644 --- a/space-client/src/test/java/io/github/pgmarc/space/contracts/UsageLevelTest.java +++ b/space-client/src/test/java/io/github/pgmarc/space/contracts/UsageLevelTest.java @@ -1,14 +1,13 @@ package io.github.pgmarc.space.contracts; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; import java.time.ZonedDateTime; -import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.junit.jupiter.api.Assertions.assertAll; + class UsageLevelTest { @@ -16,39 +15,38 @@ class UsageLevelTest { void givenNonRenewableUsageLimitShouldCreate() { String usageLimitName = "maxPets"; - double consumption = 5; + double consumption = 0; UsageLevel usageLevel = UsageLevel.of(usageLimitName, consumption); assertAll( - () -> assertEquals(usageLimitName, usageLevel.getName()), - () -> assertEquals(consumption, usageLevel.getConsumption()), - () -> assertFalse(usageLevel.isRenewableUsageLimit())); + () -> assertThat(usageLevel.getName()).isEqualTo(usageLimitName), + () -> assertThat(usageLevel.getConsumption()).isEqualTo(consumption), + () -> assertThat(usageLevel.isRenewableUsageLimit()).isFalse()); } @Test - void givenInvalidParamertersShouldThrow() { + void givenNullUsageLimitNameShouldThrow() { - String usageLimitName = "maxPets"; - double consumption = 5; + assertThatExceptionOfType(NullPointerException.class) + .isThrownBy(() -> UsageLevel.of(null, 5)) + .withMessage("usage limit name must not be null"); + } - assertAll( - () -> assertThrows(NullPointerException.class, () -> UsageLevel.of(null, consumption)), - () -> assertThrows(IllegalArgumentException.class, () -> UsageLevel.of(usageLimitName, -1))); + @Test + void givenNegativeConsumptionShouldThrow() { + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> UsageLevel.of("maxPets", -1)) + .withMessage("usage level consumption must be positive"); } @Test void givenRenewableUsageLimitShouldCreate() { - String usageLimitName = "maxTokens"; - double consumption = 300; ZonedDateTime resetTimestamp = ZonedDateTime.parse("2025-08-19T00:00:00Z"); - UsageLevel usageLevel = UsageLevel.of(usageLimitName, consumption, resetTimestamp); + UsageLevel usageLevel = UsageLevel.of("maxTokens", 300, resetTimestamp); - assertAll( - () -> assertEquals(usageLimitName, usageLevel.getName()), - () -> assertEquals(consumption, usageLevel.getConsumption()), - () -> assertEquals(resetTimestamp.toLocalDateTime(), usageLevel.getResetTimestamp().get()), - () -> assertTrue(usageLevel.isRenewableUsageLimit())); + assertThat(usageLevel.getResetTimestamp()).hasValue(resetTimestamp.toLocalDateTime()); + assertThat(usageLevel.isRenewableUsageLimit()).isTrue(); } } diff --git a/space-client/src/test/java/io/github/pgmarc/space/serializers/SubscriptionRequestSerializerTest.java b/space-client/src/test/java/io/github/pgmarc/space/serializers/SubscriptionRequestSerializerTest.java index a633a19..f4c97f8 100644 --- a/space-client/src/test/java/io/github/pgmarc/space/serializers/SubscriptionRequestSerializerTest.java +++ b/space-client/src/test/java/io/github/pgmarc/space/serializers/SubscriptionRequestSerializerTest.java @@ -1,63 +1,66 @@ package io.github.pgmarc.space.serializers; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.time.Duration; -import java.util.Set; - -import org.json.JSONObject; -import org.junit.jupiter.api.Test; - import io.github.pgmarc.space.contracts.Subscription; import io.github.pgmarc.space.contracts.SubscriptionRequest; import io.github.pgmarc.space.contracts.UserContact; +import org.json.JSONObject; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; class SubscriptionRequestSerializerTest { @Test void givenSubscriptionRequestShouldSerialize() { - UserContact userContact = UserContact.builder("01c36d29-0d6a-4b41-83e9-8c6d9310c508", "johndoe") - .firstName("John") - .lastName("Doe") - .email("john.doe@my-domain.com") - .phone("+34 666 666 666") - .build(); + UserContact userContact = UserContact + .builder("01c36d29-0d6a-4b41-83e9-8c6d9310c508", "johndoe") + .firstName("John") + .lastName("Doe") + .email("john.doe@my-domain.com") + .phone("+34 666 666 666") + .build(); - String zoom = "zoom"; String petclinic = "petclinic"; + String petsAdoptionCentre = "petsAdoptionCentre"; + String petclinicVersion = "2024"; + String petclinicPlan = "GOLD"; + String zoom = "zoom"; + String zoomVersion = "2025"; + String zoomPlan = "ENTERPRISE"; + String hugeMeetings = "hugeMeetings"; + String extraSeats = "extraSeats"; + int renewalDays = 365; SubscriptionRequest subReq = SubscriptionRequest.builder(userContact) - .renewIn(Duration.ofDays(365)) - .startService(zoom, "2025") - .plan("ENTERPRISE") - .addOn("extraSeats", 2) - .addOn("hugeMeetings", 1) - .endService() - .startService("petclinic", "2024") - .plan("GOLD") - .addOn("petsAdoptionCentre", 1) - .endService() - .build(); + .renewInDays(renewalDays) + .startService(zoom, zoomVersion) + .plan(zoomPlan) + .addOn(extraSeats, 2) + .addOn(hugeMeetings, 1) + .endService() + .startService(petclinic, petclinicVersion) + .plan(petclinicPlan) + .addOn(petsAdoptionCentre, 1) + .endService() + .build(); SubscriptionRequestSerializer serializer = new SubscriptionRequestSerializer(); JSONObject actual = serializer.toJson(subReq); - Set serviceKeys = Set.of(zoom, petclinic); - Set addOnZoomKeys = Set.of("hugeMeetings", "extraSeats"); - Set addOnPetclinicKeys = Set.of( "petsAdoptionCentre"); - - Set actualZoomAddOnKeys = actual.getJSONObject(Subscription.Keys.SUBSCRIPTION_ADDONS.toString()).getJSONObject(zoom).keySet(); - Set actualPetclinicAddOnKeys = actual.getJSONObject(Subscription.Keys.SUBSCRIPTION_ADDONS.toString()).getJSONObject(petclinic).keySet(); - - assertAll( - () -> assertEquals(serviceKeys, - actual.getJSONObject(Subscription.Keys.CONTRACTED_SERVICES.toString()).keySet()), - () -> assertEquals(serviceKeys, actual.getJSONObject(Subscription.Keys.SUBSCRIPTION_PLANS.toString()).keySet()), - () -> assertEquals(serviceKeys, actual.getJSONObject(Subscription.Keys.SUBSCRIPTION_ADDONS.toString()).keySet()), - () -> assertEquals(addOnZoomKeys, actualZoomAddOnKeys), - () -> assertEquals(addOnPetclinicKeys, actualPetclinicAddOnKeys)); + JSONObject contractedServices = actual.getJSONObject(Subscription.Keys.CONTRACTED_SERVICES.toString()); + JSONObject subscriptionPlans = actual.getJSONObject(Subscription.Keys.SUBSCRIPTION_PLANS.toString()); + JSONObject subscriptionAddOns = actual.getJSONObject(Subscription.Keys.SUBSCRIPTION_ADDONS.toString()); + int actualRenewal = actual.getJSONObject(Subscription.Keys.BILLING_PERIOD.toString()) + .getInt("renewalDays"); + boolean actualAutoRenew = actual.getJSONObject(Subscription.Keys.BILLING_PERIOD.toString()).getBoolean("autoRenew"); + assertThat(actualRenewal).isEqualTo(renewalDays); + assertThat(actualAutoRenew).isTrue(); + assertThat(contractedServices.keySet()).contains(zoom, petclinic); + assertThat(subscriptionPlans.getString(zoom)).isEqualTo(zoomPlan); + assertThat(subscriptionPlans.getString(petclinic)).isEqualTo(petclinicPlan); + assertThat(subscriptionAddOns.getJSONObject(zoom).keySet()).contains(hugeMeetings, extraSeats); + assertThat(subscriptionAddOns.getJSONObject(petclinic).keySet()).contains(petsAdoptionCentre); } }