def test_process_does_not_modify_title_when_the_google_product_category_is_in_the_config_but_no_keywords( self): original_title = 'Some title with no target keywords in the middle' original_data = requests_bodies.build_request_body( properties_to_be_updated={ 'title': 'Some title with no target keywords in the middle', 'googleProductCategory': 'ファッション・アクセサリー > ジュエリー > 腕時計' }) optimized_data, optimization_result = self.optimizer.process( original_data, 'test') product = optimized_data['entries'][0]['product'] self.assertEqual(original_title, product['title']) self.assertEqual(0, optimization_result.num_of_products_optimized)
def test_process_sets_product_tracking_field_to_sanitized_when_title_truncated( self): original_data = requests_bodies.build_request_body( properties_to_be_updated={ 'title': 'a' * (title_length_optimizer._MAX_TITLE_LENGTH * 2) }) tracking_field = 'customLabel4' with mock.patch.dict('os.environ', {'PRODUCT_TRACKING_FIELD': tracking_field}): optimized_data, _ = self.optimizer.process(original_data) product = optimized_data['entries'][0]['product'] self.assertEqual(enums.TrackingTag.SANITIZED.value, product[tracking_field])
def test_adult_optimizer_does_nothing_if_adult_tokens_in_description_but_category_is_not_adult( self, is_adult, test_description, test_google_product_category): original_data = requests_bodies.build_request_body( properties_to_be_updated={ 'adult': is_adult, 'description': test_description, 'googleProductCategory': test_google_product_category }) optimized_data, optimization_result = self.optimizer.process( original_data, 'test') product = optimized_data['entries'][0]['product'] self.assertEqual(False, product['adult']) self.assertEqual(0, optimization_result.num_of_products_optimized)
def test_set_optimization_tracking_sets_tracking_field_sanitized_optimized_when_product_sanitized_then_optimized( self): data = requests_bodies.build_request_body() dummy_optimizer = DummyOptimizer() dummy_sanitizer = DummySanitizer() tracking_field = 'customLabel4' with mock.patch.dict('os.environ', {'PRODUCT_TRACKING_FIELD': tracking_field}): optimized_data, _ = dummy_optimizer.process(data) sanitized_data, _ = dummy_sanitizer.process(optimized_data) sanitized_product = sanitized_data['entries'][0]['product'] self.assertNotEqual(base_optimizer.SANITIZED_AND_OPTIMIZED, sanitized_product[tracking_field])
def test_mine_and_insert_attributes_for_batch_mines_womens_from_female_product_type( self): product_data = requests_bodies.build_request_body( properties_to_be_updated={ 'offerId': 'product-1', 'title': 'dummy title', 'googleProductCategory': 'Apparel & Accessories > Shoes', 'productTypes': ['Apparel & Accessories', 'Women\'s', 'Shoes'] }, properties_to_be_removed=['gender']) miner = attribute_miner.AttributeMiner('test', constants.DEFAULT_COUNTRY) mined_attributes = miner.mine_and_insert_attributes_for_batch(product_data) self.assertIn("Women's", mined_attributes['product-1'].get('gender'))
def test_mine_and_insert_attributes_does_not_inserts_colors_into_color_field_if_color_field_not_empty( self): product_data = requests_bodies.build_request_body( properties_to_be_updated={ 'offerId': 'product-1', 'title': 'タイトルレッド・オレンジ', 'color': 'Red' }) miner = attribute_miner.AttributeMiner(constants.LANGUAGE_CODE_JA, constants.COUNTRY_CODE_JP) _ = miner.mine_and_insert_attributes_for_batch(product_data) product = product_data['entries'][0]['product'] self.assertIn('Red', product['color'])
def test_mine_and_insert_attributes_inserts_gender_into_gender_field(self): product_data = requests_bodies.build_request_body( properties_to_be_updated={ 'offerId': 'product-1', 'title': 'dummy title', 'googleProductCategory': 'Apparel & Accessories > Shoes', 'productTypes': ['Apparel & Accessories', 'Women\'s', 'Shoes'] }, properties_to_be_removed=['gender']) miner = attribute_miner.AttributeMiner('test', constants.DEFAULT_COUNTRY) _ = miner.mine_and_insert_attributes_for_batch(product_data) product = product_data['entries'][0]['product'] self.assertEqual('female', product['gender'])
def test_color_length_optimizer_removes_all_when_all_colors_longer_than_forty_chars( self): color_with_values_longer_than_forty_chars = 'BlackBlackBlackBlackBlackBlackBlackBlackBlack/BlueBlueBlueBlueBlueBlueBlueBlueBlueBlueBlue' original_data = requests_bodies.build_request_body( properties_to_be_updated={ 'color': color_with_values_longer_than_forty_chars }) optimizer = color_length_optimizer.ColorLengthOptimizer() optimized_data, optimization_result = optimizer.process(original_data) product = optimized_data['entries'][0]['product'] self.assertEqual('', product['color']) self.assertEqual(1, optimization_result.num_of_products_optimized)
def test_process_removes_false_identifier_exists_field_when_mpn_set(self): original_data = requests_bodies.build_request_body( properties_to_be_updated={ 'identifierExists': False, 'brand': '', 'mpn': '12345', 'gtin': '', }) optimized_data, optimization_result = self.optimizer.process( original_data) api_response_result = optimized_data['entries'][0]['product'] self.assertNotIn('identifierExists', api_response_result) self.assertEqual(1, optimization_result.num_of_products_optimized)
def test_process_cut_product_type_when_it_has_too_many_items(self): original_data = requests_bodies.build_request_body( properties_to_be_updated={ 'productTypes': ['a'] * (product_type_length_optimizer._MAX_LIST_LENGTH + 1) }) optimized_data, optimization_result = self.optimizer.process( original_data) product = optimized_data['entries'][0]['product'] expected_product_type = [ 'a' ] * product_type_length_optimizer._MAX_LIST_LENGTH self.assertEqual(expected_product_type, product['productTypes']) self.assertEqual(1, optimization_result.num_of_products_optimized)
def test_invalid_chars_optimizer_sets_product_tracking_field_to_sanitized_when_invalid_char_removed( self): # Char in pos 10 is invalid title_with_single_invalid_char = 'Brand 150g Product Desc' original_data = requests_bodies.build_request_body( properties_to_be_updated={'title': title_with_single_invalid_char}) optimizer = invalid_chars_optimizer.InvalidCharsOptimizer() tracking_field = 'customLabel4' with mock.patch.dict('os.environ', {'PRODUCT_TRACKING_FIELD': tracking_field}): optimized_data, _ = optimizer.process(original_data) product = optimized_data['entries'][0]['product'] self.assertEqual(enums.TrackingTag.SANITIZED.value, product[tracking_field])
def test_process_does_not_set_product_tracking_field_when_title_equals_description( self): original_data = requests_bodies.build_request_body( properties_to_be_updated={ 'title': 'Beauty product', 'description': 'Beauty product' }) tracking_field = 'customLabel4' with mock.patch.dict('os.environ', {'PRODUCT_TRACKING_FIELD': tracking_field}): optimized_data, _ = self.optimizer.process(original_data) optimized_product = optimized_data['entries'][0]['product'] self.assertEqual('', optimized_product[tracking_field]) self.assertEqual(original_data, optimized_data)
def test_invalid_chars_optimizer_removes_last_char_in_unicode_private_area( self): title_with_last_char_in_unicode_private_area = ( f'Brand 150g{chr(0xF8FF)} ' f'Product Desc') original_data = requests_bodies.build_request_body( properties_to_be_updated={ 'title': title_with_last_char_in_unicode_private_area }) optimizer = invalid_chars_optimizer.InvalidCharsOptimizer() optimized_data, optimization_result = optimizer.process(original_data) product = optimized_data['entries'][0]['product'] self.assertEqual('Brand 150g Product Desc', product['title']) self.assertEqual(1, optimization_result.num_of_products_optimized)
def test_mine_and_insert_attributes_for_batch_mines_unisex_from_multiple_description_terms( self): product_data = requests_bodies.build_request_body( properties_to_be_updated={ 'offerId': 'product-1', 'title': 'dummy title', 'description': 'Men\'s and Women\'s shoes', 'googleProductCategory': 'Apparel & Accessories > Shoes', 'productTypes': ['Apparel & Accessories', 'Shoes'] }, properties_to_be_removed=['gender']) miner = attribute_miner.AttributeMiner('test', constants.DEFAULT_COUNTRY) mined_attributes = miner.mine_and_insert_attributes_for_batch(product_data) self.assertIn('Unisex', mined_attributes['product-1'].get('gender'))
def test_process_moves_at_most_three_performing_keywords_to_front_of_title( self): original_data = requests_bodies.build_request_body( properties_to_be_updated={ 'title': 'Some title with multiple keywords keyword2 keyword1 heavy_keyword heavy_keyword_2 in the middle', 'googleProductCategory': 'ファッション・アクセサリー > ジュエリー > 腕時計' }) optimized_data, optimization_result = self.optimizer.process( original_data, 'test') product = optimized_data['entries'][0]['product'] expected_title = ('keyword1 keyword2 heavy_keyword_2 Some title with ' 'multiple keywords heavy_keyword in the middle') self.assertEqual(expected_title, product['title']) self.assertEqual(1, optimization_result.num_of_products_optimized)
def test_size_length_optimizer_sets_product_tracking_field_to_sanitized_when_invalid_size_trimmed( self): size_more_than_100_chars = ('SmallSmallSmallSmallSmallSmallSmallSmall' 'SmallSmallSmallSmallSmallSmallSmallSmall' 'SmallSmallSmallSmallSmallSmallSmallSmall') original_data = requests_bodies.build_request_body( properties_to_be_updated={'sizes': [size_more_than_100_chars]}) optimizer = size_length_optimizer.SizeLengthOptimizer() tracking_field = 'customLabel4' with mock.patch.dict('os.environ', {'PRODUCT_TRACKING_FIELD': tracking_field}): optimized_data, _ = optimizer.process(original_data) product = optimized_data['entries'][0]['product'] self.assertEqual(enums.TrackingTag.SANITIZED.value, product[tracking_field])
def test_process_does_not_change_data_when_title_is_not_truncated_from_description( self): original_title = 'b' original_description = 'a' * ( title_length_optimizer._MAX_TITLE_LENGTH * 2) original_data = requests_bodies.build_request_body( properties_to_be_updated={ 'title': original_title, 'description': original_description }) optimized_data, optimization_result = self.optimizer.process( original_data) product = optimized_data['entries'][0]['product'] self.assertEqual(original_title, product['title']) self.assertEqual(0, optimization_result.num_of_products_optimized)
def test_mine_and_insert_attributes_for_batch_not_contains_gender_when_gender_could_not_be_mined( self): product_data = requests_bodies.build_request_body( properties_to_be_updated={ 'offerId': 'product-1', 'title': 'dummy title', 'gender': '', 'googleProductCategory': 'Apparel & Accessories > Shoes', 'productTypes': ['Apparel & Accessories', 'Shoes'] }) miner = attribute_miner.AttributeMiner('test', constants.DEFAULT_COUNTRY) mined_attributes = miner.mine_and_insert_attributes_for_batch(product_data) self.assertNotIn('Unisex', mined_attributes['product-1']) self.assertNotIn("Men's", mined_attributes['product-1']) self.assertNotIn("Women's", mined_attributes['product-1'])
def test_invalid_chars_optimizer_removes_multiple_invalid_chars(self): # Chars in pos 10 & pos 11 are invalid title_with_multiple_invalid_chars = 'Brand 150g Product Title' desc_with_multiple_invalid_chars = 'Brand 150g Product Desc' original_data = requests_bodies.build_request_body( properties_to_be_updated={ 'title': title_with_multiple_invalid_chars, 'description': desc_with_multiple_invalid_chars }) optimizer = invalid_chars_optimizer.InvalidCharsOptimizer() optimized_data, optimization_result = optimizer.process(original_data) product = optimized_data['entries'][0]['product'] self.assertEqual('Brand 150g Product Title', product['title']) self.assertEqual('Brand 150g Product Desc', product['description']) self.assertEqual(1, optimization_result.num_of_products_optimized)
def test_size_length_optimizer_truncates_size_when_more_than_max_chars( self): size_more_than_100_chars = ('SmallSmallSmallSmallSmallSmallSmallSmall' 'SmallSmallSmallSmallSmallSmallSmallSmall' 'SmallSmallSmallSmallSmallSmallSmallSmall') original_data = requests_bodies.build_request_body( properties_to_be_updated={'sizes': [size_more_than_100_chars]}) optimizer = size_length_optimizer.SizeLengthOptimizer() optimized_data, optimization_result = optimizer.process(original_data) product = optimized_data['entries'][0]['product'] self.assertEqual( 'SmallSmallSmallSmallSmallSmallSmall' 'SmallSmallSmallSmallSmallSmallSmall' 'SmallSmallSmallSmallSmallSmall', product['sizes'][0]) self.assertEqual(1, optimization_result.num_of_products_optimized)
def test_set_optimization_tracking_returns_when_tracking_field_not_set(self): data = requests_bodies.build_request_body() dummy_optimizer = DummyOptimizer() tracking_field = '' with mock.patch.dict('os.environ', {'PRODUCT_TRACKING_FIELD': tracking_field}): optimized_data, _ = dummy_optimizer.process(data) optimized_product = optimized_data['entries'][0]['product'] # Check none of the customLabel fields were set. # (Nothing else we can assert on here since there are no errors/ # log messages. It is valid for the tracking field to be blank.) self.assertEqual('', optimized_product['customLabel0']) self.assertEqual('', optimized_product['customLabel1']) self.assertEqual('', optimized_product['customLabel2']) self.assertEqual('', optimized_product['customLabel3']) self.assertEqual('', optimized_product['customLabel4'])
def test_process_completely_removes_a_keyword_from_title_and_prepend_it( self): original_data = requests_bodies.build_request_body( properties_to_be_updated={ 'title': 'Some title with heavy_keyword in the middle and at the end heavy_keyword', 'googleProductCategory': 'ファッション・アクセサリー > ジュエリー > 腕時計' }) optimized_data, optimization_result = self.optimizer.process( original_data, 'test') product = optimized_data['entries'][0]['product'] expected_title = ( 'heavy_keyword Some title with in the middle and at the ' 'end') self.assertEqual(expected_title, product['title']) self.assertEqual(1, optimization_result.num_of_products_optimized)
def test_process_sets_product_tracking_field_to_sanitized_when_invalid_identifier_exists_removed( self): original_data = requests_bodies.build_request_body( properties_to_be_updated={ 'identifierExists': False, 'brand': 'testbrand', 'mpn': '', 'gtin': '', }) tracking_field = 'customLabel4' with mock.patch.dict('os.environ', {'PRODUCT_TRACKING_FIELD': tracking_field}): optimized_data, _ = self.optimizer.process(original_data) optimized_product = optimized_data['entries'][0]['product'] self.assertEqual(enums.TrackingTag.SANITIZED.value, optimized_product[tracking_field])
def test_mine_and_insert_attributes_for_batch_mines_girls_from_female_baby_gender( self): product_data = requests_bodies.build_request_body( properties_to_be_updated={ 'offerId': 'product-1', 'title': 'dummy title', 'gender': 'female', 'googleProductCategory': 'Apparel & Accessories > Clothing > Baby & Toddler Clothing' }) miner = attribute_miner.AttributeMiner('test', constants.DEFAULT_COUNTRY) mined_attributes = miner.mine_and_insert_attributes_for_batch(product_data) self.assertIn("Girl's", mined_attributes['product-1'].get('gender'))
def test_attribute_not_appended_to_description_if_it_already_exists_in_description( self): original_description = 'Dummy Description. Cool Company.' brand_to_append = 'Cool Company' original_data = requests_bodies.build_request_body( properties_to_be_updated={ 'description': original_description, 'brand': brand_to_append }, properties_to_be_removed=['color', 'sizes']) mined_attrs = attribute_miner.AttributeMiner( constants.LANGUAGE_CODE_EN, constants.DEFAULT_COUNTRY).mine_and_insert_attributes_for_batch( original_data) optimizer = description_optimizer.DescriptionOptimizer(mined_attrs) _, optimization_result = optimizer.process(original_data, 'test') self.assertEqual(0, optimization_result.num_of_products_optimized)
def _build_request_body(has_mpn_field: bool, mpn_value: Optional[str] = None) -> Dict[str, Any]: """Builds a dummy request body. Request body includes 1 product with specific mpn value or without mpn. Args: has_mpn_field: Whether the request body should have mpn field or not. mpn_value: The mpn value of the product. Returns: A dummy request body including 1 product. """ properties_to_be_removed = [] if not has_mpn_field: properties_to_be_removed.append('mpn') body = requests_bodies.build_request_body({'mpn': mpn_value}, properties_to_be_removed) return body
def test_process_puts_the_first_part_of_description_into_title_when_title_is_truncated_from_description( self, suffix): original_description = 'a' * ( title_length_optimizer._MAX_TITLE_LENGTH * 2) original_data = requests_bodies.build_request_body( properties_to_be_updated={ 'title': 'a' * (title_length_optimizer._MAX_TITLE_LENGTH - 5) + suffix, 'description': original_description }) optimized_data, optimization_result = self.optimizer.process( original_data) product = optimized_data['entries'][0]['product'] expected_title = ( original_description[:title_length_optimizer._MAX_TITLE_LENGTH]) self.assertEqual(expected_title, product['title']) self.assertEqual(1, optimization_result.num_of_products_optimized)
def test_color_length_optimizer_removes_colors_until_length_is_less_than_100( self): color_with_three_len_thirty_five_colors = ( 'BlackBlackBlackBlackBlackBlackBlack' '/WhiteWhiteWhiteWhiteWhiteWhiteWhite' '/GreenGreenGreenGreenGreenGreenGreen') original_data = requests_bodies.build_request_body( properties_to_be_updated={ 'color': color_with_three_len_thirty_five_colors }) optimizer = color_length_optimizer.ColorLengthOptimizer() optimized_data, optimization_result = optimizer.process(original_data) product = optimized_data['entries'][0]['product'] self.assertEqual( 'BlackBlackBlackBlackBlackBlackBlack' '/WhiteWhiteWhiteWhiteWhiteWhiteWhite', product['color']) self.assertEqual(1, optimization_result.num_of_products_optimized)
def test_sizes_appended_to_description(self): original_description = 'Dummy Description.' sizes_to_append = ['Large'] original_data = requests_bodies.build_request_body( properties_to_be_updated={ 'description': original_description, 'sizes': sizes_to_append }) mined_attrs = attribute_miner.AttributeMiner( constants.LANGUAGE_CODE_EN, constants.DEFAULT_COUNTRY).mine_and_insert_attributes_for_batch( original_data) optimizer = description_optimizer.DescriptionOptimizer(mined_attrs) optimized_data, optimization_result = optimizer.process( original_data, 'test') product = optimized_data['entries'][0]['product'] self.assertIn(sizes_to_append[0], product['description']) self.assertEqual(1, optimization_result.num_of_products_optimized)
def test_attribute_not_appended_to_description_it_not_enough_space(self): original_description = 'a' * description_optimizer._MAX_DESCRIPTION_LENGTH brand_to_append = 'Cool Company' original_data = requests_bodies.build_request_body( properties_to_be_updated={ 'description': original_description, 'brand': brand_to_append }) mined_attrs = attribute_miner.AttributeMiner( constants.LANGUAGE_CODE_EN, constants.DEFAULT_COUNTRY).mine_and_insert_attributes_for_batch( original_data) optimizer = description_optimizer.DescriptionOptimizer(mined_attrs) optimized_data, optimization_result = optimizer.process( original_data, 'test') product = optimized_data['entries'][0]['product'] self.assertEqual(original_description, product['description']) self.assertEqual(0, optimization_result.num_of_products_optimized)