de.hybris.platform.solrfacetsearch.integration.FacetDrillDownTest.java Source code

Java tutorial

Introduction

Here is the source code for de.hybris.platform.solrfacetsearch.integration.FacetDrillDownTest.java

Source

/*
 * [y] hybris Platform
 *
 * Copyright (c) 2000-2014 hybris AG
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of hybris
 * ("Confidential Information"). You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the
 * license agreement you entered into with hybris.
 *
 *  
 */
package de.hybris.platform.solrfacetsearch.integration;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;

import de.hybris.platform.category.CategoryService;
import de.hybris.platform.category.model.CategoryModel;
import de.hybris.platform.core.model.product.ProductModel;
import de.hybris.platform.jalo.order.price.PriceInformation;
import de.hybris.platform.product.PriceService;
import de.hybris.platform.solrfacetsearch.config.IndexedProperties;
import de.hybris.platform.solrfacetsearch.config.IndexedProperty;
import de.hybris.platform.solrfacetsearch.config.ValueRange;
import de.hybris.platform.solrfacetsearch.search.Facet;
import de.hybris.platform.solrfacetsearch.search.FacetValue;
import de.hybris.platform.solrfacetsearch.search.SearchResult;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import javax.annotation.Resource;

import org.apache.commons.beanutils.BeanToPropertyValueTransformer;
import org.apache.commons.collections.CollectionUtils;
import org.junit.Test;

/**
 * Tests the drill down of facets, i.e. for each selected facet value the remaining facet count should be reduced. This
 * also should work
 */
public class FacetDrillDownTest extends AbstractSolrIntegrationTest {

    private static final String MANUFACTURER_NAME = "Intel";
    private static final String PRICE_RANGE = "101-200";
    private static final String CATEGORY_NAME = "Motherboards_online_de";
    private static final String CATEGORY2_NAME = "Mainboards";
    private static final String FULL_TEXT_VALUE = "graphics";

    @Resource
    protected PriceService priceService;

    @Resource
    protected CategoryService categoryService;

    /**
     * Given products with manufacturerName = "Intel" in hwcatalog and with a certain facet count<br/>
     * and with hwcatalog selected<br/>
     * and with facet value manufacturerName set to "Intel"<br/>
     * then a search yields products only with manufacturerName = <manufacturerName> and the facet count reduced to
     * reflect this
     */
    @Test
    public void testFacetNonLocalized() throws Exception {
        query.setCatalogVersion(hwOnline);
        query.clearOrderFields();
        query.addOrderField("name", true);

        final SearchResult result1 = facetSearchService.search(query);
        assertTrue("query1 must return results", result1.getTotalNumberOfResults() > 0);
        final Collection<ProductModel> products1 = checkProductCollection(hwOnline, result1.getResults());
        checkOrderByName(products1);
        checkFacets(result1);

        query.addFacetValue("manufacturerName", MANUFACTURER_NAME);
        final SearchResult result2 = facetSearchService.search(query);
        assertNotNull("Result must not be null", result2);
        assertTrue("query2 must return results", result2.getTotalNumberOfResults() > 0);
        final Collection<ProductModel> products2 = checkProductCollection(hwOnline, result2.getResults());
        checkOrderByName(products2);
        for (final ProductModel product : products2) {
            assertEquals("Manufacturer name", MANUFACTURER_NAME, product.getManufacturerName());
        }
        checkFacets(result2);
        compareFacets(result1, result2);
    }

    private void checkOrderByName(final Collection<ProductModel> products) {
        String previousName = "";
        for (final ProductModel product : products) {
            assertTrue(String.format("Products not sorted by 'name'. '%s' should come before '%s' ", previousName,
                    product.getName()), previousName.compareToIgnoreCase(product.getName()) <= 0);
            previousName = product.getName();
        }
    }

    private void checkOrderByManufacturerName(final Collection<ProductModel> products) {
        String previousName = "";
        for (final ProductModel product : products) {
            assertTrue(
                    String.format("Products not sorted by 'manufacturerName'. '%s' should come before '%s' ",
                            previousName, product.getManufacturerName()),
                    previousName.compareToIgnoreCase(product.getManufacturerName()) <= 0);
            previousName = product.getManufacturerName();
        }
    }

    /**
     * Given products with categoryName = "Motherboards_online_de" in hwcatalog and language de and with a certain facet
     * count<br/>
     * and with hwcatalog selected<br/>
     * and with language de selected<br/>
     * and with facet value categoryName set to "Motherboards_online_de"<br/>
     * then a search yields products only with categoryName = "Motherboards_online_de" and the facet count reduced to
     * reflect this
     */
    @Test
    public void testFacetLocalized() throws Exception {

        query.setCatalogVersion(hwOnline);
        query.setLanguage("de");
        query.clearOrderFields();
        query.addOrderField("manufacturerName", true);

        final SearchResult result1 = facetSearchService.search(query);
        assertTrue("query1 must return results", result1.getTotalNumberOfResults() > 0);
        final Collection<ProductModel> products1 = checkProductCollection(hwOnline, result1.getResults());
        checkOrderByManufacturerName(products1);
        checkFacets(result1);

        query.addFacetValue("categoryName", CATEGORY_NAME);
        final SearchResult result2 = facetSearchService.search(query);
        assertTrue("query2 must return results", result2.getTotalNumberOfResults() > 0);
        final Collection<ProductModel> products2 = checkProductCollection(hwOnline, result2.getResults());
        checkOrderByManufacturerName(products2);
        for (final ProductModel product : products2) {
            final Collection<CategoryModel> categories = product.getSupercategories();
            boolean catFound = false;
            for (final CategoryModel category : categories) {
                if (CATEGORY_NAME.equals(category.getName())) {
                    catFound = true;
                    break;
                }
            }
            assertTrue("Category not found", catFound);
        }

        checkFacets(result2);
        compareFacets(result1, result2);
    }

    /**
     * Given product in a price range = "101-200" and "graphics" in description, residing in hwcatalog and with a certain
     * facet count<br/>
     * and with hwcatalog selected<br/>
     * and with facet price set to "101-200"<br/>
     * then when searching in description for the string "graphics" the the resulting products must be in the specified
     * price range and and the facet count must be reduced to reflect this
     * 
     * @throws Exception
     */
    @Test
    public void testFacetWithSearch() throws Exception {
        query.setCatalogVersion(hwOnline);
        query.setLanguage("en");

        final SearchResult result1 = facetSearchService.search(query);
        assertTrue("query1 must return results", result1.getTotalNumberOfResults() > 0);
        checkProductCollection(hwOnline, result1.getResults());
        checkFacets(result1);

        query.addFacetValue("price", PRICE_RANGE);
        final SearchResult result2 = facetSearchService.search(query);
        assertNotNull("Result must not be null", result2);
        assertTrue("query2 must return results", result2.getTotalNumberOfResults() > 0);
        final Collection<ProductModel> products2 = checkProductCollection(hwOnline, result2.getResults());
        for (final ProductModel product : products2) {
            checkPrice(product, 101, 200);
        }
        checkFacets(result2);
        compareFacets(result1, result2);

        query.search(FULL_TEXT_VALUE);
        final SearchResult result3 = facetSearchService.search(query);
        assertNotNull("Result must not be null", result3);
        assertTrue("query3 must return results", result3.getTotalNumberOfResults() > 0);
        final Collection<ProductModel> products3 = checkProductCollection(hwOnline, result3.getResults());
        for (final ProductModel product : products3) {
            checkPrice(product, 101, 200);
            final String description = product.getDescription(Locale.ENGLISH);
            assertNotNull("Product must have a description", description);
            assertTrue("Description must contain string 'graphics'",
                    description.toLowerCase().contains("graphics"));
        }
        checkFacets(result3);
        compareFacets(result2, result3);
    }

    private void checkPrice(final ProductModel product, final int min, final int max) {
        final List<PriceInformation> prices = priceService.getPriceInformationsForProduct(product);
        final PriceInformation price = prices.get(0);
        final double value = price.getPriceValue().getValue();
        assertTrue(String.format("Price must be between %d and %d", Integer.valueOf(min), Integer.valueOf(max)),
                value >= min && value <= max);
    }

    /**
     * Given product in a price range = "101-200" in hwcatalog and with a certain facet count<br/>
     * and with hwcatalog selected<br/>
     * and with facet price set to "101-200" then the the resulting products must be in the specified price range and the
     * facet count mustbe reduced to reflect this
     */
    @Test
    public void testRangedFacet() throws Exception {
        query.setCatalogVersion(hwOnline);

        final SearchResult result1 = facetSearchService.search(query);
        assertTrue("query1 must return results", result1.getTotalNumberOfResults() > 0);
        checkProductCollection(hwOnline, result1.getResults());
        checkFacets(result1);

        query.addFacetValue("price", PRICE_RANGE);
        final SearchResult result2 = facetSearchService.search(query);
        assertNotNull("Result must not be null", result2);
        assertTrue("query2 must return results", result2.getTotalNumberOfResults() > 0);
        final Collection<ProductModel> products2 = checkProductCollection(hwOnline, result2.getResults());
        for (final ProductModel product : products2) {
            checkPrice(product, 101, 200);
        }
        checkFacets(result2);
        compareFacets(result1, result2);

    }

    /**
     * Given products with manufacturerName = "Intel", categoryName = "Motherboards_online_de" in language de, in
     * hwcatalog and with a certain facet count and with hwcatalog selected<br/>
     * and with facet value manufacturerName set "Intel"<br/>
     * and with facet value categoryName set to "Motherboards_online_de"<br/>
     * then a search yields products only with manufacturerName = "Intel" and the facet count reduced to reflect this,
     * with the facet count lower when the second facet is selected
     */
    @Test
    public void testFacetDrillDown() throws Exception {
        query.setCatalogVersion(hwOnline);
        query.setLanguage("de");

        final SearchResult result1 = facetSearchService.search(query);
        assertTrue("query1 must return results", result1.getTotalNumberOfResults() > 0);
        checkProductCollection(hwOnline, result1.getResults());
        checkFacets(result1);

        query.addFacetValue("manufacturerName", MANUFACTURER_NAME);
        final SearchResult result2 = facetSearchService.search(query);
        assertNotNull("Result must not be null", result2);
        assertTrue("query2 must return results", result2.getTotalNumberOfResults() > 0);
        final Collection<ProductModel> products2 = checkProductCollection(hwOnline, result2.getResults());
        for (final ProductModel product : products2) {
            assertEquals("Manufacturer name", MANUFACTURER_NAME, product.getManufacturerName());
        }
        checkFacets(result2);
        compareFacets(result1, result2);

        query.addFacetValue("categoryName", CATEGORY2_NAME);
        final SearchResult result3 = facetSearchService.search(query);
        assertTrue("query3 must return results", result3.getTotalNumberOfResults() > 0);
        final Collection<ProductModel> products3 = checkProductCollection(hwOnline, result3.getResults());
        for (final ProductModel product : products3) {
            assertEquals("Manufacturer name", MANUFACTURER_NAME, product.getManufacturerName());
            assertTrue("Category not found", isSuperCategory(product, CATEGORY2_NAME));
        }

        checkFacets(result3);
        compareFacets(result2, result3);
    }

    protected boolean isSuperCategory(final ProductModel product, final String categoryName) {
        for (final CategoryModel category : product.getSupercategories()) {
            if (isSuperCategory(category, categoryName)) {
                return true;
            }
        }
        return false;
    }

    protected boolean isSuperCategory(final CategoryModel category, final String categoryName) {
        if (categoryName.equals(category.getName())) {
            return true;
        }

        for (final CategoryModel superCategory : category.getSupercategories()) {
            if (isSuperCategory(superCategory, categoryName)) {
                return true;
            }
        }
        return false;
    }

    private void checkFacets(final SearchResult result) {
        final List<Facet> facets3 = result.getFacets();
        assertFalse("Facets collection must not be empty", facets3.isEmpty());
        assertTrue("Result not contain facet price", result.containsFacet("price"));
        final Facet facet = result.getFacet("price");
        final List<String> facetValues = (List<String>) CollectionUtils.collect(facet.getFacetValues(),
                new BeanToPropertyValueTransformer("name"), new ArrayList<String>());
        final IndexedProperty priceProperty = indexedType.getIndexedProperties().get("price");
        assertNotNull("No such indexed property: 'price'", priceProperty);
        final List<ValueRange> priceRanges = IndexedProperties.getValueRanges(priceProperty, null);
        assertNotNull("No priceRanges found", priceRanges);
        assertFalse("Price ranges must not be empty", priceRanges.isEmpty());
        final List<String> ranngeValues = (List<String>) CollectionUtils.collect(priceRanges,
                new BeanToPropertyValueTransformer("name"), new ArrayList<String>());
        final Iterator<String> facetValueItr = facetValues.iterator();
        final Iterator<String> rangeValueItr = ranngeValues.iterator();
        while (rangeValueItr.hasNext()) {
            final String rangeValue = rangeValueItr.next();
            if (facetValues.contains(rangeValue)) {
                assertTrue("No more facet values", facetValueItr.hasNext());
                final String facetValue = facetValueItr.next();
                assertEquals("Facet value", rangeValue, facetValue);
            }
        }
        assertTrue("Result not contain facet manufacturerName", result.containsFacet("manufacturerName"));
        //assertTrue("Result not contain facet processor", result.containsFacet("processor"));
        assertTrue("Result not contain facet categoryName", result.containsFacet("categoryName"));
    }

    private void compareFacets(final SearchResult result1, final SearchResult result2) {
        for (final Facet facet1 : result1.getFacets()) {
            final Facet facet2 = result2.getFacet(facet1.getName());
            if (facet2 != null) {
                final Collection<FacetValue> facetValues1 = facet1.getFacetValues();
                for (final FacetValue facetValue1 : facetValues1) {
                    long facetValue2Count = 0;
                    final FacetValue facetValue2 = facet2.getFacetValue(facetValue1.getName());
                    if (facetValue2 != null) {
                        facetValue2Count = facetValue2.getCount();
                    }
                    final long facetValue1Count = facetValue1.getCount();
                    assertTrue(
                            "Facet value count of " + facet1.getName() + "/" + facet1.getName()
                                    + " is expected to be less than or equal to " + facetValue1Count,
                            facetValue2Count <= facetValue1Count);
                }
            }
        }
    }

}