Skip to content

Commit 63b65eb

Browse files
authored
Merge pull request #309 from commercetools/308-remove-attributes-product-syn
308: remove attributes product sync
2 parents dd0a3ce + 11a989c commit 63b65eb

35 files changed

Lines changed: 1566 additions & 352 deletions

docs/RELEASE_NOTES.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,23 @@
5656
[Javadoc](https://commercetools.github.io/commercetools-sync-java/v/v1.0.0-M14/) |
5757
[Jar](https://bintray.com/commercetools/maven/commercetools-sync-java/v1.0.0-M14)
5858
59+
**Bug Fixes** (1)
60+
**Product Sync** - Fixed a bug where the removed attributes in the source product variant draft were not being removed from the target variant. [#238](https://github.com/commercetools/commercetools-sync-java/issues/308)
5961
60-
**Enhancements** (6)
62+
**Enhancements** (7)
6163
- **Product Sync** - Products create and update requests are now issued in parallel. This should lead to a performance improvement. [#238](https://github.com/commercetools/commercetools-sync-java/issues/238)
6264
- **Commons** - Bumped `com.adarshr.test-logger` to 1.5.0.
6365
- **Commons** - Bumped `mockito` to 2.22.0.
6466
- **Commons** - Bumped `org.junit.jupiter:junit-jupiter-api` to 5.3.1.
6567
- **Commons** - Bumped `org.junit.jupiter:junit-jupiter-engine` to 5.3.1.
6668
- **Commons** - Bumped `org.junit.jupiter:junit-jupiter-params` to 5.3.1.
69+
- **Commons** - `UnorderedCollectionSyncUtils#buildRemoveUpdateActions ensures no `null` elements in the resulting list and ignores `null` keys now. [#238](https://github.com/commercetools/commercetools-sync-java/issues/308)
70+
71+
**Breaking Changes** (3)
72+
-- **Product Sync** - Products attributes are not validated anymore whether they are required or not. [#308](https://github.com/commercetools/commercetools-sync-java/issues/308)
73+
-- **Product Sync** - `AttributeMetaData#buildRemoveUpdateActions` now filters out `null` elements resulting from ``. [#308](https://github.com/commercetools/commercetools-sync-java/issues/308)
74+
-- **Product Sync** - `ProductVariantAttributeUpdateActionUtils#buildProductVariantAttributeUpdateAction` now takes a map of all meta data instead of the specific metadata entry. [#308](https://github.com/commercetools/commercetools-sync-java/issues/308)
75+
6776
-->
6877

6978
### v1.0.0-M13 - Sept 5, 2018

src/integration-test/java/com/commercetools/sync/integration/ctpprojectsource/products/ProductSyncIT.java

Lines changed: 108 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.commercetools.sync.products.ProductSyncOptionsBuilder;
66
import com.commercetools.sync.products.SyncFilter;
77
import com.commercetools.sync.products.helpers.ProductSyncStatistics;
8+
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
89
import com.fasterxml.jackson.databind.node.ObjectNode;
910
import io.sphere.sdk.categories.Category;
1011
import io.sphere.sdk.channels.Channel;
@@ -19,7 +20,9 @@
1920
import io.sphere.sdk.products.ProductVariantDraftBuilder;
2021
import io.sphere.sdk.products.attributes.AttributeDraft;
2122
import io.sphere.sdk.products.commands.ProductCreateCommand;
23+
import io.sphere.sdk.products.commands.updateactions.SetAttribute;
2224
import io.sphere.sdk.products.commands.updateactions.SetAttributeInAllVariants;
25+
import io.sphere.sdk.products.queries.ProductByKeyGet;
2326
import io.sphere.sdk.producttypes.ProductType;
2427
import io.sphere.sdk.states.State;
2528
import io.sphere.sdk.states.StateType;
@@ -57,6 +60,7 @@
5760
import static com.commercetools.sync.integration.commons.utils.TaxCategoryITUtils.createTaxCategory;
5861
import static com.commercetools.sync.integration.inventories.utils.InventoryITUtils.SUPPLY_CHANNEL_KEY_1;
5962
import static com.commercetools.sync.products.ActionGroup.ATTRIBUTES;
63+
import static com.commercetools.sync.products.ProductSyncMockUtils.PRODUCT_KEY_1_CHANGED_ATTRIBUTES_RESOURCE_PATH;
6064
import static com.commercetools.sync.products.ProductSyncMockUtils.PRODUCT_KEY_1_CHANGED_RESOURCE_PATH;
6165
import static com.commercetools.sync.products.ProductSyncMockUtils.PRODUCT_KEY_1_CHANGED_WITH_PRICES_RESOURCE_PATH;
6266
import static com.commercetools.sync.products.ProductSyncMockUtils.PRODUCT_KEY_1_RESOURCE_PATH;
@@ -284,6 +288,7 @@ public void sync_withPriceReferences_ShouldUpdateProducts() {
284288

285289
@Test
286290
public void sync_withProductTypeReference_ShouldUpdateProducts() {
291+
// Preparation
287292
// Create custom options with whitelisting and action filter callback..
288293
final ProductSyncOptions customSyncOptions =
289294
ProductSyncOptionsBuilder.of(CTP_TARGET_CLIENT)
@@ -294,8 +299,6 @@ public void sync_withProductTypeReference_ShouldUpdateProducts() {
294299
.build();
295300
final ProductSync customSync = new ProductSync(customSyncOptions);
296301

297-
298-
299302
// Create 3 existing products in target project with keys (productKey1, productKey2 and productKey3)
300303
final ProductDraft existingProductDraft = createProductDraft(PRODUCT_KEY_1_RESOURCE_PATH,
301304
targetProductType.toReference(), targetTaxCategory.toReference(), targetProductState.toReference(),
@@ -305,14 +308,14 @@ public void sync_withProductTypeReference_ShouldUpdateProducts() {
305308
final ProductDraft existingProductDraft2 = createProductDraft(PRODUCT_KEY_2_RESOURCE_PATH,
306309
targetProductType.toReference(), targetTaxCategory.toReference(), targetProductState.toReference(),
307310
targetCategoryReferencesWithIds, createRandomCategoryOrderHints(targetCategoryReferencesWithIds));
308-
final Product targetProductWithKey2 = CTP_TARGET_CLIENT.execute(ProductCreateCommand.of(existingProductDraft2))
309-
.toCompletableFuture().join();
311+
CTP_TARGET_CLIENT.execute(ProductCreateCommand.of(existingProductDraft2))
312+
.toCompletableFuture().join();
310313

311314
final ProductDraft existingProductDraft3 = createProductDraftBuilder(PRODUCT_KEY_2_RESOURCE_PATH,
312315
targetProductType.toReference())
313316
.slug(LocalizedString.ofEnglish("newSlug3"))
314317
.key("productKey3")
315-
.masterVariant(ProductVariantDraftBuilder.of().key("v3").build())
318+
.masterVariant(ProductVariantDraftBuilder.of().key("v3").sku("s3").build())
316319
.taxCategory(null)
317320
.state(null)
318321
.categories(Collections.emptySet())
@@ -325,7 +328,7 @@ public void sync_withProductTypeReference_ShouldUpdateProducts() {
325328
sourceProductType.toReference(), sourceTaxCategory.toReference(), sourceProductState.toReference(),
326329
sourceCategoryReferencesWithIds, createRandomCategoryOrderHints(sourceCategoryReferencesWithIds));
327330
final Product product2 = CTP_SOURCE_CLIENT.execute(ProductCreateCommand.of(newProductDraft2))
328-
.toCompletableFuture().join();
331+
.toCompletableFuture().join();
329332
final ProductDraft newProductDraft3 = createProductDraftBuilder(PRODUCT_KEY_2_RESOURCE_PATH,
330333
sourceProductType.toReference())
331334
.slug(LocalizedString.ofEnglish("newSlug3"))
@@ -337,25 +340,27 @@ public void sync_withProductTypeReference_ShouldUpdateProducts() {
337340
.categoryOrderHints(null)
338341
.build();
339342
final Product product3 = CTP_SOURCE_CLIENT.execute(ProductCreateCommand.of(newProductDraft3))
340-
.toCompletableFuture().join();
343+
.toCompletableFuture().join();
341344

342345

346+
// Create existing product with productKey1 in source project that has references to products with keys
347+
// (productKey2 and productKey3).
348+
343349
final ObjectNode productReferenceValue1 = getProductReferenceWithId(product2.getId());
344350
final ObjectNode productReferenceValue2 = getProductReferenceWithId(product3.getId());
345351

346352
final AttributeDraft productRefAttr = AttributeDraft.of("product-reference", productReferenceValue1);
347353
final AttributeDraft productSetRefAttr =
348354
getProductReferenceSetAttributeDraft("product-reference-set", productReferenceValue1,
349355
productReferenceValue2);
350-
final List<AttributeDraft> attributeDrafts = Arrays.asList(productRefAttr, productSetRefAttr);
356+
final List<AttributeDraft> attributeDrafts = existingProductDraft.getMasterVariant().getAttributes();
357+
attributeDrafts.addAll(Arrays.asList(productRefAttr, productSetRefAttr));
351358

352359
final ProductVariantDraft masterVariant = ProductVariantDraftBuilder.of()
353360
.key("v1")
354361
.sku("s1")
355362
.attributes(attributeDrafts).build();
356363

357-
// Create existing product with productKey1 in source project that has references to products with keys
358-
// (productKey2 and productKey3).
359364
final ProductDraft newProductDraftWithProductReference =
360365
createProductDraftBuilder(PRODUCT_KEY_1_CHANGED_RESOURCE_PATH, sourceProductType.toReference())
361366
.masterVariant(masterVariant)
@@ -367,31 +372,107 @@ public void sync_withProductTypeReference_ShouldUpdateProducts() {
367372
CTP_SOURCE_CLIENT.execute(ProductCreateCommand.of(newProductDraftWithProductReference))
368373
.toCompletableFuture().join();
369374

375+
376+
// Test
370377
final List<Product> products = CTP_SOURCE_CLIENT.execute(buildProductQuery())
371378
.toCompletableFuture().join().getResults();
372-
373379
final List<ProductDraft> productDrafts = replaceProductsReferenceIdsWithKeys(products);
374-
375380
final ProductSyncStatistics syncStatistics = customSync.sync(productDrafts).toCompletableFuture().join();
376381

382+
383+
// Assertion
377384
assertThat(syncStatistics).hasValues(3, 0, 1, 0);
378385
assertThat(errorCallBackMessages).isEmpty();
379386
assertThat(errorCallBackExceptions).isEmpty();
380387
assertThat(warningCallBackMessages).isEmpty();
381-
assertThat(updateActions).hasSize(2);
382-
383-
final UpdateAction<Product> productReferenceAction = updateActions.get(0);
384-
assertThat(productReferenceAction).isExactlyInstanceOf(SetAttributeInAllVariants.class);
385-
final SetAttributeInAllVariants action1 = (SetAttributeInAllVariants) productReferenceAction;
386-
assertThat(action1.getName()).isEqualTo("product-reference");
387-
assertThat(action1.getValue()).isNotNull();
388-
assertThat(action1.getValue().get("id").asText()).isEqualTo(targetProductWithKey2.getId());
389-
390-
final UpdateAction<Product> productReferenceSetAction = updateActions.get(1);
391-
assertThat(productReferenceSetAction).isExactlyInstanceOf(SetAttributeInAllVariants.class);
392-
final SetAttributeInAllVariants action2 = (SetAttributeInAllVariants) productReferenceSetAction;
393-
assertThat(action2.getName()).isEqualTo("product-reference-set");
394-
assertThat(action2.getValue()).isNotNull();
395-
assertThat(action2.getValue().isArray()).isTrue();
388+
389+
final Product targetProduct2 = CTP_TARGET_CLIENT.execute(ProductByKeyGet.of("productKey2"))
390+
.toCompletableFuture()
391+
.join();
392+
393+
final Product targetProduct3 = CTP_TARGET_CLIENT.execute(ProductByKeyGet.of("productKey3"))
394+
.toCompletableFuture()
395+
.join();
396+
397+
final ObjectNode targetProductReferenceValue2 = getProductReferenceWithId(targetProduct2.getId());
398+
final ObjectNode targetProductReferenceValue3 = getProductReferenceWithId(targetProduct3.getId());
399+
400+
final AttributeDraft targetProductRefAttr =
401+
AttributeDraft.of("product-reference", targetProductReferenceValue2);
402+
final AttributeDraft targetProductSetRefAttr =
403+
getProductReferenceSetAttributeDraft("product-reference-set", targetProductReferenceValue2,
404+
targetProductReferenceValue3);
405+
406+
assertThat(updateActions).containsExactlyInAnyOrder(
407+
SetAttributeInAllVariants.of(targetProductRefAttr.getName(), targetProductRefAttr.getValue(), true),
408+
SetAttributeInAllVariants.of(targetProductSetRefAttr.getName(), targetProductSetRefAttr.getValue(), true)
409+
);
410+
}
411+
412+
@Test
413+
public void sync_withChangedAttributes_ShouldUpdateProducts() {
414+
// Preparation
415+
// Create custom options with whitelisting and action filter callback..
416+
final ProductSyncOptions customSyncOptions =
417+
ProductSyncOptionsBuilder.of(CTP_TARGET_CLIENT)
418+
.errorCallback(this::errorCallback)
419+
.warningCallback(warningCallBackMessages::add)
420+
.beforeUpdateCallback(this::beforeUpdateCallback)
421+
.syncFilter(SyncFilter.ofWhiteList(ATTRIBUTES))
422+
.build();
423+
final ProductSync customSync = new ProductSync(customSyncOptions);
424+
425+
// Create existing products in target project with keys (productKey1)
426+
final ProductDraft existingProductDraft = createProductDraft(PRODUCT_KEY_1_RESOURCE_PATH,
427+
targetProductType.toReference(), targetTaxCategory.toReference(), targetProductState.toReference(),
428+
targetCategoryReferencesWithIds, createRandomCategoryOrderHints(targetCategoryReferencesWithIds));
429+
CTP_TARGET_CLIENT.execute(ProductCreateCommand.of(existingProductDraft)).toCompletableFuture().join();
430+
431+
432+
// Create existing product with productKey1 in source project with changed attributes
433+
final ProductDraft newProductDraftWithProductReference =
434+
createProductDraftBuilder(PRODUCT_KEY_1_CHANGED_ATTRIBUTES_RESOURCE_PATH, sourceProductType.toReference())
435+
.taxCategory(sourceTaxCategory.toReference())
436+
.state(sourceProductState.toReference())
437+
.categories(Collections.emptySet())
438+
.categoryOrderHints(null)
439+
.build();
440+
CTP_SOURCE_CLIENT.execute(ProductCreateCommand.of(newProductDraftWithProductReference))
441+
.toCompletableFuture().join();
442+
443+
444+
// Test
445+
final List<Product> products = CTP_SOURCE_CLIENT.execute(buildProductQuery())
446+
.toCompletableFuture().join().getResults();
447+
final List<ProductDraft> productDrafts = replaceProductsReferenceIdsWithKeys(products);
448+
final ProductSyncStatistics syncStatistics = customSync.sync(productDrafts).toCompletableFuture().join();
449+
450+
451+
// Assertion
452+
assertThat(syncStatistics).hasValues(1, 0, 1, 0);
453+
assertThat(errorCallBackMessages).isEmpty();
454+
assertThat(errorCallBackExceptions).isEmpty();
455+
assertThat(warningCallBackMessages).isEmpty();
456+
457+
final AttributeDraft priceInfoAttrDraft =
458+
AttributeDraft.of("priceInfo", JsonNodeFactory.instance.textNode("100/kg"));
459+
final AttributeDraft angebotAttrDraft =
460+
AttributeDraft.of("angebot", JsonNodeFactory.instance.textNode("big discount"));
461+
462+
assertThat(updateActions).containsExactlyInAnyOrder(
463+
SetAttributeInAllVariants.of(priceInfoAttrDraft, true),
464+
SetAttribute.of(1, angebotAttrDraft, true),
465+
SetAttributeInAllVariants.ofUnsetAttribute("size", true),
466+
SetAttributeInAllVariants.ofUnsetAttribute("rinderrasse", true),
467+
SetAttributeInAllVariants.ofUnsetAttribute("herkunft", true),
468+
SetAttributeInAllVariants.ofUnsetAttribute("teilstueck", true),
469+
SetAttributeInAllVariants.ofUnsetAttribute("fuetterung", true),
470+
SetAttributeInAllVariants.ofUnsetAttribute("reifung", true),
471+
SetAttributeInAllVariants.ofUnsetAttribute("haltbarkeit", true),
472+
SetAttributeInAllVariants.ofUnsetAttribute("verpackung", true),
473+
SetAttributeInAllVariants.ofUnsetAttribute("anlieferung", true),
474+
SetAttributeInAllVariants.ofUnsetAttribute("zubereitung", true),
475+
SetAttribute.ofUnsetAttribute(1, "localisedText", true)
476+
);
396477
}
397478
}

0 commit comments

Comments
 (0)