diff --git a/src/integration-test/java/com/commercetools/project/sync/InventorySyncMultiChannelIT.java b/src/integration-test/java/com/commercetools/project/sync/InventorySyncMultiChannelIT.java index 016efbd4..4b7269b4 100644 --- a/src/integration-test/java/com/commercetools/project/sync/InventorySyncMultiChannelIT.java +++ b/src/integration-test/java/com/commercetools/project/sync/InventorySyncMultiChannelIT.java @@ -1,206 +1,249 @@ -// package com.commercetools.project.sync; -// -// 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.cleanUpProjects; -// import static com.commercetools.project.sync.util.IntegrationTestUtils.createITSyncerFactory; -// import static java.util.Collections.singletonList; -// import static org.assertj.core.api.Assertions.assertThat; -// -// import com.commercetools.project.sync.inventoryentry.InventoryEntrySyncer; -// import com.fasterxml.jackson.databind.JsonNode; -// import com.fasterxml.jackson.databind.node.JsonNodeFactory; -// import io.sphere.sdk.channels.Channel; -// import io.sphere.sdk.channels.ChannelDraft; -// import io.sphere.sdk.channels.ChannelRole; -// import io.sphere.sdk.channels.commands.ChannelCreateCommand; -// import io.sphere.sdk.client.SphereClient; -// import io.sphere.sdk.inventory.InventoryEntry; -// import io.sphere.sdk.inventory.InventoryEntryDraft; -// import io.sphere.sdk.inventory.InventoryEntryDraftBuilder; -// import io.sphere.sdk.inventory.commands.InventoryEntryCreateCommand; -// import io.sphere.sdk.models.LocalizedString; -// import io.sphere.sdk.models.Reference; -// import io.sphere.sdk.types.CustomFieldsDraft; -// import io.sphere.sdk.types.FieldDefinition; -// import io.sphere.sdk.types.StringFieldType; -// import io.sphere.sdk.types.TypeDraft; -// import io.sphere.sdk.types.TypeDraftBuilder; -// import io.sphere.sdk.types.commands.TypeCreateCommand; -// import java.util.Collections; -// import java.util.HashMap; -// import java.util.Locale; -// import java.util.Map; -// import java.util.concurrent.CompletableFuture; -// import java.util.stream.IntStream; -// import javax.annotation.Nonnull; -// import org.junit.jupiter.api.BeforeEach; -// import org.junit.jupiter.api.Disabled; -// import org.junit.jupiter.api.Test; -// import uk.org.lidalia.slf4jext.Level; -// import uk.org.lidalia.slf4jtest.TestLogger; -// import uk.org.lidalia.slf4jtest.TestLoggerFactory; -// -// @Disabled( -// "Disabled for normal builds, " -// + "This scenario created to evaluate multiple channel use case" -// + "see: https://github.com/commercetools/commercetools-project-sync/issues/301") -// public class InventorySyncMultiChannelIT { -// private static final TestLogger testLogger = -// TestLoggerFactory.getTestLogger(InventoryEntrySyncer.class); -// -// public static final String SKU_1 = "SKU_ONE"; -// public static final String SKU_2 = "SKU_TWO"; -// public static final String SUPPLY_CHANNEL_KEY_1 = "channel-key_1"; -// public static final String SUPPLY_CHANNEL_KEY_2 = "channel-key_2"; -// -// public static final String CUSTOM_TYPE = "inventory-custom-type-name"; -// public static final String CUSTOM_FIELD_NAME = "inventory-custom-field-1"; -// -// @BeforeEach -// void setup() { -// testLogger.clearAll(); -// cleanUpProjects(CTP_SOURCE_CLIENT, CTP_TARGET_CLIENT); -// create249InventoryEntry(CTP_SOURCE_CLIENT); -// create249InventoryEntry(CTP_TARGET_CLIENT); -// setupProjectData(CTP_SOURCE_CLIENT); -// setupProjectData(CTP_TARGET_CLIENT); -// } -// -// private void setupProjectData(SphereClient sphereClient) { -// final ChannelDraft channelDraft1 = -// ChannelDraft.of(SUPPLY_CHANNEL_KEY_1).withRoles(ChannelRole.INVENTORY_SUPPLY); -// final ChannelDraft channelDraft2 = -// ChannelDraft.of(SUPPLY_CHANNEL_KEY_2).withRoles(ChannelRole.INVENTORY_SUPPLY); -// -// final String channelId1 = -// sphereClient -// .execute(ChannelCreateCommand.of(channelDraft1)) -// .toCompletableFuture() -// .join() -// .getId(); -// final String channelId2 = -// sphereClient -// .execute(ChannelCreateCommand.of(channelDraft2)) -// .toCompletableFuture() -// .join() -// .getId(); -// -// final Reference supplyChannelReference1 = Channel.referenceOfId(channelId1); -// final Reference supplyChannelReference2 = Channel.referenceOfId(channelId2); -// -// createInventoriesCustomType(sphereClient); -// -// // NOTE: There can only be one inventory entry for the combination of sku and supplyChannel. -// final InventoryEntryDraft draft1 = InventoryEntryDraftBuilder.of(SKU_1, 0L).build(); -// final InventoryEntryDraft draft2 = -// InventoryEntryDraftBuilder.of(SKU_1, 0L) -// .supplyChannel(supplyChannelReference1) -// .custom(CustomFieldsDraft.ofTypeKeyAndJson(CUSTOM_TYPE, getMockCustomFieldsJsons())) -// .build(); -// final InventoryEntryDraft draft3 = -// InventoryEntryDraftBuilder.of(SKU_1, 1L) -// .supplyChannel(supplyChannelReference2) -// .custom(CustomFieldsDraft.ofTypeKeyAndJson(CUSTOM_TYPE, getMockCustomFieldsJsons())) -// .build(); -// -// final InventoryEntryDraft draft4 = InventoryEntryDraftBuilder.of(SKU_2, 0L).build(); -// final InventoryEntryDraft draft5 = -// InventoryEntryDraftBuilder.of(SKU_2, 0L) -// .supplyChannel(supplyChannelReference1) -// .custom(CustomFieldsDraft.ofTypeKeyAndJson(CUSTOM_TYPE, getMockCustomFieldsJsons())) -// .build(); -// final InventoryEntryDraft draft6 = -// InventoryEntryDraftBuilder.of(SKU_2, 1L) -// .supplyChannel(supplyChannelReference2) -// .custom(CustomFieldsDraft.ofTypeKeyAndJson(CUSTOM_TYPE, getMockCustomFieldsJsons())) -// .build(); -// -// CompletableFuture.allOf( -// sphereClient.execute(InventoryEntryCreateCommand.of(draft1)).toCompletableFuture(), -// sphereClient.execute(InventoryEntryCreateCommand.of(draft2)).toCompletableFuture(), -// sphereClient.execute(InventoryEntryCreateCommand.of(draft3)).toCompletableFuture(), -// sphereClient.execute(InventoryEntryCreateCommand.of(draft4)).toCompletableFuture(), -// sphereClient.execute(InventoryEntryCreateCommand.of(draft5)).toCompletableFuture(), -// sphereClient.execute(InventoryEntryCreateCommand.of(draft6)).toCompletableFuture()) -// .join(); -// } -// -// private static void createInventoriesCustomType(@Nonnull final SphereClient ctpClient) { -// final FieldDefinition fieldDefinition = -// FieldDefinition.of( -// StringFieldType.of(), -// CUSTOM_FIELD_NAME, -// LocalizedString.of(Locale.ENGLISH, CUSTOM_FIELD_NAME), -// false); -// final TypeDraft typeDraft = -// TypeDraftBuilder.of( -// CUSTOM_TYPE, -// LocalizedString.of(Locale.ENGLISH, CUSTOM_TYPE), -// Collections.singleton(InventoryEntry.resourceTypeId())) -// .fieldDefinitions(singletonList(fieldDefinition)) -// .build(); -// ctpClient.execute(TypeCreateCommand.of(typeDraft)).toCompletableFuture().join(); -// } -// -// private static Map getMockCustomFieldsJsons() { -// final Map customFieldsJsons = new HashMap<>(); -// customFieldsJsons.put(CUSTOM_FIELD_NAME, JsonNodeFactory.instance.textNode("customValue")); -// return customFieldsJsons; -// } -// -// private void create249InventoryEntry(SphereClient sphereClient) { -// CompletableFuture.allOf( -// IntStream.range(0, 10) -// .mapToObj( -// value -> -// sphereClient -// .execute( -// InventoryEntryCreateCommand.of( -// InventoryEntryDraftBuilder.of("SKU_" + value, 1L).build())) -// .toCompletableFuture()) -// .toArray(CompletableFuture[]::new)) -// .join(); -// -// CompletableFuture.allOf( -// IntStream.range(0, 251) -// .mapToObj(value -> create(sphereClient, value)) -// .toArray(CompletableFuture[]::new)) -// .join(); -// } -// -// private CompletableFuture create(SphereClient sphereClient, int value) { -// final ChannelDraft channelDraft1 = -// ChannelDraft.of("other-channel-key_" + value).withRoles(ChannelRole.INVENTORY_SUPPLY); -// -// final String channelId = -// sphereClient -// .execute(ChannelCreateCommand.of(channelDraft1)) -// .toCompletableFuture() -// .join() -// .getId(); -// -// final Reference supplyChannelReference = Channel.referenceOfId(channelId); -// -// return sphereClient -// .execute( -// InventoryEntryCreateCommand.of( -// InventoryEntryDraftBuilder.of("SKU_CHANNEL", 0L) -// .supplyChannel(supplyChannelReference) -// .build())) -// .toCompletableFuture(); -// } -// -// @Test -// void run_asInventoryFullSync_ShouldNotReturnAnError() { -// // test -// CliRunner.of().run(new String[] {"-s", "inventoryEntries", "-f"}, createITSyncerFactory()); -// -// // assertions -// assertThat(testLogger.getAllLoggingEvents()) -// .allMatch(loggingEvent -> !Level.ERROR.equals(loggingEvent.getLevel())); -// -// // Every sync module is expected to have 2 logs (start and stats summary) -// assertThat(testLogger.getAllLoggingEvents()).hasSize(2); -// } -// } +package com.commercetools.project.sync; + +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.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.channel.Channel; +import com.commercetools.api.models.channel.ChannelDraft; +import com.commercetools.api.models.channel.ChannelDraftBuilder; +import com.commercetools.api.models.channel.ChannelRoleEnum; +import com.commercetools.api.models.common.LocalizedString; +import com.commercetools.api.models.inventory.InventoryEntry; +import com.commercetools.api.models.inventory.InventoryEntryDraft; +import com.commercetools.api.models.inventory.InventoryEntryDraftBuilder; +import com.commercetools.api.models.type.CustomFieldsDraftBuilder; +import com.commercetools.api.models.type.FieldContainer; +import com.commercetools.api.models.type.FieldContainerBuilder; +import com.commercetools.api.models.type.FieldDefinition; +import com.commercetools.api.models.type.FieldDefinitionBuilder; +import com.commercetools.api.models.type.FieldTypeBuilder; +import com.commercetools.api.models.type.ResourceTypeId; +import com.commercetools.api.models.type.TypeDraft; +import com.commercetools.api.models.type.TypeDraftBuilder; +import com.commercetools.project.sync.inventoryentry.InventoryEntrySyncer; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import io.vrap.rmf.base.client.ApiHttpResponse; +import java.util.concurrent.CompletableFuture; +import java.util.stream.IntStream; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import uk.org.lidalia.slf4jext.Level; +import uk.org.lidalia.slf4jtest.TestLogger; +import uk.org.lidalia.slf4jtest.TestLoggerFactory; + +@Disabled( + "Disabled for normal builds, " + + "This scenario created to evaluate multiple channel use case" + + "see: https://github.com/commercetools/commercetools-project-sync/issues/301") +public class InventorySyncMultiChannelIT { + private static final TestLogger testLogger = + TestLoggerFactory.getTestLogger(InventoryEntrySyncer.class); + + public static final String SKU_1 = "SKU_ONE"; + public static final String SKU_2 = "SKU_TWO"; + public static final String SUPPLY_CHANNEL_KEY_1 = "channel-key_1"; + public static final String SUPPLY_CHANNEL_KEY_2 = "channel-key_2"; + + public static final String CUSTOM_TYPE = "inventory-custom-type-name"; + public static final String CUSTOM_FIELD_NAME = "inventory-custom-field-1"; + + @BeforeEach + void setup() { + testLogger.clearAll(); + cleanUpProjects(CTP_SOURCE_CLIENT, CTP_TARGET_CLIENT); + create249InventoryEntry(CTP_SOURCE_CLIENT); + create249InventoryEntry(CTP_TARGET_CLIENT); + setupProjectData(CTP_SOURCE_CLIENT); + setupProjectData(CTP_TARGET_CLIENT); + } + + private void setupProjectData(ProjectApiRoot projectApiRoot) { + final ChannelDraft channelDraft1 = + ChannelDraftBuilder.of() + .key(SUPPLY_CHANNEL_KEY_1) + .roles(ChannelRoleEnum.INVENTORY_SUPPLY) + .build(); + final ChannelDraft channelDraft2 = + ChannelDraftBuilder.of() + .key(SUPPLY_CHANNEL_KEY_2) + .roles(ChannelRoleEnum.INVENTORY_SUPPLY) + .build(); + + final Channel channel1 = + projectApiRoot + .channels() + .create(channelDraft1) + .execute() + .thenApply(ApiHttpResponse::getBody) + .toCompletableFuture() + .join(); + final Channel channel2 = + projectApiRoot + .channels() + .create(channelDraft2) + .execute() + .thenApply(ApiHttpResponse::getBody) + .toCompletableFuture() + .join(); + + createInventoriesCustomType(projectApiRoot); + + // NOTE: There can only be one inventory entry for the combination of sku and supplyChannel. + final InventoryEntryDraft draft1 = + InventoryEntryDraftBuilder.of().sku(SKU_1).quantityOnStock(0L).build(); + final InventoryEntryDraft draft2 = + InventoryEntryDraftBuilder.of() + .sku(SKU_1) + .quantityOnStock(0L) + .supplyChannel(channel1.toResourceIdentifier()) + .custom( + CustomFieldsDraftBuilder.of() + .type(builder -> builder.key(CUSTOM_TYPE)) + .fields(getMockFieldContainer()) + .build()) + .build(); + final InventoryEntryDraft draft3 = + InventoryEntryDraftBuilder.of() + .sku(SKU_1) + .quantityOnStock(1L) + .supplyChannel(channel2.toResourceIdentifier()) + .custom( + CustomFieldsDraftBuilder.of() + .type(builder -> builder.key(CUSTOM_TYPE)) + .fields(getMockFieldContainer()) + .build()) + .build(); + + final InventoryEntryDraft draft4 = + InventoryEntryDraftBuilder.of().sku(SKU_2).quantityOnStock(0L).build(); + final InventoryEntryDraft draft5 = + InventoryEntryDraftBuilder.of() + .sku(SKU_2) + .quantityOnStock(0L) + .supplyChannel(channel1.toResourceIdentifier()) + .custom( + CustomFieldsDraftBuilder.of() + .type(builder -> builder.key(CUSTOM_TYPE)) + .fields(getMockFieldContainer()) + .build()) + .build(); + final InventoryEntryDraft draft6 = + InventoryEntryDraftBuilder.of() + .sku(SKU_2) + .quantityOnStock(1L) + .supplyChannel(channel2.toResourceIdentifier()) + .custom( + CustomFieldsDraftBuilder.of() + .type(builder -> builder.key(CUSTOM_TYPE)) + .fields(getMockFieldContainer()) + .build()) + .build(); + + CompletableFuture.allOf( + projectApiRoot.inventory().create(draft1).execute().toCompletableFuture(), + projectApiRoot.inventory().create(draft2).execute().toCompletableFuture(), + projectApiRoot.inventory().create(draft3).execute().toCompletableFuture(), + projectApiRoot.inventory().create(draft4).execute().toCompletableFuture(), + projectApiRoot.inventory().create(draft5).execute().toCompletableFuture(), + projectApiRoot.inventory().create(draft6).execute().toCompletableFuture()) + .join(); + } + + private static void createInventoriesCustomType(@Nonnull final ProjectApiRoot ctpClient) { + final FieldDefinition fieldDefinition = + FieldDefinitionBuilder.of() + .name(CUSTOM_FIELD_NAME) + .label(LocalizedString.ofEnglish(CUSTOM_FIELD_NAME)) + .required(false) + .type(FieldTypeBuilder.of().stringBuilder().build()) + .build(); + + final TypeDraft typeDraft = + TypeDraftBuilder.of() + .key(CUSTOM_TYPE) + .name(LocalizedString.ofEnglish(CUSTOM_TYPE)) + .resourceTypeIds(ResourceTypeId.INVENTORY_ENTRY) + .fieldDefinitions(fieldDefinition) + .build(); + + ctpClient.types().create(typeDraft).execute().toCompletableFuture().join(); + } + + private static FieldContainer getMockFieldContainer() { + return FieldContainerBuilder.of() + .addValue(CUSTOM_FIELD_NAME, JsonNodeFactory.instance.textNode("customValue")) + .build(); + } + + private void create249InventoryEntry(ProjectApiRoot projectApiRoot) { + CompletableFuture.allOf( + IntStream.range(0, 10) + .mapToObj( + value -> + projectApiRoot + .inventory() + .create( + InventoryEntryDraftBuilder.of() + .sku("SKU_" + value) + .quantityOnStock(1L) + .build()) + .execute() + .toCompletableFuture()) + .toArray(CompletableFuture[]::new)) + .join(); + + CompletableFuture.allOf( + IntStream.range(0, 251) + .mapToObj(value -> create(projectApiRoot, value)) + .toArray(CompletableFuture[]::new)) + .join(); + } + + private CompletableFuture create(ProjectApiRoot projectApiRoot, int value) { + final ChannelDraft channelDraft1 = + ChannelDraftBuilder.of() + .key("other-channel-key_" + value) + .roles(ChannelRoleEnum.INVENTORY_SUPPLY) + .build(); + + final Channel channel = + projectApiRoot + .channels() + .create(channelDraft1) + .execute() + .thenApply(ApiHttpResponse::getBody) + .toCompletableFuture() + .join(); + + return projectApiRoot + .inventory() + .create( + InventoryEntryDraftBuilder.of() + .supplyChannel(channel.toResourceIdentifier()) + .sku("SKU_CHANNEL") + .quantityOnStock(0L) + .build()) + .execute() + .thenApply(ApiHttpResponse::getBody) + .toCompletableFuture(); + } + + @Test + void run_asInventoryFullSync_ShouldNotReturnAnError() { + // test + CliRunner.of().run(new String[] {"-s", "inventoryEntries", "-f"}, createITSyncerFactory()); + + // assertions + assertThat(testLogger.getAllLoggingEvents()) + .allMatch(loggingEvent -> !Level.ERROR.equals(loggingEvent.getLevel())); + + // Every sync module is expected to have 2 logs (start and stats summary) + assertThat(testLogger.getAllLoggingEvents()).hasSize(2); + } +} diff --git a/src/main/java/com/commercetools/project/sync/inventoryentry/InventoryEntrySyncer.java b/src/main/java/com/commercetools/project/sync/inventoryentry/InventoryEntrySyncer.java index 44518836..ea146de9 100644 --- a/src/main/java/com/commercetools/project/sync/inventoryentry/InventoryEntrySyncer.java +++ b/src/main/java/com/commercetools/project/sync/inventoryentry/InventoryEntrySyncer.java @@ -29,8 +29,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 InventoryEntrySyncer extends Syncer< InventoryEntry, diff --git a/src/test/java/com/commercetools/project/sync/category/CategorySyncerTest.java b/src/test/java/com/commercetools/project/sync/category/CategorySyncerTest.java index 5e4a7c37..0103eec3 100644 --- a/src/test/java/com/commercetools/project/sync/category/CategorySyncerTest.java +++ b/src/test/java/com/commercetools/project/sync/category/CategorySyncerTest.java @@ -13,15 +13,11 @@ import com.commercetools.api.client.ByProjectKeyCategoriesKeyByKeyGet; import com.commercetools.api.client.ByProjectKeyCategoriesKeyByKeyRequestBuilder; import com.commercetools.api.client.ByProjectKeyCategoriesRequestBuilder; -import com.commercetools.api.client.ByProjectKeyGraphqlPost; -import com.commercetools.api.client.ByProjectKeyGraphqlRequestBuilder; import com.commercetools.api.client.ProjectApiRoot; import com.commercetools.api.models.category.Category; import com.commercetools.api.models.category.CategoryDraft; import com.commercetools.api.models.category.CategoryPagedQueryResponse; import com.commercetools.api.models.category.CategoryPagedQueryResponseBuilder; -import com.commercetools.api.models.graph_ql.GraphQLRequest; -import com.commercetools.api.models.graph_ql.GraphQLResponse; import com.commercetools.sync.categories.CategorySync; import com.commercetools.sync.commons.utils.CaffeineReferenceIdToKeyCacheImpl; import com.commercetools.sync.commons.utils.ReferenceIdToKeyCache; @@ -83,21 +79,8 @@ void transform_ShouldReplaceCategoryReferenceIdsWithKeys() throws JsonProcessing .map(category -> category.getCustom().getType().getId()) .collect(Collectors.toList()); - final String jsonStringCustomTypes = - "{\"data\":{\"typeDefinitions\":{\"results\":[{\"id\":\"53c4a8b4-754f-4b95-b6f2-3e1e70e3d0c3\",\"key\":\"cat1\"}]}}}"; - - final GraphQLResponse customTypesResult = - readObject(jsonStringCustomTypes, GraphQLResponse.class); - - final ApiHttpResponse response = mock(ApiHttpResponse.class); - when(response.getBody()).thenReturn(customTypesResult); - - final ByProjectKeyGraphqlRequestBuilder byProjectKeyGraphqlRequestBuilder = mock(); - when(sourceClient.graphql()).thenReturn(byProjectKeyGraphqlRequestBuilder); - final ByProjectKeyGraphqlPost byProjectKeyGraphqlPost = mock(); - when(byProjectKeyGraphqlRequestBuilder.post(any(GraphQLRequest.class))) - .thenReturn(byProjectKeyGraphqlPost); - when(byProjectKeyGraphqlPost.execute()).thenReturn(CompletableFuture.completedFuture(response)); + mockResourceIdsGraphQlRequest( + sourceClient, "typeDefinitions", "53c4a8b4-754f-4b95-b6f2-3e1e70e3d0c3", "cat1"); // test final CompletionStage> draftsFromPageStage = @@ -228,22 +211,8 @@ void syncWithWarning_ShouldCallWarningCallback() throws JsonProcessingException when(byProjectKeyCategoriesGetTarget.execute()) .thenReturn(CompletableFuture.completedFuture(targetResponse)); - final String jsonStringCustomTypes = - "{\"data\":{\"categories\":{\"results\":[{\"id\":\"ba81a6da-cf83-435b-a89e-2afab579846f\",\"key\":\"categoryKey2\"}]}}}"; - - final GraphQLResponse customTypesResult = - readObject(jsonStringCustomTypes, GraphQLResponse.class); - - final ApiHttpResponse graphQLResponse = mock(ApiHttpResponse.class); - when(graphQLResponse.getBody()).thenReturn(customTypesResult); - - final ByProjectKeyGraphqlRequestBuilder byProjectKeyGraphqlRequestBuilder = mock(); - when(targetClient.graphql()).thenReturn(byProjectKeyGraphqlRequestBuilder); - final ByProjectKeyGraphqlPost byProjectKeyGraphqlPost = mock(); - when(byProjectKeyGraphqlRequestBuilder.post(any(GraphQLRequest.class))) - .thenReturn(byProjectKeyGraphqlPost); - when(byProjectKeyGraphqlPost.execute()) - .thenReturn(CompletableFuture.completedFuture(graphQLResponse)); + mockResourceIdsGraphQlRequest( + targetClient, "categories", "ba81a6da-cf83-435b-a89e-2afab579846f", "categoryKey2"); // test final CategorySyncer categorySyncer = 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 8c056d6c..ee831181 100644 --- a/src/test/java/com/commercetools/project/sync/inventoryentry/InventoryEntrySyncerTest.java +++ b/src/test/java/com/commercetools/project/sync/inventoryentry/InventoryEntrySyncerTest.java @@ -1,13 +1,44 @@ package com.commercetools.project.sync.inventoryentry; +import static com.commercetools.project.sync.util.TestUtils.*; +import static com.commercetools.sync.inventories.utils.InventoryTransformUtils.toInventoryEntryDrafts; +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.commercetools.api.client.ByProjectKeyGraphqlPost; +import com.commercetools.api.client.ByProjectKeyGraphqlRequestBuilder; +import com.commercetools.api.client.ByProjectKeyInventoryGet; +import com.commercetools.api.client.ByProjectKeyInventoryRequestBuilder; +import com.commercetools.api.client.ProjectApiRoot; +import com.commercetools.api.models.graph_ql.GraphQLRequest; +import com.commercetools.api.models.graph_ql.GraphQLResponse; +import com.commercetools.api.models.inventory.InventoryEntry; +import com.commercetools.api.models.inventory.InventoryEntryDraft; +import com.commercetools.api.models.inventory.InventoryPagedQueryResponse; +import com.commercetools.api.models.inventory.InventoryPagedQueryResponseBuilder; import com.commercetools.sync.commons.utils.CaffeineReferenceIdToKeyCacheImpl; import com.commercetools.sync.commons.utils.ReferenceIdToKeyCache; +import com.commercetools.sync.inventories.InventorySync; +import com.fasterxml.jackson.core.JsonProcessingException; +import io.vrap.rmf.base.client.ApiHttpResponse; +import java.time.Clock; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +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; import uk.org.lidalia.slf4jtest.TestLoggerFactory; -// These tests aren't migrated -// TODO: Migrate tests class InventoryEntrySyncerTest { private final TestLogger syncerTestLogger = @@ -20,111 +51,130 @@ void setup() { syncerTestLogger.clearAll(); } - // @Test - // void of_ShouldCreateInventoryEntrySyncerInstance() { - // // test - // final InventoryEntrySyncer inventorySyncer = - // InventoryEntrySyncer.of( - // mock(SphereClient.class), mock(SphereClient.class), getMockedClock()); - // - // // assertions - // assertThat(inventorySyncer).isNotNull(); - // assertThat(inventorySyncer.getSync()).isInstanceOf(InventorySync.class); - // } - // - // @Test - // void transform_ShouldReplaceInventoryEntryReferenceIdsWithKeys() { - // // preparation - // final SphereClient sourceClient = mock(SphereClient.class); - // final InventoryEntrySyncer inventoryEntrySyncer = - // InventoryEntrySyncer.of(sourceClient, mock(SphereClient.class), getMockedClock()); - // final List inventoryPage = - // asList( - // readObjectFromResource("inventory-sku-1.json", InventoryEntry.class), - // readObjectFromResource("inventory-sku-2.json", InventoryEntry.class)); - // final List referenceIds = - // inventoryPage.stream() - // .filter(inventoryEntry -> inventoryEntry.getSupplyChannel() != null) - // .filter(inventoryEntry -> inventoryEntry.getCustom() != null) - // .flatMap( - // inventoryEntry -> - // Stream.of( - // inventoryEntry.getCustom().getType().getId(), - // inventoryEntry.getSupplyChannel().getId())) - // .collect(Collectors.toList()); - // - // final String jsonStringCustomTypes = - // "{\"results\":[{\"id\":\"02e915e7-7763-48d1-83bd-d4e940a1a368\"," - // + "\"key\":\"test-custom-type-key\"} ]}"; - // final ResourceKeyIdGraphQlResult customTypesResult = - // SphereJsonUtils.readObject(jsonStringCustomTypes, ResourceKeyIdGraphQlResult.class); - // - // final String jsonStringSupplyChannels = - // "{\"results\":[{\"id\":\"5c0516b5-f506-4b6a-b4d1-c06ca29ab7e1\"," - // + "\"key\":\"test-channel-key\"} ]}"; - // final ResourceKeyIdGraphQlResult supplyChannelsResult = - // SphereJsonUtils.readObject(jsonStringSupplyChannels, ResourceKeyIdGraphQlResult.class); - // - // when(sourceClient.execute(any(ResourceIdsGraphQlRequest.class))) - // .thenReturn(CompletableFuture.completedFuture(customTypesResult)) - // .thenReturn(CompletableFuture.completedFuture(supplyChannelsResult)); - // - // // test - // final CompletionStage> draftsFromPageStage = - // inventoryEntrySyncer.transform(inventoryPage); - // - // // assertions - // final List expectedResult = - // toInventoryEntryDrafts(sourceClient, referenceIdToKeyCache, inventoryPage).join(); - // final List referenceKeys = - // expectedResult.stream() - // .filter(inventoryEntry -> inventoryEntry.getSupplyChannel() != null) - // .filter(inventoryEntry -> inventoryEntry.getCustom() != null) - // .flatMap( - // inventoryEntry -> - // Stream.of( - // inventoryEntry.getCustom().getType().getId(), - // inventoryEntry.getSupplyChannel().getId())) - // .collect(Collectors.toList()); - // assertThat(referenceKeys).doesNotContainAnyElementsOf(referenceIds); - // assertThat(draftsFromPageStage).isCompletedWithValue(expectedResult); - // } - // - // @Test - // void syncWithError_ShouldCallErrorCallback() { - // // preparation: inventory entry with no key is synced - // final SphereClient sourceClient = mock(SphereClient.class); - // final SphereClient targetClient = mock(SphereClient.class); - // when(sourceClient.getConfig()).thenReturn(SphereApiConfig.of("source-project")); - // when(targetClient.getConfig()).thenReturn(SphereApiConfig.of("target-project")); - // final List inventoryEntries = - // Collections.singletonList( - // readObjectFromResource("inventory-no-sku.json", InventoryEntry.class)); - // - // final PagedQueryResult pagedQueryResult = mock(PagedQueryResult.class); - // when(pagedQueryResult.getResults()).thenReturn(inventoryEntries); - // when(sourceClient.execute(any(InventoryEntryQuery.class))) - // .thenReturn(CompletableFuture.completedFuture(pagedQueryResult)); - // - // mockResourceIdsGraphQlRequest( - // sourceClient, "4db98ea6-38dc-4ccb-b20f-466e1566567h", "customTypeKey"); - // mockResourceIdsGraphQlRequest( - // sourceClient, "1489488b-f737-4a9e-ba49-2d42d84c4c6f", "channelKey"); - // - // // test - // final InventoryEntrySyncer inventoryEntrySyncer = - // InventoryEntrySyncer.of(sourceClient, targetClient, mock(Clock.class)); - // inventoryEntrySyncer.sync(null, true).toCompletableFuture().join(); - // - // // assertion - // final LoggingEvent errorLog = syncerTestLogger.getAllLoggingEvents().get(1); - // assertThat(errorLog.getMessage()) - // .isEqualTo( - // "Error when trying to sync inventory entry. Existing key: <>. Update - // actions: []"); - // assertThat(errorLog.getThrowable().get().getMessage()) - // .isEqualTo( - // "InventoryEntryDraft doesn't have a SKU. Please make sure all inventory entry drafts - // have SKUs."); - // } + @Test + void of_ShouldCreateInventoryEntrySyncerInstance() { + // test + final InventoryEntrySyncer inventorySyncer = + InventoryEntrySyncer.of( + mock(ProjectApiRoot.class), mock(ProjectApiRoot.class), getMockedClock()); + + // assertions + assertThat(inventorySyncer).isNotNull(); + assertThat(inventorySyncer.getSync()).isInstanceOf(InventorySync.class); + } + + @Test + void transform_ShouldReplaceInventoryEntryReferenceIdsWithKeys() throws JsonProcessingException { + // preparation + final ProjectApiRoot sourceClient = mock(ProjectApiRoot.class); + final InventoryEntrySyncer inventoryEntrySyncer = + InventoryEntrySyncer.of(sourceClient, mock(ProjectApiRoot.class), getMockedClock()); + final List inventoryPage = + asList( + readObjectFromResource("inventory-sku-1.json", InventoryEntry.class), + readObjectFromResource("inventory-sku-2.json", InventoryEntry.class)); + final List referenceIds = + inventoryPage.stream() + .filter(inventoryEntry -> inventoryEntry.getSupplyChannel() != null) + .filter(inventoryEntry -> inventoryEntry.getCustom() != null) + .flatMap( + inventoryEntry -> + Stream.of( + inventoryEntry.getCustom().getType().getId(), + inventoryEntry.getSupplyChannel().getId())) + .collect(Collectors.toList()); + + final String jsonStringCustomTypes = + "{\"data\":{\"typeDefinitions\":{\"results\":[{\"id\":\"02e915e7-7763-48d1-83bd-d4e940a1a368\"," + + "\"key\":\"test-custom-type-key\"}]}}}"; + final GraphQLResponse customTypesResult = + readObject(jsonStringCustomTypes, GraphQLResponse.class); + + final String jsonStringSupplyChannels = + "{\"data\":{\"channels\":{\"results\":[{\"id\":\"5c0516b5-f506-4b6a-b4d1-c06ca29ab7e1\"," + + "\"key\":\"test-channel-key\"}]}}}"; + final GraphQLResponse supplyChannelsResult = + readObject(jsonStringSupplyChannels, GraphQLResponse.class); + + final ApiHttpResponse graphQLResponse = mock(ApiHttpResponse.class); + + when(graphQLResponse.getBody()).thenReturn(customTypesResult).thenReturn(supplyChannelsResult); + final ByProjectKeyGraphqlRequestBuilder byProjectKeyGraphqlRequestBuilder = mock(); + when(sourceClient.graphql()).thenReturn(byProjectKeyGraphqlRequestBuilder); + final ByProjectKeyGraphqlPost byProjectKeyGraphqlPost = mock(); + when(byProjectKeyGraphqlRequestBuilder.post(any(GraphQLRequest.class))) + .thenReturn(byProjectKeyGraphqlPost); + when(byProjectKeyGraphqlPost.execute()) + .thenReturn(CompletableFuture.completedFuture(graphQLResponse)); + + // test + final CompletionStage> draftsFromPageStage = + inventoryEntrySyncer.transform(inventoryPage); + + // assertions + final List expectedResult = + toInventoryEntryDrafts(sourceClient, referenceIdToKeyCache, inventoryPage).join(); + final List referenceKeys = + expectedResult.stream() + .filter(inventoryEntry -> inventoryEntry.getSupplyChannel() != null) + .filter(inventoryEntry -> inventoryEntry.getCustom() != null) + .flatMap( + inventoryEntry -> + Stream.of( + inventoryEntry.getCustom().getType().getId(), + inventoryEntry.getSupplyChannel().getId())) + .collect(Collectors.toList()); + assertThat(referenceKeys).doesNotContainAnyElementsOf(referenceIds); + assertThat(draftsFromPageStage).isCompletedWithValue(expectedResult); + } + + @Test + @Disabled("https://commercetools.atlassian.net/browse/DEVX-275") + void syncWithError_ShouldCallErrorCallback() throws JsonProcessingException { + // preparation: inventory entry with no key is synced + final ProjectApiRoot sourceClient = mock(ProjectApiRoot.class); + final ProjectApiRoot targetClient = mock(ProjectApiRoot.class); + + final List inventoryEntries = + Collections.singletonList( + readObjectFromResource("inventory-no-sku.json", InventoryEntry.class)); + + final ByProjectKeyInventoryRequestBuilder byProjectKeyInventoryRequestBuilder = mock(); + when(sourceClient.inventory()).thenReturn(byProjectKeyInventoryRequestBuilder); + final ByProjectKeyInventoryGet byProjectKeyInventoryGet = mock(); + when(byProjectKeyInventoryRequestBuilder.get()).thenReturn(byProjectKeyInventoryGet); + when(byProjectKeyInventoryGet.withSort(anyString())).thenReturn(byProjectKeyInventoryGet); + when(byProjectKeyInventoryGet.withLimit(anyInt())).thenReturn(byProjectKeyInventoryGet); + when(byProjectKeyInventoryGet.withWithTotal(anyBoolean())).thenReturn(byProjectKeyInventoryGet); + final ApiHttpResponse response = mock(ApiHttpResponse.class); + final InventoryPagedQueryResponse inventoryPagedQueryResponse = + InventoryPagedQueryResponseBuilder.of() + .results(inventoryEntries) + .limit(20L) + .offset(0L) + .count(1L) + .build(); + when(response.getBody()).thenReturn(inventoryPagedQueryResponse); + when(byProjectKeyInventoryGet.execute()) + .thenReturn(CompletableFuture.completedFuture(response)); + + mockResourceIdsGraphQlRequest( + sourceClient, "typeDefinitions", "4db98ea6-38dc-4ccb-b20f-466e1566567h", "customTypeKey"); + mockResourceIdsGraphQlRequest( + sourceClient, "channels", "1489488b-f737-4a9e-ba49-2d42d84c4c6f", "channelKey"); + + // test + final InventoryEntrySyncer inventoryEntrySyncer = + InventoryEntrySyncer.of(sourceClient, targetClient, mock(Clock.class)); + inventoryEntrySyncer.sync(null, true).toCompletableFuture().join(); + + // assertion + final LoggingEvent errorLog = syncerTestLogger.getAllLoggingEvents().get(1); + assertThat(errorLog.getMessage()) + .isEqualTo( + "Error when trying to sync inventory entry. Existing key: <>. Update actions: []"); + assertThat(errorLog.getThrowable().get().getMessage()) + .isEqualTo( + "InventoryEntryDraft doesn't have a SKU. Please make sure all inventory entry drafts have SKUs."); + } } diff --git a/src/test/java/com/commercetools/project/sync/util/TestUtils.java b/src/test/java/com/commercetools/project/sync/util/TestUtils.java index c44906f7..51debda3 100644 --- a/src/test/java/com/commercetools/project/sync/util/TestUtils.java +++ b/src/test/java/com/commercetools/project/sync/util/TestUtils.java @@ -12,6 +12,8 @@ import static org.mockito.Mockito.when; import com.commercetools.api.client.ByProjectKeyCustomObjectsPost; +import com.commercetools.api.client.ByProjectKeyGraphqlPost; +import com.commercetools.api.client.ByProjectKeyGraphqlRequestBuilder; import com.commercetools.api.client.ProjectApiRoot; import com.commercetools.api.defaultconfig.ApiRootBuilder; import com.commercetools.api.models.custom_object.CustomObject; @@ -20,7 +22,6 @@ import com.commercetools.api.models.error.ErrorResponseBuilder; import com.commercetools.api.models.graph_ql.GraphQLRequest; import com.commercetools.api.models.graph_ql.GraphQLResponse; -import com.commercetools.api.models.graph_ql.GraphQLResponseBuilder; import com.commercetools.project.sync.model.response.LastSyncCustomObject; import com.commercetools.sync.products.helpers.ProductSyncStatistics; import com.fasterxml.jackson.core.JsonProcessingException; @@ -291,14 +292,29 @@ public static Clock getMockedClock() { return clock; } - public static void mockResourceIdsGraphQlRequest(ProjectApiRoot client, String id, String key) { + public static void mockResourceIdsGraphQlRequest( + ProjectApiRoot client, String resource, String id, String key) { final String jsonResponseString = - "{\"results\":[{\"id\":\"" + id + "\"," + "\"key\":\"" + key + "\"}]}"; - final GraphQLResponse result = GraphQLResponseBuilder.of().data(jsonResponseString).build(); + "{\"data\":{\"" + + resource + + "\":{\"results\":[{\"id\":\"" + + id + + "\"," + + "\"key\":\"" + + key + + "\"}]}}}"; + final GraphQLResponse result = + JsonUtils.fromJsonString(jsonResponseString, GraphQLResponse.class); + + final ApiHttpResponse apiHttpResponse = mock(ApiHttpResponse.class); - final ApiHttpResponse apiHttpResponse = mock(ApiHttpResponse.class); when(apiHttpResponse.getBody()).thenReturn(result); - when(client.graphql().post(any(GraphQLRequest.class)).execute()) + final ByProjectKeyGraphqlRequestBuilder byProjectKeyGraphqlRequestBuilder = mock(); + when(client.graphql()).thenReturn(byProjectKeyGraphqlRequestBuilder); + final ByProjectKeyGraphqlPost byProjectKeyGraphqlPost = mock(); + when(byProjectKeyGraphqlRequestBuilder.post(any(GraphQLRequest.class))) + .thenReturn(byProjectKeyGraphqlPost); + when(byProjectKeyGraphqlPost.execute()) .thenReturn(CompletableFuture.completedFuture(apiHttpResponse)); }