search_controller_test.rb 15.9 KB
require "#{File.dirname(__FILE__)}/../test_helper"
require File.dirname(__FILE__) + '/../../lib/ext/facets_browse'

# Re-raise errors caught by the controller.
class SearchController; def rescue_action(e) raise e end; end

class SearchControllerTest < ActionController::TestCase

  def setup
    TestSolr.enable
    p1 = File.join(RAILS_ROOT, 'app', 'views')
    p2 = File.join(File.dirname(__FILE__) + '/../../views')
    SearchController.append_view_path([p1,p2])
    @controller = SearchController.new
    @request    = ActionController::TestRequest.new
    @request.stubs(:ssl?).returns(false)
    @response   = ActionController::TestResponse.new

    @category = Category.create!(:name => 'my category', :environment => Environment.default)

    env = Environment.default
    domain = env.domains.first
    if !domain
      domain = Domain.create!(:name => "127.0.0.1")
      env.domains = [domain]
      env.save!
    end
    domain.google_maps_key = 'ENVIRONMENT_KEY'
    domain.save!

    @product_category = fast_create(ProductCategory)

    # By pass user validation on person creation
    user = mock()
    user.stubs(:id).returns(1)
    user.stubs(:valid?).returns(true)
    user.stubs(:email).returns('some@test.com')
    user.stubs(:save!).returns(true)
    Person.any_instance.stubs(:user).returns(user)

    env.enable_plugin(SolrPlugin)
  end

  should 'get facets with articles search results' do
		cat1 = fast_create(Category, :name => 'cat1')
		cat2 = fast_create(Category, :name => 'cat2')
    person = fast_create(Person)
    art = create_article_with_optional_category('an article to be found', person)
		art.add_category cat1, false
		art.add_category cat2, true
		art.save!

    get 'articles', :query => 'article found'
		assert !assigns(:searches)[:articles][:facets].blank?
		assert assigns(:searches)[:articles][:facets]['facet_fields']['solr_plugin_f_type_facet'][0][0] == 'Article'
		assert assigns(:searches)[:articles][:facets]['facet_fields']['solr_plugin_f_profile_type_facet'][0][0] == 'Person'
		assert assigns(:searches)[:articles][:facets]['facet_fields']['solr_plugin_f_category_facet'][0][0] == 'cat1'
		assert assigns(:searches)[:articles][:facets]['facet_fields']['solr_plugin_f_category_facet'][1][0] == 'cat2'
  end

  should 'get facets with people search results' do
    state = fast_create(State, :name => 'Acre', :acronym => 'AC')
    city = fast_create(City, :name => 'Rio Branco', :parent_id => state.id)
    person = Person.create!(:name => 'Hildebrando', :identifier => 'hild', :user_id => fast_create(User).id, :region_id => city.id)
    cat1 = fast_create(Category, :name => 'cat1')
    cat2 = fast_create(Category, :name => 'cat2')
    person.add_category cat1
    person.add_category cat2

    get 'people', :query => 'Hildebrando'

    assert !assigns(:searches)[:people][:facets].blank?
    assert assigns(:searches)[:people][:facets]['facet_fields']['solr_plugin_f_region_facet'][0][0] == city.id.to_s

    categories_facet = assigns(:searches)[:people][:facets]['facet_fields']['solr_plugin_f_categories_facet']
    assert_equal 2, categories_facet.count
    assert_equivalent [cat1.id.to_s, cat2.id.to_s], [categories_facet[0][0], categories_facet[1][0]]
  end

  should 'get facets with products search results' do
		state = fast_create(State, :name => 'Acre', :acronym => 'AC')
		city = fast_create(City, :name => 'Rio Branco', :parent_id => state.id)
		ent = fast_create(Enterprise, :region_id => city.id)
    prod = Product.create!(:name => 'Sound System', :profile_id => ent.id, :product_category_id => @product_category.id)
		qualifier1 = fast_create(Qualifier)
		qualifier2 = fast_create(Qualifier)
		prod.qualifiers_list = [[qualifier1.id, 0], [qualifier2.id, 0]]
		prod.qualifiers.reload
		prod.save!

    get 'products', :query => 'Sound'
		assert !assigns(:searches)[:products][:facets].blank?
		assert assigns(:searches)[:products][:facets]['facet_fields']['solr_plugin_f_category_facet'][0][0] == @product_category.name
		assert assigns(:searches)[:products][:facets]['facet_fields']['solr_plugin_f_region_facet'][0][0] == city.id.to_s
		assert assigns(:searches)[:products][:facets]['facet_fields']['solr_plugin_f_qualifier_facet'][0][0] == "#{qualifier1.id} 0"
		assert assigns(:searches)[:products][:facets]['facet_fields']['solr_plugin_f_qualifier_facet'][1][0] == "#{qualifier2.id} 0"
  end

  # 'assets' menu outside any category
  should 'list products in general without geosearch' do
    Profile.delete_all
		SearchController.stubs(:logged_in?).returns(false)

    ent1 = create_profile_with_optional_category(Enterprise, 'teste1')
    ent2 = create_profile_with_optional_category(Enterprise, 'teste2')
    prod1 = ent1.products.create!(:name => 'a beautiful product', :product_category => @product_category)
    prod2 = ent2.products.create!(:name => 'another beautiful product', :product_category => @product_category)

    get :products
    assert_equivalent [prod2, prod1], assigns(:searches)[:products][:results].docs
		assert_match 'Highlights', @response.body
  end

  should 'offer text box to enter a new search in general context' do
    get :index, :query => 'a sample search'
    assert_tag :tag => 'form', :attributes => { :action => '/search' }, :descendant => {
      :tag => 'input',
      :attributes => { :name => 'query', :value => 'a sample search' }
    }
  end

  should 'offer text box to enter a new seach in specific context' do
    get :index, :category_path => [ 'my-category'], :query => 'a sample search'
    assert_tag :tag => 'form', :attributes => { :action => '/search/index/my-category' }, :descendant => {
      :tag => 'input',
      :attributes => { :name => 'query', :value => 'a sample search' }
    }
  end

  should 'find enterprise by product category' do
    ent1 = create_profile_with_optional_category(Enterprise, 'test1')
    prod_cat = ProductCategory.create!(:name => 'pctest', :environment => Environment.default)
    prod = ent1.products.create!(:name => 'teste', :product_category => prod_cat)

    ent2 = create_profile_with_optional_category(Enterprise, 'test2')

    get :index, :query => prod_cat.name

    assert_includes assigns(:searches)[:enterprises][:results], ent1
    assert_not_includes assigns(:searches)[:enterprises][:results], ent2
  end

  should 'show only results in general search' do
    ent1 = create_profile_with_optional_category(Enterprise, 'test1')
    prod_cat = ProductCategory.create!(:name => 'pctest', :environment => Environment.default)
    prod = ent1.products.create!(:name => 'teste', :product_category => prod_cat)

    ent2 = create_profile_with_optional_category(Enterprise, 'test2')

    get :index, :query => prod_cat.name

		assert assigns(:facets).blank?
		assert assigns(:searches)[:enterprises][:facets].blank?
		assert assigns(:searches)[:products][:facets].blank?
	end

	# Testing random sequences always have a small chance of failing
	should 'randomize product display in empty search' do
    prod_cat = ProductCategory.create!(:name => 'prod cat test', :environment => Environment.default)
    ent = create_profile_with_optional_category(Enterprise, 'test enterprise')
    (1..SearchController::LIST_SEARCH_LIMIT+5).each do |n|
      fast_create(Product, {:name => "produto #{n}", :profile_id => ent.id, :product_category_id => prod_cat.id}, :search => true)
    end

    get :products
    result1 = assigns(:searches)[:products][:results].map(&:id)

    (1..10).each do |n|
      get :products
    end
    result2 = assigns(:searches)[:products][:results].map(&:id)

    assert_not_equal result1, result2
	end

	should 'remove far products by geolocalization empty logged search' do
    user = create_user('a_logged_user')
    # trigger geosearch
    user.person.lat = '1.0'
    user.person.lng = '1.0'
    SearchController.any_instance.stubs(:logged_in?).returns(true)
    SearchController.any_instance.stubs(:current_user).returns(user)

    cat = fast_create(ProductCategory)
    ent1 = Enterprise.create!(:name => 'ent1', :identifier => 'ent1', :lat => '1.3', :lng => '1.3')
    prod1 = Product.create!(:name => 'produto 1', :profile_id => ent1.id, :product_category_id => cat.id)
    ent2 = Enterprise.create!(:name => 'ent2', :identifier => 'ent2', :lat => '2.0', :lng => '2.0')
    prod2 = Product.create!(:name => 'produto 2', :profile_id => ent2.id, :product_category_id => cat.id)
    ent3 = Enterprise.create!(:name => 'ent3', :identifier => 'ent3', :lat => '1.6', :lng => '1.6')
    prod3 = Product.create!(:name => 'produto 3', :profile_id => ent3.id, :product_category_id => cat.id)
    ent4 = Enterprise.create!(:name => 'ent4', :identifier => 'ent4', :lat => '10', :lng => '10')
    prod4 = Product.create!(:name => 'produto 4', :profile_id => ent4.id, :product_category_id => cat.id)

    get :products
    assert_equivalent [prod1, prod3, prod2], assigns(:searches)[:products][:results].docs
	end

	should 'browse facets when query is not empty' do
		get :articles, :query => 'something'
		get :facets_browse, :asset_key => 'articles', :facet_id => 'solr_plugin_f_type'
		assert_equal assigns(:facet)[:id], 'solr_plugin_f_type'
		get :products, :query => 'something'
		get :facets_browse, :asset_key => 'products', :facet_id => 'solr_plugin_f_category'
		assert_equal assigns(:facet)[:id], 'solr_plugin_f_category'
		get :people, :query => 'something'
		get :facets_browse, :asset_key => 'people', :facet_id => 'solr_plugin_f_region'
		assert_equal assigns(:facet)[:id], 'solr_plugin_f_region'
	end

	should 'raise exception when facet is invalid' do
		get :articles, :query => 'something'
		assert_raise RuntimeError do
			get :facets_browse, :asset_key => 'articles', :facet_id => 'solr_plugin_fwhatever'
		end
	end

  should 'order product results by more recent when requested' do
		ent = fast_create(Enterprise)
    prod1 = Product.create!(:name => 'product 1', :profile_id => ent.id, :product_category_id => @product_category.id)
    prod2 = Product.create!(:name => 'product 2', :profile_id => ent.id, :product_category_id => @product_category.id)
    prod3 = Product.create!(:name => 'product 3', :profile_id => ent.id, :product_category_id => @product_category.id)

    # change others attrs will make updated_at = Time.now for all
    Product.record_timestamps = false
    prod3.update_attribute :updated_at, Time.now-2.days
    prod1.update_attribute :updated_at, Time.now-1.days
    prod2.update_attribute :updated_at, Time.now
    Product.record_timestamps = true

    get :products, :query => 'product', :order_by => :more_recent

    assert_equal [prod2, prod1, prod3], assigns(:searches)[:products][:results].docs
  end

  should 'only list products from enabled enterprises' do
		ent1 = fast_create(Enterprise, :enabled => true)
		ent2 = fast_create(Enterprise, :enabled => false)
    prod1 = Product.create!(:name => 'product 1', :profile_id => ent1.id, :product_category_id => @product_category.id)
    prod2 = Product.create!(:name => 'product 2', :profile_id => ent2.id, :product_category_id => @product_category.id)

    get :products, :query => 'product'

    assert_includes assigns(:searches)[:products][:results], prod1
    assert_not_includes assigns(:searches)[:products][:results], prod2
  end

  should 'order product results by name when requested' do
		ent = fast_create(Enterprise)
    prod1 = Product.create!(:name => 'product 1', :profile_id => ent.id, :product_category_id => @product_category.id)
    prod2 = Product.create!(:name => 'product 2', :profile_id => ent.id, :product_category_id => @product_category.id)
    prod3 = Product.create!(:name => 'product 3', :profile_id => ent.id, :product_category_id => @product_category.id)

    prod3.update_attribute :name, 'product A'
    prod2.update_attribute :name, 'product B'
    prod1.update_attribute :name, 'product C'

    get :products, :query => 'product', :order_by => :name

    assert_equal [prod3, prod2, prod1], assigns(:searches)[:products][:results].docs
  end

	should 'order product results by closest when requested' do
    user = create_user('a_logged_user')
		user.person.lat = '1.0'
		user.person.lng = '1.0'
    # trigger geosearch
		SearchController.any_instance.stubs(:logged_in?).returns(true)
		SearchController.any_instance.stubs(:current_user).returns(user)

		cat = fast_create(ProductCategory)
		ent1 = Enterprise.create!(:name => 'ent1', :identifier => 'ent1', :lat => '-5.0', :lng => '-5.0')
    prod1 = Product.create!(:name => 'product 1', :profile_id => ent1.id, :product_category_id => cat.id)
		ent2 = Enterprise.create!(:name => 'ent2', :identifier => 'ent2', :lat => '2.0', :lng => '2.0')
    prod2 = Product.create!(:name => 'product 2', :profile_id => ent2.id, :product_category_id => cat.id)
		ent3 = Enterprise.create!(:name => 'ent3', :identifier => 'ent3', :lat => '10.0', :lng => '10.0')
    prod3 = Product.create!(:name => 'product 3', :profile_id => ent3.id, :product_category_id => cat.id)

		get :products, :query => 'product', :order_by => :closest
		assert_equal [prod2, prod1, prod3], assigns(:searches)[:products][:results].docs
	end


  should 'order events by name when requested' do
    person = create_user('someone').person
    ev1 = create_event(person, :name => 'party B', :category_ids => [@category.id],	:start_date => Date.today - 1.day)
    ev2 = create_event(person, :name => 'party A', :category_ids => [@category.id],	:start_date => Date.today - 2.days)

    get :events, :query => 'party', :order_by => :name

    assert_equal [ev2, ev1], assigns(:searches)[:events][:results].docs
  end

  should 'order articles by name when requested' do
		art1 = Article.create!(:name => 'review C', :profile_id => fast_create(Person).id)
		art2 = Article.create!(:name => 'review A', :profile_id => fast_create(Person).id)
		art3 = Article.create!(:name => 'review B', :profile_id => fast_create(Person).id)

    get :articles, :query => 'review', :order_by => :name

    assert_equal [art2, art3, art1], assigns(:searches)[:articles][:results].docs
  end

  should 'order enterprise results by name when requested' do
		ent1 = Enterprise.create!(:name => 'Company B', :identifier => 'com_b')
		ent2 = Enterprise.create!(:name => 'Company A', :identifier => 'com_a')
		ent3 = Enterprise.create!(:name => 'Company C', :identifier => 'com_c')

    get :enterprises, :query => 'Company', :order_by => :name

    assert_equal [ent2, ent1, ent3], assigns(:searches)[:enterprises][:results].docs
  end

  should 'order people results by name when requested' do
		person1 = Person.create!(:name => 'Deodárbio Silva', :identifier => 'deod', :user_id => fast_create(User).id)
		person2 = Person.create!(:name => 'Glislange Silva', :identifier => 'glis', :user_id => fast_create(User).id)
		person3 = Person.create!(:name => 'Ausêncio Silva', :identifier => 'ause', :user_id => fast_create(User).id)

    get :people, :query => 'Silva', :order_by => :name

    assert_equal [person3, person1, person2], assigns(:searches)[:people][:results].docs
  end

  should 'order community results by name when requested' do
		com1 = Community.create!(:name => 'Yellow Group')
		com2 = Community.create!(:name => 'Red Group')
		com3 = Community.create!(:name => 'Green Group')

    get :communities, :query => 'Group', :order_by => :name

    assert_equal [com3, com2, com1], assigns(:searches)[:communities][:results].docs
  end

  should 'raise error when requested to order by unknown filter' do
		com1 = Community.create!(:name => 'Yellow Group')
		com2 = Community.create!(:name => 'Red Group')
		com3 = Community.create!(:name => 'Green Group')

    assert_raise RuntimeError do
      get :communities, :query => 'Group', :order_by => :something
    end
  end

  protected

  def create_article_with_optional_category(name, profile, category = nil)
    fast_create(Article, {:name => name, :profile_id => profile.id }, :search => true, :category => category)
  end

  def create_profile_with_optional_category(klass, name, category = nil, data = {})
    fast_create(klass, { :name => name }.merge(data), :search => true, :category => category)
  end

  def create_event(profile, options)
    ev = Event.new({ :name => 'some event', :start_date => Date.new(2008,1,1) }.merge(options))
    ev.profile = profile
    ev.save!
    ev
  end

end