Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DE-572] Tests for listing and creating Product(s) Price Points #37

Merged
merged 3 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package com.maxio.advancedbilling.controllers.productpricepoints;

import com.maxio.advancedbilling.AdvancedBillingClient;
import com.maxio.advancedbilling.TestClient;
import com.maxio.advancedbilling.controllers.ProductPricePointsController;
import com.maxio.advancedbilling.controllers.ProductsController;
import com.maxio.advancedbilling.exceptions.ApiException;
import com.maxio.advancedbilling.models.CreateOrUpdateProduct;
import com.maxio.advancedbilling.models.CreateOrUpdateProductRequest;
import com.maxio.advancedbilling.models.CreateProductFamily;
import com.maxio.advancedbilling.models.CreateProductFamilyRequest;
import com.maxio.advancedbilling.models.CreateProductPricePoint;
import com.maxio.advancedbilling.models.CreateProductPricePointRequest;
import com.maxio.advancedbilling.models.IntervalUnit;
import com.maxio.advancedbilling.models.ListAllProductPricePointsInput;
import com.maxio.advancedbilling.models.ListProductsInput;
import com.maxio.advancedbilling.models.PricePointType;
import com.maxio.advancedbilling.models.Product;
import com.maxio.advancedbilling.models.ProductFamily;
import com.maxio.advancedbilling.models.ProductPricePoint;
import com.maxio.advancedbilling.models.ProductPricePointResponse;
import com.maxio.advancedbilling.models.ProductResponse;
import org.junit.jupiter.api.BeforeAll;

import java.io.IOException;
import java.util.EnumSet;
import java.util.List;

import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
import static org.apache.commons.lang3.RandomStringUtils.randomNumeric;
import static org.junit.jupiter.api.Assertions.fail;

abstract class ProductPricePointsBaseTest {

protected static final AdvancedBillingClient ADVANCED_BILLING_CLIENT = TestClient.createClient();
protected static final ProductsController PRODUCTS_CONTROLLER = ADVANCED_BILLING_CLIENT.getProductsController();
protected static final ProductPricePointsController PRODUCT_PRICE_POINTS_CONTROLLER = ADVANCED_BILLING_CLIENT.getProductPricePointsController();

protected static ProductFamily productFamily;

@BeforeAll
static void setupProductFamily() throws IOException, ApiException {
productFamily = ADVANCED_BILLING_CLIENT
.getProductFamiliesController()
.createProductFamily(new CreateProductFamilyRequest.Builder(
new CreateProductFamily.Builder()
.name("Test Product Family %s".formatted(randomAlphabetic(5)))
.build()
).build()
)
.getProductFamily();
}

protected static Product createProduct() throws IOException, ApiException {
return PRODUCTS_CONTROLLER
.createProduct(
productFamily.getId(),
new CreateOrUpdateProductRequest(new CreateOrUpdateProduct.Builder()
.name("product-name-%s".formatted(randomNumeric(5)))
.handle("product-handle-%s".formatted(randomNumeric(5)))
.intervalUnit(IntervalUnit.MONTH)
.interval(2)
.build()
)
)
.getProduct();
}

protected static ProductPricePointResponse createProductPricePoint(int productId, CreateProductPricePoint createProductPricePoint)
throws IOException, ApiException {
return createProductPricePointWithDelay(0, productId, createProductPricePoint);
}

protected static ProductPricePointResponse createProductPricePointWithDelay(long delayInMillis, int productId,
CreateProductPricePoint createProductPricePoint)
throws IOException, ApiException {
try {
Thread.sleep(delayInMillis);
} catch (InterruptedException e) {
fail(e.getMessage(), e);
}

return PRODUCT_PRICE_POINTS_CONTROLLER
.createProductPricePoint(productId, new CreateProductPricePointRequest(createProductPricePoint));
}

protected static CreateProductPricePoint.Builder defaultBuilder() {
return new CreateProductPricePoint.Builder()
.priceInCents(100L)
.interval(2)
.intervalUnit(IntervalUnit.MONTH)
.trialPriceInCents(4900L)
.trialInterval(1)
.trialIntervalUnit(IntervalUnit.MONTH)
.trialType("payment_expected")
.initialChargeInCents(120000L)
.initialChargeAfterTrial(false)
.expirationInterval(12)
.expirationIntervalUnit(IntervalUnit.MONTH);
}

// when archiving default price point, {"errors":["Cannot archive the default price point."]} is returned
protected static void archiveAllSitePricePointsExcludingDefault() throws IOException, ApiException {
List<ProductPricePoint> sitePricePointsExcludingDefault = listAllSitePricePointsPerPage200ExcludingDefault();
while (!sitePricePointsExcludingDefault.isEmpty()) {
for (ProductPricePoint pricePoint : sitePricePointsExcludingDefault) {
PRODUCT_PRICE_POINTS_CONTROLLER.archiveProductPricePoint(
pricePoint.getProductId(),
pricePoint.getId()
);
}
sitePricePointsExcludingDefault = listAllSitePricePointsPerPage200ExcludingDefault();
}
}

protected static void archiveAllSiteProducts() throws IOException, ApiException {
List<ProductResponse> productResponses = listAllSiteProductsPerPage200();
while (!productResponses.isEmpty()) {
for (ProductResponse p : productResponses) {
PRODUCTS_CONTROLLER.archiveProduct(p.getProduct().getId());
}
productResponses = listAllSiteProductsPerPage200();
}
}

protected static List<PricePointType> pricePointTypesExcludingDefault() {
return EnumSet.complementOf(EnumSet.of(PricePointType.ENUM_DEFAULT)).stream().toList();
}

private static List<ProductResponse> listAllSiteProductsPerPage200() throws IOException, ApiException {
return PRODUCTS_CONTROLLER.listProducts(
new ListProductsInput.Builder().perPage(200).build()
);
}

private static List<ProductPricePoint> listAllSitePricePointsPerPage200ExcludingDefault() throws IOException, ApiException {
return PRODUCT_PRICE_POINTS_CONTROLLER
.listAllProductPricePoints(new ListAllProductPricePointsInput.Builder()
.filterType(pricePointTypesExcludingDefault())
.perPage(200)
.build()
)
.getPricePoints();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
package com.maxio.advancedbilling.controllers.productpricepoints;

import com.maxio.advancedbilling.exceptions.ApiException;
import com.maxio.advancedbilling.exceptions.ProductPricePointErrorResponseException;
import com.maxio.advancedbilling.models.CreateProductPricePoint;
import com.maxio.advancedbilling.models.CreateProductPricePointRequest;
import com.maxio.advancedbilling.models.IntervalUnit;
import com.maxio.advancedbilling.models.PricePointType;
import com.maxio.advancedbilling.models.Product;
import com.maxio.advancedbilling.models.ProductPricePoint;
import com.maxio.advancedbilling.models.ProductPricePointErrors;
import com.maxio.advancedbilling.utils.CommonAssertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.io.IOException;
import java.util.List;
import java.util.stream.Stream;

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 ProductPricePointsControllerCreateTest extends ProductPricePointsBaseTest {

private static Product product;

@BeforeEach
void beforeEach() throws IOException, ApiException {
product = createProduct();
}

@Test
void shouldReturn201AndCreatePricePoint() throws IOException, ApiException {
// when
ProductPricePoint productPricePoint = createProductPricePoint(
product.getId(), defaultBuilder().name("Educational").handle("educational").build()
).getPricePoint();

// then
assertAll(
() -> assertThat(productPricePoint.getId()).isNotNull(),
() -> assertThat(productPricePoint.getName()).isEqualTo("Educational"),
() -> assertThat(productPricePoint.getHandle()).isEqualTo("educational"),
() -> assertThat(productPricePoint.getPriceInCents()).isEqualTo(100),
() -> assertThat(productPricePoint.getInterval()).isEqualTo(2),
() -> assertThat(productPricePoint.getIntervalUnit()).isEqualTo(IntervalUnit.MONTH),
() -> assertThat(productPricePoint.getTrialPriceInCents()).isEqualTo(4900),
() -> assertThat(productPricePoint.getTrialInterval()).isEqualTo(1),
() -> assertThat(productPricePoint.getTrialIntervalUnit()).isEqualTo(IntervalUnit.MONTH),
() -> assertThat(productPricePoint.getTrialType()).isEqualTo("payment_expected"),
() -> assertThat(productPricePoint.getIntroductoryOffer()).isFalse(),
() -> assertThat(productPricePoint.getInitialChargeInCents()).isEqualTo(120000),
() -> assertThat(productPricePoint.getInitialChargeAfterTrial()).isFalse(),
() -> assertThat(productPricePoint.getExpirationInterval()).isEqualTo(12),
() -> assertThat(productPricePoint.getExpirationIntervalUnit()).isEqualTo(IntervalUnit.MONTH),
() -> assertThat(productPricePoint.getProductId()).isEqualTo(product.getId()),
() -> assertThat(productPricePoint.getArchivedAt()).isNull(),
() -> assertThat(productPricePoint.getCreatedAt()).isNotNull(),
() -> assertThat(productPricePoint.getUpdatedAt()).isNotNull(),
() -> assertThat(productPricePoint.getUseSiteExchangeRate()).isTrue(),
() -> assertThat(productPricePoint.getType()).isEqualTo(PricePointType.CATALOG),
() -> assertThat(productPricePoint.getTaxIncluded()).isFalse(),
() -> assertThat(productPricePoint.getSubscriptionId()).isNull()
);
}

@Test
void shouldReturn404WhenCreatingPricePointForNotExistingProduct() {
// when - then
CommonAssertions.assertNotFound(() -> createProductPricePoint(12345, null));
}

@Test
void shouldReturn422WhenPricePointInRequestIsNull() {
// when - then
assertThatExceptionOfType(ProductPricePointErrorResponseException.class)
.isThrownBy(() -> createProductPricePoint(product.getId(), null))
.withMessage("Unprocessable Entity (WebDAV)")
.satisfies(e -> {
assertThat(e.getResponseCode()).isEqualTo(422);
assertThat(e.getErrors())
patryk-grudzien-keen marked this conversation as resolved.
Show resolved Hide resolved
.usingRecursiveComparison()
.isEqualTo(new ProductPricePointErrors.Builder().pricePoint("can't be blank").build());
});
}

@Test
void shouldReturn422WhenPricePointRequestIsEmpty() {
// when - then
assertThatExceptionOfType(ProductPricePointErrorResponseException.class)
.isThrownBy(() -> createProductPricePoint(product.getId(), new CreateProductPricePoint()))
.withMessage("Unprocessable Entity (WebDAV)")
.satisfies(e -> {
assertThat(e.getResponseCode()).isEqualTo(422);
assertThat(e.getErrors())
.usingRecursiveComparison()
.isEqualTo(new ProductPricePointErrors.Builder()
.interval(List.of("Recurring Interval: must be greater than or equal to 1."))
.intervalUnit(List.of("Interval unit: cannot be blank.", "Interval unit: must be 'month' or 'day'."))
.name(List.of("Name: cannot be blank."))
.build()
);
});
}

@ParameterizedTest
@MethodSource("argsForShouldReturn422WhenRequiredParametersAreMissing")
void shouldReturn422WhenRequiredParametersAreMissing(CreateProductPricePointRequest request, ProductPricePointErrors expectedErrors) {
// when - then
assertThatExceptionOfType(ProductPricePointErrorResponseException.class)
.isThrownBy(() -> PRODUCT_PRICE_POINTS_CONTROLLER.createProductPricePoint(product.getId(), request))
.withMessage("Unprocessable Entity (WebDAV)")
.satisfies(e -> {
assertThat(e.getResponseCode()).isEqualTo(422);
assertThat(e.getErrors())
.usingRecursiveComparison()
.isEqualTo(expectedErrors);
});
}

private static Stream<Arguments> argsForShouldReturn422WhenRequiredParametersAreMissing() {
return Stream.of(
Arguments.of(
new CreateProductPricePointRequest(
new CreateProductPricePoint.Builder().name("").build()
),
new ProductPricePointErrors.Builder()
.interval(List.of("Recurring Interval: must be greater than or equal to 1."))
.intervalUnit(List.of("Interval unit: cannot be blank.", "Interval unit: must be 'month' or 'day'."))
.name(List.of("Name: cannot be blank."))
.build()
),
Arguments.of(
new CreateProductPricePointRequest(
new CreateProductPricePoint.Builder().name("price point name").build()
),
new ProductPricePointErrors.Builder()
.interval(List.of("Recurring Interval: must be greater than or equal to 1."))
.intervalUnit(List.of("Interval unit: cannot be blank.", "Interval unit: must be 'month' or 'day'."))
.build()
),
Arguments.of(
new CreateProductPricePointRequest(
new CreateProductPricePoint.Builder()
.name("price point name")
.priceInCents(-100L)
.build()
),
new ProductPricePointErrors.Builder()
.interval(List.of("Recurring Interval: must be greater than or equal to 1."))
.intervalUnit(List.of("Interval unit: cannot be blank.", "Interval unit: must be 'month' or 'day'."))
.price(List.of("Price: must be greater than or equal to 0."))
.build()
),
Arguments.of(
new CreateProductPricePointRequest(
new CreateProductPricePoint.Builder()
.name("price point name")
.priceInCents(100L)
.interval(0)
.build()
),
new ProductPricePointErrors.Builder()
.interval(List.of("Recurring Interval: must be greater than or equal to 1."))
.intervalUnit(List.of("Interval unit: cannot be blank.", "Interval unit: must be 'month' or 'day'."))
.build()
),
Arguments.of(
new CreateProductPricePointRequest(
new CreateProductPricePoint.Builder()
.priceInCents(100L)
.interval(-1)
.build()
),
new ProductPricePointErrors.Builder()
.interval(List.of("Recurring Interval: must be greater than or equal to 1."))
.intervalUnit(List.of("Interval unit: cannot be blank.", "Interval unit: must be 'month' or 'day'."))
.name(List.of("Name: cannot be blank."))
.build()
),
Arguments.of(
new CreateProductPricePointRequest(
new CreateProductPricePoint.Builder()
.name("price point name")
.priceInCents(100L)
.interval(2)
.intervalUnit(null)
.build()
),
new ProductPricePointErrors.Builder()
.intervalUnit(List.of("Interval unit: cannot be blank.", "Interval unit: must be 'month' or 'day'."))
.build()
)
);
}
}
Loading