diff --git a/src/integration-test/java/com/commercetools/project/sync/ProductSyncWithSelfReferencesIT.java b/src/integration-test/java/com/commercetools/project/sync/ProductSyncWithSelfReferencesIT.java new file mode 100644 index 00000000..c8ee2b12 --- /dev/null +++ b/src/integration-test/java/com/commercetools/project/sync/ProductSyncWithSelfReferencesIT.java @@ -0,0 +1,248 @@ +package com.commercetools.project.sync; + +import static com.commercetools.api.models.common.LocalizedString.ofEnglish; +import static com.commercetools.project.sync.util.CtpClientUtils.CTP_SOURCE_CLIENT; +import static com.commercetools.project.sync.util.CtpClientUtils.CTP_TARGET_CLIENT; +import static com.commercetools.project.sync.util.IntegrationTestUtils.assertProductExists; +import static com.commercetools.project.sync.util.IntegrationTestUtils.assertProductTypeExists; +import static com.commercetools.project.sync.util.IntegrationTestUtils.cleanUpProjects; +import static com.commercetools.project.sync.util.IntegrationTestUtils.createAttributeObject; +import static com.commercetools.project.sync.util.IntegrationTestUtils.createITSyncerFactory; +import static com.commercetools.project.sync.util.IntegrationTestUtils.createReferenceOfType; +import static com.commercetools.project.sync.util.TestUtils.assertSyncerLoggingEvents; +import static org.assertj.core.api.Assertions.assertThat; + +import com.commercetools.api.client.ProjectApiRoot; +import com.commercetools.api.models.common.Reference; +import com.commercetools.api.models.common.ReferenceTypeId; +import com.commercetools.api.models.product.Attribute; +import com.commercetools.api.models.product.AttributeAccessor; +import com.commercetools.api.models.product.Product; +import com.commercetools.api.models.product.ProductDraft; +import com.commercetools.api.models.product.ProductDraftBuilder; +import com.commercetools.api.models.product.ProductUpdateActionBuilder; +import com.commercetools.api.models.product.ProductVariant; +import com.commercetools.api.models.product.ProductVariantDraft; +import com.commercetools.api.models.product.ProductVariantDraftBuilder; +import com.commercetools.api.models.product_type.AttributeConstraintEnum; +import com.commercetools.api.models.product_type.AttributeDefinitionDraft; +import com.commercetools.api.models.product_type.AttributeDefinitionDraftBuilder; +import com.commercetools.api.models.product_type.AttributeReferenceTypeId; +import com.commercetools.api.models.product_type.ProductType; +import com.commercetools.api.models.product_type.ProductTypeDraft; +import com.commercetools.api.models.product_type.ProductTypeDraftBuilder; +import com.commercetools.project.sync.product.ProductSyncer; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import uk.org.lidalia.slf4jext.Level; +import uk.org.lidalia.slf4jtest.TestLogger; +import uk.org.lidalia.slf4jtest.TestLoggerFactory; + +class ProductSyncWithSelfReferencesIT { + + private static final TestLogger productSyncerTestLogger = + TestLoggerFactory.getTestLogger(ProductSyncer.class); + + private static final String MAIN_PRODUCT_TYPE_KEY = "sample-product-type"; + private static final String MAIN_PRODUCT_MASTER_VARIANT_KEY = "main-product-master-variant-key"; + private static final String MAIN_PRODUCT_KEY = "product-with-nested"; + private static final String NESTED_ATTRIBUTE_NAME = "nested-products"; + private static final String PRODUCT_REFERENCE_ATTRIBUTE_NAME = "products"; + + @BeforeEach + void setup() { + productSyncerTestLogger.clearAll(); + cleanUpProjects(CTP_SOURCE_CLIENT, CTP_TARGET_CLIENT); + setupSourceProjectData(CTP_SOURCE_CLIENT); + } + + static void setupSourceProjectData(@Nonnull final ProjectApiRoot sourceProjectClient) { + final AttributeDefinitionDraft setOfProductsAttributeDef = + AttributeDefinitionDraftBuilder.of() + .type( + attributeTypeBuilder -> + attributeTypeBuilder + .setBuilder() + .elementType( + elementBuilder -> + elementBuilder + .referenceBuilder() + .referenceTypeId(AttributeReferenceTypeId.PRODUCT))) + .name(PRODUCT_REFERENCE_ATTRIBUTE_NAME) + .label(ofEnglish(PRODUCT_REFERENCE_ATTRIBUTE_NAME)) + .isRequired(false) + .isSearchable(false) + .attributeConstraint(AttributeConstraintEnum.NONE) + .build(); + + final ProductTypeDraft productTypeDraft = + ProductTypeDraftBuilder.of() + .key(MAIN_PRODUCT_TYPE_KEY) + .name(MAIN_PRODUCT_TYPE_KEY) + .description("a productType for t-shirts") + .attributes(setOfProductsAttributeDef) + .build(); + + final ProductType mainProductType = + sourceProjectClient.productTypes().post(productTypeDraft).executeBlocking().getBody(); + + final AttributeDefinitionDraft nestedAttributeDefinition = + AttributeDefinitionDraftBuilder.of() + .type( + attributeTypeBuilder -> + attributeTypeBuilder + .setBuilder() + .elementType( + typeBuilder -> + typeBuilder + .nestedBuilder() + .typeReference(mainProductType.toReference()))) + .isRequired(false) + .isSearchable(true) + .attributeConstraint(AttributeConstraintEnum.NONE) + .name(NESTED_ATTRIBUTE_NAME) + .label(ofEnglish(NESTED_ATTRIBUTE_NAME)) + .build(); + + sourceProjectClient + .productTypes() + .withKey(mainProductType.getKey()) + .post( + productTypeUpdateBuilder -> + productTypeUpdateBuilder + .version(mainProductType.getVersion()) + .withActions( + productTypeUpdateActionBuilder -> + productTypeUpdateActionBuilder + .addAttributeDefinitionBuilder() + .attribute(nestedAttributeDefinition))) + .executeBlocking(); + + final ProductVariantDraft masterVariant = + ProductVariantDraftBuilder.of() + .key(MAIN_PRODUCT_MASTER_VARIANT_KEY) + .sku(MAIN_PRODUCT_MASTER_VARIANT_KEY) + .build(); + + final ProductDraft productDraft = + ProductDraftBuilder.of() + .productType(mainProductType.toResourceIdentifier()) + .name(ofEnglish(MAIN_PRODUCT_KEY)) + .slug(ofEnglish(MAIN_PRODUCT_KEY)) + .masterVariant(masterVariant) + .key(MAIN_PRODUCT_KEY) + .build(); + + final Product productWithSelfReference = + sourceProjectClient.products().post(productDraft).executeBlocking().getBody(); + + final ArrayNode setAttributeValue = JsonNodeFactory.instance.arrayNode(); + final ArrayNode nestedAttributeValue = JsonNodeFactory.instance.arrayNode(); + + final ObjectNode referenceOfType = + createReferenceOfType( + ReferenceTypeId.PRODUCT.getJsonName(), productWithSelfReference.getId()); + setAttributeValue.add(referenceOfType); + nestedAttributeValue.add( + createAttributeObject(PRODUCT_REFERENCE_ATTRIBUTE_NAME, setAttributeValue)); + + sourceProjectClient + .products() + .withKey(MAIN_PRODUCT_KEY) + .post( + productUpdateBuilder -> + productUpdateBuilder + .version(productWithSelfReference.getVersion()) + .actions( + ProductUpdateActionBuilder.of() + .setAttributeInAllVariantsBuilder() + .name(PRODUCT_REFERENCE_ATTRIBUTE_NAME) + .value(setAttributeValue) + .build(), + ProductUpdateActionBuilder.of() + .setAttributeInAllVariantsBuilder() + .name(NESTED_ATTRIBUTE_NAME) + .value(JsonNodeFactory.instance.arrayNode().add(nestedAttributeValue)) + .build())) + .executeBlocking(); + } + + @AfterAll + static void tearDownSuite() { + cleanUpProjects(CTP_SOURCE_CLIENT, CTP_TARGET_CLIENT); + } + + @Test + void run_WithSyncAsArgumentWithAllArgAsFullSync_ShouldExecuteAllSyncers() { + // test + CliRunner.of() + .run(new String[] {"-s", "all", "-r", "runnerName", "-f"}, createITSyncerFactory()); + + assertThat(productSyncerTestLogger.getAllLoggingEvents()) + .allMatch(loggingEvent -> !Level.ERROR.equals(loggingEvent.getLevel())); + final String productStatsSummary = + "Summary: 1 product(s) were processed in total (1 created, 1 updated, " + + "0 failed to sync and 0 product(s) with missing reference(s))."; + assertSyncerLoggingEvents(productSyncerTestLogger, "ProductSync", productStatsSummary); + + assertAllResourcesAreSyncedToTarget(CTP_TARGET_CLIENT); + } + + private static void assertAllResourcesAreSyncedToTarget( + @Nonnull final ProjectApiRoot targetClient) { + + assertProductTypeExists(targetClient, MAIN_PRODUCT_TYPE_KEY); + final Product mainProduct = + assertProductExists( + targetClient, + MAIN_PRODUCT_KEY, + MAIN_PRODUCT_MASTER_VARIANT_KEY, + MAIN_PRODUCT_MASTER_VARIANT_KEY); + + assertThat(mainProduct.getKey()).isEqualTo(MAIN_PRODUCT_KEY); + final ProductVariant stagedMasterVariant = + mainProduct.getMasterData().getStaged().getMasterVariant(); + assertThat(stagedMasterVariant.getKey()).isEqualTo(MAIN_PRODUCT_MASTER_VARIANT_KEY); + assertThat(stagedMasterVariant.getAttributes()).hasSize(2); + assertThat(stagedMasterVariant.getAttribute(PRODUCT_REFERENCE_ATTRIBUTE_NAME)) + .satisfies( + attribute -> { + final List referenceList = AttributeAccessor.asSetReference(attribute); + assertThat(referenceList).hasSize(1); + + final Reference productReference = referenceList.get(0); + assertThat(productReference.getTypeId().getJsonName()) + .isEqualTo(AttributeReferenceTypeId.PRODUCT.getJsonName()); + assertThat(productReference.getId()).isEqualTo(mainProduct.getId()); + }); + assertThat(stagedMasterVariant.getAttribute(NESTED_ATTRIBUTE_NAME)) + .satisfies( + attribute -> { + final List> attributeAsSetNested = + AttributeAccessor.asSetNested(attribute); + assertThat(attributeAsSetNested).hasSize(1); + + final List nestedAttributeElement = attributeAsSetNested.get(0); + assertThat(nestedAttributeElement).hasSize(1); + + assertThat(nestedAttributeElement.get(0).getName()) + .isEqualTo(PRODUCT_REFERENCE_ATTRIBUTE_NAME); + assertThat(nestedAttributeElement.get(0).getValue()) + .isExactlyInstanceOf(ArrayList.class); + final List productReferences = + AttributeAccessor.asSetReference(nestedAttributeElement.get(0)); + assertThat(productReferences) + .singleElement() + .satisfies( + productReference -> + assertThat(productReference.getId()).isEqualTo(mainProduct.getId())); + }); + } +} diff --git a/src/integration-test/java/com/commercetools/project/sync/ProductTypeSyncWithNestedAttributesIT.java b/src/integration-test/java/com/commercetools/project/sync/ProductTypeSyncWithNestedAttributesIT.java new file mode 100644 index 00000000..df839991 --- /dev/null +++ b/src/integration-test/java/com/commercetools/project/sync/ProductTypeSyncWithNestedAttributesIT.java @@ -0,0 +1,158 @@ +package com.commercetools.project.sync; + +import static com.commercetools.api.models.common.LocalizedString.ofEnglish; +import static com.commercetools.project.sync.util.CtpClientUtils.CTP_SOURCE_CLIENT; +import static com.commercetools.project.sync.util.CtpClientUtils.CTP_TARGET_CLIENT; +import static com.commercetools.project.sync.util.IntegrationTestUtils.assertProductTypeExists; +import static com.commercetools.project.sync.util.IntegrationTestUtils.cleanUpProjects; +import static com.commercetools.project.sync.util.IntegrationTestUtils.createITSyncerFactory; +import static org.assertj.core.api.Assertions.assertThat; + +import com.commercetools.api.client.ProjectApiRoot; +import com.commercetools.api.models.product_type.AttributeConstraintEnum; +import com.commercetools.api.models.product_type.AttributeDefinitionDraft; +import com.commercetools.api.models.product_type.AttributeDefinitionDraftBuilder; +import com.commercetools.api.models.product_type.AttributeNestedType; +import com.commercetools.api.models.product_type.AttributeReferenceType; +import com.commercetools.api.models.product_type.AttributeReferenceTypeId; +import com.commercetools.api.models.product_type.AttributeSetType; +import com.commercetools.api.models.product_type.AttributeSetTypeBuilder; +import com.commercetools.api.models.product_type.AttributeType; +import com.commercetools.api.models.product_type.ProductType; +import com.commercetools.api.models.product_type.ProductTypeDraft; +import com.commercetools.api.models.product_type.ProductTypeDraftBuilder; +import com.commercetools.project.sync.producttype.ProductTypeSyncer; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import uk.org.lidalia.slf4jext.Level; +import uk.org.lidalia.slf4jtest.TestLogger; +import uk.org.lidalia.slf4jtest.TestLoggerFactory; + +// This will suppress MoreThanOneLogger warnings in this class +@SuppressWarnings("PMD.MoreThanOneLogger") +class ProductTypeSyncWithNestedAttributesIT { + private static final TestLogger productTypeSyncerTestLogger = + TestLoggerFactory.getTestLogger(ProductTypeSyncer.class); + + private static final String MAIN_PRODUCT_TYPE_KEY = "sample-product-type"; + + @BeforeEach + void setup() { + productTypeSyncerTestLogger.clearAll(); + + cleanUpProjects(CTP_SOURCE_CLIENT, CTP_TARGET_CLIENT); + setupSourceProjectData(CTP_SOURCE_CLIENT); + } + + static void setupSourceProjectData(@Nonnull final ProjectApiRoot sourceProjectClient) { + final AttributeDefinitionDraft attributeProductReferenceSetType = + createAttributeDefinitionDraftBuilderOfType( + AttributeSetTypeBuilder.of() + .elementType( + typeBuilder -> + typeBuilder + .referenceBuilder() + .referenceTypeId(AttributeReferenceTypeId.PRODUCT)) + .build()) + .name("product_references") + .label(ofEnglish("product_references")) + .build(); + + final ProductTypeDraft mainProductTypeDraft = + ProductTypeDraftBuilder.of() + .key(MAIN_PRODUCT_TYPE_KEY) + .name(MAIN_PRODUCT_TYPE_KEY) + .description("a main product type") + .attributes(attributeProductReferenceSetType) + .build(); + + final ProductType mainProductType = + sourceProjectClient.productTypes().post(mainProductTypeDraft).executeBlocking().getBody(); + + final AttributeDefinitionDraft nestedAttribute = + createAttributeDefinitionDraftBuilderOfType( + AttributeSetTypeBuilder.of() + .elementType( + typeBuilder -> + typeBuilder + .nestedBuilder() + .typeReference(mainProductType.toReference())) + .build()) + .name("nested_product_self") + .label(ofEnglish("nested_product_self")) + .build(); + + sourceProjectClient + .productTypes() + .withKey(mainProductType.getKey()) + .post( + productTypeUpdateBuilder -> + productTypeUpdateBuilder + .version(mainProductType.getVersion()) + .withActions( + productTypeUpdateActionBuilder -> + productTypeUpdateActionBuilder + .addAttributeDefinitionBuilder() + .attribute(nestedAttribute))) + .executeBlocking(); + } + + @AfterAll + static void tearDownSuite() { + cleanUpProjects(CTP_SOURCE_CLIENT, CTP_TARGET_CLIENT); + } + + @Test + void + run_WithSyncAsArgumentWithProductTypesWithSelfReference_ShouldResolveReferencesAndExecuteProductTypeSyncer() { + // test + CliRunner.of().run(new String[] {"-s", "productTypes", "-f"}, createITSyncerFactory()); + + // assertions + assertThat(productTypeSyncerTestLogger.getAllLoggingEvents()) + .allMatch(loggingEvent -> !Level.ERROR.equals(loggingEvent.getLevel())); + + // Every sync module is expected to have 2 logs (start and stats summary) + assertThat(productTypeSyncerTestLogger.getAllLoggingEvents()).hasSize(2); + final ProductType productType = + assertProductTypeExists(CTP_TARGET_CLIENT, MAIN_PRODUCT_TYPE_KEY); + assertThat(productType.getAttributes()).hasSize(2); + assertThat(productType.getAttribute("product_references")) + .satisfies( + attributeDefinition -> { + assertThat(attributeDefinition.getType()).isInstanceOf(AttributeSetType.class); + final AttributeSetType attributeSetType = + (AttributeSetType) attributeDefinition.getType(); + assertThat(attributeSetType.getElementType()) + .isInstanceOf(AttributeReferenceType.class); + final AttributeReferenceType attributeReferenceType = + (AttributeReferenceType) attributeSetType.getElementType(); + assertThat(attributeReferenceType.getReferenceTypeId()) + .isEqualTo(AttributeReferenceTypeId.PRODUCT); + }); + + assertThat(productType.getAttribute("nested_product_self")) + .satisfies( + attributeDefinition -> { + assertThat(attributeDefinition.getType()).isInstanceOf(AttributeSetType.class); + final AttributeSetType attributeSetType = + (AttributeSetType) attributeDefinition.getType(); + assertThat(attributeSetType.getElementType()).isInstanceOf(AttributeNestedType.class); + final AttributeNestedType attributeNestedType = + (AttributeNestedType) attributeSetType.getElementType(); + assertThat(attributeNestedType.getTypeReference()) + .isEqualTo(productType.toReference()); + }); + } + + private static AttributeDefinitionDraftBuilder createAttributeDefinitionDraftBuilderOfType( + final AttributeType attributeType) { + return AttributeDefinitionDraftBuilder.of() + .type(attributeType) + .isRequired(false) + .isSearchable(true) + .attributeConstraint(AttributeConstraintEnum.SAME_FOR_ALL); + } +} diff --git a/src/main/java/com/commercetools/project/sync/state/StateSyncer.java b/src/main/java/com/commercetools/project/sync/state/StateSyncer.java index b7bad357..41bee1bf 100644 --- a/src/main/java/com/commercetools/project/sync/state/StateSyncer.java +++ b/src/main/java/com/commercetools/project/sync/state/StateSyncer.java @@ -1,6 +1,5 @@ package com.commercetools.project.sync.state; -import static com.commercetools.project.sync.util.SyncUtils.getCompletionExceptionCause; import static com.commercetools.project.sync.util.SyncUtils.logErrorCallback; import static com.commercetools.project.sync.util.SyncUtils.logWarningCallback; import static com.commercetools.sync.states.utils.StateTransformUtils.toStateDrafts; @@ -78,17 +77,7 @@ public static StateSyncer of( @Nonnull @Override protected CompletionStage> transform(@Nonnull List states) { - return toStateDrafts(getSourceClient(), referenceIdToKeyCache, states) - .handle( - (stateDrafts, throwable) -> { - if (throwable != null) { - if (LOGGER.isWarnEnabled()) { - LOGGER.warn(throwable.getMessage(), getCompletionExceptionCause(throwable)); - } - return List.of(); - } - return stateDrafts; - }); + return toStateDrafts(getSourceClient(), referenceIdToKeyCache, states); } @Nonnull diff --git a/src/main/java/com/commercetools/project/sync/type/TypeSyncer.java b/src/main/java/com/commercetools/project/sync/type/TypeSyncer.java index 4e633c56..507f77cf 100644 --- a/src/main/java/com/commercetools/project/sync/type/TypeSyncer.java +++ b/src/main/java/com/commercetools/project/sync/type/TypeSyncer.java @@ -1,6 +1,5 @@ package com.commercetools.project.sync.type; -import static com.commercetools.project.sync.util.SyncUtils.getCompletionExceptionCause; import static com.commercetools.project.sync.util.SyncUtils.logErrorCallback; import static com.commercetools.project.sync.util.SyncUtils.logWarningCallback; @@ -33,8 +32,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -// This class compiles but not tested yet -// TODO: Test class and adjust logic if needed public final class TypeSyncer extends Syncer< Type, @@ -100,28 +97,22 @@ protected Logger getLoggerInstance() { @Nonnull @Override protected CompletionStage> transform(@Nonnull final List page) { - return CompletableFuture.supplyAsync( - () -> page.stream().map(TypeSyncer::typeToDraft).collect(Collectors.toList())) - .handle( - ((typeDrafts, throwable) -> { - if (throwable != null) { - if (LOGGER.isWarnEnabled()) { - LOGGER.warn(throwable.getMessage(), getCompletionExceptionCause(throwable)); - } - return List.of(); - } - return typeDrafts; - })); + return CompletableFuture.completedFuture( + page.stream().map(TypeSyncer::typeToDraft).collect(Collectors.toList())); } @Nullable private static TypeDraft typeToDraft(@Nonnull final Type type) { - return TypeDraftBuilder.of() - .key(type.getKey()) - .name(type.getName()) - .resourceTypeIds(type.getResourceTypeIds()) - .description(type.getDescription()) - .fieldDefinitions(type.getFieldDefinitions()) - .build(); + if (type.getKey() != null && type.getName() != null && type.getResourceTypeIds() != null) { + return TypeDraftBuilder.of() + .key(type.getKey()) + .name(type.getName()) + .resourceTypeIds(type.getResourceTypeIds()) + .description(type.getDescription()) + .fieldDefinitions(type.getFieldDefinitions()) + .build(); + } else { + return TypeDraft.of(); + } } } diff --git a/src/test/java/com/commercetools/project/sync/inventoryentry/InventoryEntrySyncerTest.java b/src/test/java/com/commercetools/project/sync/inventoryentry/InventoryEntrySyncerTest.java index ee831181..00c986a2 100644 --- a/src/test/java/com/commercetools/project/sync/inventoryentry/InventoryEntrySyncerTest.java +++ b/src/test/java/com/commercetools/project/sync/inventoryentry/InventoryEntrySyncerTest.java @@ -33,7 +33,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import uk.org.lidalia.slf4jtest.LoggingEvent; import uk.org.lidalia.slf4jtest.TestLogger; @@ -129,8 +128,7 @@ void transform_ShouldReplaceInventoryEntryReferenceIdsWithKeys() throws JsonProc } @Test - @Disabled("https://commercetools.atlassian.net/browse/DEVX-275") - void syncWithError_ShouldCallErrorCallback() throws JsonProcessingException { + void syncWithError_ShouldCallErrorCallback() { // preparation: inventory entry with no key is synced final ProjectApiRoot sourceClient = mock(ProjectApiRoot.class); final ProjectApiRoot targetClient = mock(ProjectApiRoot.class); diff --git a/src/test/java/com/commercetools/project/sync/state/StateSyncerTest.java b/src/test/java/com/commercetools/project/sync/state/StateSyncerTest.java index b99b9922..073e5dbc 100644 --- a/src/test/java/com/commercetools/project/sync/state/StateSyncerTest.java +++ b/src/test/java/com/commercetools/project/sync/state/StateSyncerTest.java @@ -24,12 +24,10 @@ import com.commercetools.api.models.state.StateTypeEnum; import com.commercetools.sync.states.StateSync; import io.vrap.rmf.base.client.ApiHttpResponse; -import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import uk.org.lidalia.slf4jtest.LoggingEvent; import uk.org.lidalia.slf4jtest.TestLogger; @@ -108,7 +106,7 @@ void getQuery_ShouldBuildStateQuery() { } @Test - void transform_WhenNoKeyIsProvided_ShouldContinueAndLogError() { + void transform_WhenNoKeyIsProvided_ShouldContinueWithEmptyStateDraft() { // preparation final ProjectApiRoot sourceClient = mock(ProjectApiRoot.class); final List stateTypePage = @@ -121,32 +119,18 @@ void transform_WhenNoKeyIsProvided_ShouldContinueAndLogError() { stateSyncer.transform(stateTypePage).toCompletableFuture(); // assertion - assertThat(stateDrafts).isCompletedWithValue(Collections.emptyList()); - assertThat(syncerTestLogger.getAllLoggingEvents()) - .anySatisfy( - loggingEvent -> { - assertThat(loggingEvent.getMessage()).contains("StateDraft: key is missing"); - assertThat(loggingEvent.getThrowable().isPresent()).isTrue(); - assertThat(loggingEvent.getThrowable().get()) - .isInstanceOf(NullPointerException.class); - }); + assertThat(stateDrafts).isCompletedWithValue(List.of(StateDraft.of())); } - /* - * Disabled as long as there's NPE when a key is null or empty and therefore add with PLACEHOLDER to cache. - * See: https://commercetools.atlassian.net/browse/DEVX-277 - */ - @Disabled @Test - void syncWithError_WhenTransistionReferencesAreInvalid_ShouldCallErrorCallback() { + void syncWithError_WhenTransitionReferencesAreInvalid_ShouldCallErrorCallback() { // preparation final ProjectApiRoot sourceClient = mock(ProjectApiRoot.class); - mockResourceIdsGraphQlRequest( - sourceClient, "states", "ab949f1b-c441-4c70-9cf0-4182c36d6a6c", ""); - final List stateTypePage = List.of(readObjectFromResource("state-2.json", State.class)); + final State state = readObjectFromResource("state-2.json", State.class); + state.getTransitions().get(0).setId("invalidReference"); final StatePagedQueryResponse queryResponse = StatePagedQueryResponseBuilder.of() - .results(stateTypePage) + .results(List.of(state)) .limit(20L) .offset(0L) .count(1L) @@ -162,6 +146,7 @@ void syncWithError_WhenTransistionReferencesAreInvalid_ShouldCallErrorCallback() when(sourceClient.states()).thenReturn(mock()); when(sourceClient.states().get()).thenReturn(byProjectKeyStatesGet); + mockResourceIdsGraphQlRequest(sourceClient, "states", "", ""); // test final StateSyncer stateSyncer = StateSyncer.of(sourceClient, mock(ProjectApiRoot.class), getMockedClock()); @@ -174,8 +159,6 @@ void syncWithError_WhenTransistionReferencesAreInvalid_ShouldCallErrorCallback() "Error when trying to sync state. Existing key: <>. Update actions: []"); assertThat(errorLog.getThrowable().get().getMessage()) .isEqualTo( - format( - "StateDraft with key: %s has invalid state transitions", - stateTypePage.get(0).getKey())); + format("StateDraft with key: '%s' has invalid state transitions", state.getKey())); } } diff --git a/src/test/java/com/commercetools/project/sync/type/TypeSyncerTest.java b/src/test/java/com/commercetools/project/sync/type/TypeSyncerTest.java index dfd79bdd..e93d039e 100644 --- a/src/test/java/com/commercetools/project/sync/type/TypeSyncerTest.java +++ b/src/test/java/com/commercetools/project/sync/type/TypeSyncerTest.java @@ -21,7 +21,6 @@ import com.commercetools.api.models.type.TypePagedQueryResponseBuilder; import com.commercetools.sync.types.TypeSync; import io.vrap.rmf.base.client.ApiHttpResponse; -import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; import org.junit.jupiter.api.BeforeEach; @@ -97,7 +96,7 @@ void getQuery_ShouldBuildTypeQuery() { } @Test - void transform_WhenNoKeyIsProvided_ShouldLogErrorAndContinue() { + void transform_WhenNoKeyIsProvided_ShouldContinueWithEmptyStateDraft() { // preparation final ProjectApiRoot sourceClient = mock(ProjectApiRoot.class); final List typePage = @@ -109,15 +108,8 @@ void transform_WhenNoKeyIsProvided_ShouldLogErrorAndContinue() { final List typeDrafts = typeSyncer.transform(typePage).toCompletableFuture().join(); // assertion - assertThat(typeDrafts).isEqualTo(Collections.emptyList()); - assertThat(syncerTestLogger.getAllLoggingEvents()) - .anySatisfy( - loggingEvent -> { - assertThat(loggingEvent.getMessage()).contains("TypeDraft: key is missing"); - assertThat(loggingEvent.getThrowable().isPresent()).isTrue(); - assertThat(loggingEvent.getThrowable().get()) - .isInstanceOf(NullPointerException.class); - }); + assertThat(typeDrafts).hasSize(1); + assertThat(typeDrafts).isEqualTo(List.of(TypeDraft.of())); } @Test