Skip to content
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
Expand Up @@ -2,6 +2,7 @@

import static com.commercetools.api.models.common.LocalizedString.ofEnglish;
import static com.commercetools.sync.commons.asserts.statistics.AssertionsForStatistics.assertThat;
import static com.commercetools.sync.integration.commons.utils.CustomerITUtils.ensureStore;
import static com.commercetools.sync.integration.commons.utils.ShoppingListITUtils.*;
import static com.commercetools.sync.integration.commons.utils.TestClientUtils.CTP_SOURCE_CLIENT;
import static com.commercetools.sync.integration.commons.utils.TestClientUtils.CTP_TARGET_CLIENT;
Expand Down Expand Up @@ -36,6 +37,7 @@
import com.commercetools.api.models.shopping_list.TextLineItem;
import com.commercetools.api.models.shopping_list.TextLineItemDraft;
import com.commercetools.api.models.shopping_list.TextLineItemDraftBuilder;
import com.commercetools.api.models.store.StoreResourceIdentifier;
import com.commercetools.api.models.type.CustomFields;
import com.commercetools.api.models.type.CustomFieldsDraftBuilder;
import com.commercetools.api.models.type.TypeReference;
Expand Down Expand Up @@ -521,4 +523,62 @@ private List<ShoppingListLineItemDraft> setNullToAddedAtValuesForLineItems(
ShoppingListLineItemDraftBuilder.of(lineItemDraft).addedAt(null).build())
.collect(toList());
}

@Test
void sync_WithStoreChange_ShouldUpdateShoppingListStore() {
// Create the store that will be referenced
ensureStore(CTP_TARGET_CLIENT, "different-store-key");

// Create a shopping list draft with a different store
final ShoppingListDraft modifiedDraft =
ShoppingListDraftBuilder.of(shoppingListDraftSampleCarrotCake)
.store(
storeResourceIdentifierBuilder ->
storeResourceIdentifierBuilder.key("different-store-key"))
.build();

final ShoppingListSyncStatistics shoppingListSyncStatistics =
shoppingListSync.sync(singletonList(modifiedDraft)).toCompletableFuture().join();

assertThat(errorMessages).isEmpty();
assertThat(warningMessages).isEmpty();
assertThat(exceptions).isEmpty();

// Verify that a setStore update action was generated
assertThat(updateActionList)
.anySatisfy(
action -> {
assertThat(action.getAction()).isEqualTo("setStore");
});

assertThat(shoppingListSyncStatistics).hasValues(1, 0, 1, 0);
}

@Test
void sync_WithNullStore_ShouldUpdateShoppingListStoreToNull() {
// Create a shopping list draft with null store
final StoreResourceIdentifier nullStore = null;
final ShoppingListDraft modifiedDraft =
ShoppingListDraftBuilder.of(shoppingListDraftSampleCarrotCake).store(nullStore).build();

final ShoppingListSyncStatistics shoppingListSyncStatistics =
shoppingListSync.sync(singletonList(modifiedDraft)).toCompletableFuture().join();

assertThat(errorMessages).isEmpty();
assertThat(warningMessages).isEmpty();
assertThat(exceptions).isEmpty();

// If the original had a store and we set it to null, we should see an update
if (shoppingListSampleCarrotCake.getStore() != null) {
assertThat(updateActionList)
.anySatisfy(
action -> {
assertThat(action.getAction()).isEqualTo("setStore");
});
assertThat(shoppingListSyncStatistics).hasValues(1, 0, 1, 0);
} else {
// If both are null, no update should occur
assertThat(shoppingListSyncStatistics).hasValues(1, 0, 0, 0);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import com.commercetools.api.models.customer.CustomerResourceIdentifierBuilder;
import com.commercetools.api.models.shopping_list.ShoppingListDraft;
import com.commercetools.api.models.shopping_list.ShoppingListDraftBuilder;
import com.commercetools.api.models.store.StoreResourceIdentifier;
import com.commercetools.api.models.store.StoreResourceIdentifierBuilder;
import com.commercetools.sync.commons.exceptions.ReferenceResolutionException;
import com.commercetools.sync.commons.helpers.CustomReferenceResolver;
import com.commercetools.sync.services.CustomerService;
Expand All @@ -32,6 +34,9 @@ public final class ShoppingListReferenceResolver
"Failed to resolve customer resource identifier on "
+ "ShoppingListDraft with key:'%s'. Reason: %s";
static final String CUSTOMER_DOES_NOT_EXIST = "Customer with key '%s' doesn't exist.";
static final String FAILED_TO_RESOLVE_STORE_REFERENCE =
"Failed to resolve store resource identifier on "
+ "ShoppingListDraft with key:'%s'. Reason: %s";
static final String FAILED_TO_RESOLVE_CUSTOM_TYPE =
"Failed to resolve custom type reference on ShoppingListDraft with key:'%s'. ";

Expand Down Expand Up @@ -66,9 +71,9 @@ public ShoppingListReferenceResolver(
}

/**
* Given a {@link ShoppingListDraft} this method attempts to resolve the customer and custom type
* references to return a {@link java.util.concurrent.CompletionStage} which contains a new
* instance of the draft with the resolved references.
* Given a {@link ShoppingListDraft} this method attempts to resolve the customer, store and
* custom type references to return a {@link java.util.concurrent.CompletionStage} which contains
* a new instance of the draft with the resolved references.
*
* @param shoppingListDraft the shoppingListDraft to resolve its references.
* @return a {@link java.util.concurrent.CompletionStage} that contains as a result a new
Expand All @@ -79,6 +84,7 @@ public ShoppingListReferenceResolver(
public CompletionStage<ShoppingListDraft> resolveReferences(
@Nonnull final ShoppingListDraft shoppingListDraft) {
return resolveCustomerReference(ShoppingListDraftBuilder.of(shoppingListDraft))
.thenCompose(this::resolveStoreReference)
.thenCompose(this::resolveCustomTypeReference)
.thenCompose(this::resolveLineItemReferences)
.thenCompose(this::resolveTextLineItemReferences)
Expand Down Expand Up @@ -136,6 +142,32 @@ private CompletionStage<ShoppingListDraftBuilder> fetchAndResolveCustomerReferen
}));
}

@Nonnull
protected CompletionStage<ShoppingListDraftBuilder> resolveStoreReference(
@Nonnull final ShoppingListDraftBuilder draftBuilder) {

final StoreResourceIdentifier storeResourceIdentifier = draftBuilder.getStore();
if (storeResourceIdentifier != null && storeResourceIdentifier.getId() == null) {
try {
final String storeKey = getKeyFromResourceIdentifier(storeResourceIdentifier);
return completedFuture(
draftBuilder.store(StoreResourceIdentifierBuilder.of().key(storeKey).build()));
} catch (ReferenceResolutionException referenceResolutionException) {
return exceptionallyCompletedFuture(
new ReferenceResolutionException(
format(
FAILED_TO_RESOLVE_STORE_REFERENCE,
draftBuilder.getKey(),
referenceResolutionException.getMessage())));
}
} else if (storeResourceIdentifier != null && storeResourceIdentifier.getId() != null) {
return completedFuture(
draftBuilder.store(
StoreResourceIdentifierBuilder.of().id(storeResourceIdentifier.getId()).build()));
}
return completedFuture(draftBuilder);
}

@Nonnull
protected CompletionStage<ShoppingListDraftBuilder> resolveCustomTypeReference(
@Nonnull final ShoppingListDraftBuilder draftBuilder) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import com.commercetools.api.models.shopping_list.TextLineItem;
import com.commercetools.api.models.shopping_list.TextLineItemDraft;
import com.commercetools.api.models.shopping_list.TextLineItemDraftBuilder;
import com.commercetools.api.models.store.StoreResourceIdentifier;
import com.commercetools.api.models.store.StoreResourceIdentifierBuilder;
import com.commercetools.sync.commons.utils.ReferenceIdToKeyCache;
import java.util.List;
import java.util.Objects;
Expand Down Expand Up @@ -48,6 +50,11 @@ public final class ShoppingListReferenceResolutionUtils {
* <td>{@link com.commercetools.api.models.customer.CustomerResourceIdentifier}</td>
* </tr>
* <tr>
* <td>store</td>
* <td>{@link com.commercetools.api.models.store.StoreKeyReference}</td>
* <td>{@link com.commercetools.api.models.store.StoreResourceIdentifier}</td>
* </tr>
* <tr>
* <td>custom.type</td>
* <td>{@link com.commercetools.api.models.type.TypeReference}</td>
* <td>{@link com.commercetools.api.models.type.TypeResourceIdentifier}</td>
Expand Down Expand Up @@ -107,6 +114,11 @@ public static List<ShoppingListDraft> mapToShoppingListDrafts(
* <td>{@link com.commercetools.api.models.customer.CustomerResourceIdentifier}</td>
* </tr>
* <tr>
* <td>store</td>
* <td>{@link com.commercetools.api.models.store.StoreKeyReference}</td>
* <td>{@link com.commercetools.api.models.store.StoreResourceIdentifier}</td>
* </tr>
* <tr>
* <td>custom.type</td>
* <td>{@link com.commercetools.api.models.type.TypeReference}</td>
* <td>{@link com.commercetools.api.models.type.TypeResourceIdentifier}</td>
Expand Down Expand Up @@ -139,16 +151,18 @@ public static ShoppingListDraft mapToShoppingListDraft(
@Nonnull final ShoppingList shoppingList,
@Nonnull final ReferenceIdToKeyCache referenceIdToKeyCache) {

final CustomerResourceIdentifier resourceIdentifierWithKey =
final CustomerResourceIdentifier customerResourceIdentifierWithKey =
getResourceIdentifierWithKey(
shoppingList.getCustomer(),
referenceIdToKeyCache,
(id, key) -> CustomerResourceIdentifierBuilder.of().id(id).key(key).build());

return ShoppingListDraftBuilder.of()
.name(shoppingList.getName())
.description(shoppingList.getDescription())
.key(shoppingList.getKey())
.customer(resourceIdentifierWithKey)
.customer(customerResourceIdentifierWithKey)
.store(mapToStoreResourceIdentifier(shoppingList))
.slug(shoppingList.getSlug())
.lineItems(mapToLineItemDrafts(shoppingList.getLineItems(), referenceIdToKeyCache))
.textLineItems(
Expand Down Expand Up @@ -217,5 +231,14 @@ private static TextLineItemDraft mapToTextLineItemDraft(
.build();
}

@Nullable
private static StoreResourceIdentifier mapToStoreResourceIdentifier(
@Nonnull final ShoppingList shoppingList) {
if (shoppingList.getStore() != null) {
return StoreResourceIdentifierBuilder.of().key(shoppingList.getStore().getKey()).build();
}
return null;
}

private ShoppingListReferenceResolutionUtils() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public static List<ShoppingListUpdateAction> buildActions(
buildSetDescriptionUpdateAction(oldShoppingList, newShoppingList),
buildSetAnonymousIdUpdateAction(oldShoppingList, newShoppingList),
buildSetCustomerUpdateAction(oldShoppingList, newShoppingList),
buildSetStoreUpdateAction(oldShoppingList, newShoppingList),
buildSetDeleteDaysAfterLastModificationUpdateAction(oldShoppingList, newShoppingList));

updateActions.addAll(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.commercetools.api.models.shopping_list.ShoppingListSetDeleteDaysAfterLastModificationActionBuilder;
import com.commercetools.api.models.shopping_list.ShoppingListSetDescriptionActionBuilder;
import com.commercetools.api.models.shopping_list.ShoppingListSetSlugActionBuilder;
import com.commercetools.api.models.shopping_list.ShoppingListSetStoreActionBuilder;
import com.commercetools.api.models.shopping_list.ShoppingListUpdateAction;
import java.util.Optional;
import javax.annotation.Nonnull;
Expand Down Expand Up @@ -116,6 +117,38 @@ public static Optional<ShoppingListUpdateAction> buildSetCustomerUpdateAction(
.build());
}

/**
* Compares the store references of a {@link ShoppingList} and a {@link ShoppingListDraft} and
* returns an {@link ShoppingListUpdateAction} as a result in an {@link java.util.Optional}. If
* both the {@link ShoppingList} and the {@link ShoppingListDraft} have the same store, then no
* update action is needed and hence an empty {@link java.util.Optional} is returned.
*
* <p>Note: This method compares store keys since {@link
* com.commercetools.api.models.store.StoreKeyReference} contains the key directly.
*
* @param oldShoppingList the shopping list which should be updated.
* @param newShoppingList the shopping list draft which holds the new store.
* @return A filled optional with the update action or an empty optional if the stores are
* identical.
*/
@Nonnull
public static Optional<ShoppingListUpdateAction> buildSetStoreUpdateAction(
@Nonnull final ShoppingList oldShoppingList,
@Nonnull final ShoppingListDraft newShoppingList) {

final String oldStoreKey =
oldShoppingList.getStore() != null ? oldShoppingList.getStore().getKey() : null;
final String newStoreKey =
newShoppingList.getStore() != null && newShoppingList.getStore().getKey() != null
? newShoppingList.getStore().getKey()
: (newShoppingList.getStore() != null ? newShoppingList.getStore().getId() : null);

return buildUpdateAction(
oldStoreKey,
newStoreKey,
() -> ShoppingListSetStoreActionBuilder.of().store(newShoppingList.getStore()).build());
}

/**
* Compares the anonymousIds of {@link ShoppingList} and a {@link ShoppingListDraft} and returns
* an {@link ShoppingListUpdateAction} as a result in an {@link java.util.Optional}. If both the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@
import com.commercetools.api.models.shopping_list.ShoppingListSetDeleteDaysAfterLastModificationAction;
import com.commercetools.api.models.shopping_list.ShoppingListSetDescriptionAction;
import com.commercetools.api.models.shopping_list.ShoppingListSetSlugAction;
import com.commercetools.api.models.shopping_list.ShoppingListSetStoreAction;
import com.commercetools.api.models.shopping_list.ShoppingListUpdateAction;
import com.commercetools.api.models.store.StoreKeyReference;
import com.commercetools.api.models.store.StoreKeyReferenceBuilder;
import com.commercetools.api.models.store.StoreResourceIdentifier;
import com.commercetools.api.models.store.StoreResourceIdentifierBuilder;
import java.util.Locale;
import java.util.Optional;
import java.util.UUID;
Expand Down Expand Up @@ -351,4 +356,94 @@ void buildSetAnonymousId_WithSameValues_ShouldNotBuildUpdateActions() {
assertThat(setDeleteDaysUpdateAction)
.containsInstanceOf(ShoppingListSetDeleteDaysAfterLastModificationAction.class);
}

@Test
void buildSetStoreUpdateAction_WithDifferentStoreKeys_ShouldBuildUpdateAction() {
final StoreKeyReference oldStoreReference =
StoreKeyReferenceBuilder.of().key("old-store-key").build();
final ShoppingList oldShoppingList = mock(ShoppingList.class);
when(oldShoppingList.getStore()).thenReturn(oldStoreReference);

final StoreResourceIdentifier newStoreIdentifier =
StoreResourceIdentifierBuilder.of().key("new-store-key").build();
final ShoppingListDraft newShoppingList = mock(ShoppingListDraft.class);
when(newShoppingList.getStore()).thenReturn(newStoreIdentifier);

final ShoppingListUpdateAction setStoreUpdateAction =
ShoppingListUpdateActionUtils.buildSetStoreUpdateAction(oldShoppingList, newShoppingList)
.orElse(null);

assertThat(setStoreUpdateAction).isNotNull();
assertThat(setStoreUpdateAction.getAction()).isEqualTo("setStore");
assertThat(((ShoppingListSetStoreAction) setStoreUpdateAction).getStore())
.isEqualTo(newStoreIdentifier);
}

@Test
void buildSetStoreUpdateAction_WithSameStoreKeys_ShouldNotBuildUpdateAction() {
final StoreKeyReference oldStoreReference =
StoreKeyReferenceBuilder.of().key("same-store-key").build();
final ShoppingList oldShoppingList = mock(ShoppingList.class);
when(oldShoppingList.getStore()).thenReturn(oldStoreReference);

final StoreResourceIdentifier newStoreIdentifier =
StoreResourceIdentifierBuilder.of().key("same-store-key").build();
final ShoppingListDraft newShoppingList = mock(ShoppingListDraft.class);
when(newShoppingList.getStore()).thenReturn(newStoreIdentifier);

final Optional<ShoppingListUpdateAction> setStoreUpdateAction =
ShoppingListUpdateActionUtils.buildSetStoreUpdateAction(oldShoppingList, newShoppingList);

assertThat(setStoreUpdateAction).isNotPresent();
}

@Test
void buildSetStoreUpdateAction_WithNullOldStore_ShouldBuildUpdateAction() {
final ShoppingList oldShoppingList = mock(ShoppingList.class);
when(oldShoppingList.getStore()).thenReturn(null);

final StoreResourceIdentifier newStoreIdentifier =
StoreResourceIdentifierBuilder.of().key("new-store-key").build();
final ShoppingListDraft newShoppingList = mock(ShoppingListDraft.class);
when(newShoppingList.getStore()).thenReturn(newStoreIdentifier);

final ShoppingListUpdateAction setStoreUpdateAction =
ShoppingListUpdateActionUtils.buildSetStoreUpdateAction(oldShoppingList, newShoppingList)
.orElse(null);

assertThat(setStoreUpdateAction).isNotNull();
assertThat(setStoreUpdateAction.getAction()).isEqualTo("setStore");
}

@Test
void buildSetStoreUpdateAction_WithNullNewStore_ShouldBuildUpdateAction() {
final StoreKeyReference oldStoreReference =
StoreKeyReferenceBuilder.of().key("old-store-key").build();
final ShoppingList oldShoppingList = mock(ShoppingList.class);
when(oldShoppingList.getStore()).thenReturn(oldStoreReference);

final ShoppingListDraft newShoppingList = mock(ShoppingListDraft.class);
when(newShoppingList.getStore()).thenReturn(null);

final ShoppingListUpdateAction setStoreUpdateAction =
ShoppingListUpdateActionUtils.buildSetStoreUpdateAction(oldShoppingList, newShoppingList)
.orElse(null);

assertThat(setStoreUpdateAction).isNotNull();
assertThat(setStoreUpdateAction.getAction()).isEqualTo("setStore");
}

@Test
void buildSetStoreUpdateAction_WithBothNull_ShouldNotBuildUpdateAction() {
final ShoppingList oldShoppingList = mock(ShoppingList.class);
when(oldShoppingList.getStore()).thenReturn(null);

final ShoppingListDraft newShoppingList = mock(ShoppingListDraft.class);
when(newShoppingList.getStore()).thenReturn(null);

final Optional<ShoppingListUpdateAction> setStoreUpdateAction =
ShoppingListUpdateActionUtils.buildSetStoreUpdateAction(oldShoppingList, newShoppingList);

assertThat(setStoreUpdateAction).isNotPresent();
}
}
Loading
Loading