bento_search 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +299 -0
  3. data/Rakefile +40 -0
  4. data/app/assets/images/bento_search/large_loader.gif +0 -0
  5. data/app/assets/javascripts/bento_search.js +3 -0
  6. data/app/assets/javascripts/bento_search/ajax_load.js +22 -0
  7. data/app/assets/stylesheets/bento_search/bento.css +4 -0
  8. data/app/controllers/bento_search/bento_search_controller.rb +7 -0
  9. data/app/controllers/bento_search/search_controller.rb +72 -0
  10. data/app/helpers/bento_search_helper.rb +138 -0
  11. data/app/item_decorators/bento_search/only_premade_openurl.rb +16 -0
  12. data/app/item_decorators/bento_search/openurl_add_other_link.rb +35 -0
  13. data/app/item_decorators/bento_search/openurl_main_link.rb +30 -0
  14. data/app/models/bento_search/author.rb +25 -0
  15. data/app/models/bento_search/link.rb +30 -0
  16. data/app/models/bento_search/multi_searcher.rb +109 -0
  17. data/app/models/bento_search/openurl_creator.rb +128 -0
  18. data/app/models/bento_search/registrar.rb +70 -0
  19. data/app/models/bento_search/result_item.rb +203 -0
  20. data/app/models/bento_search/results.rb +54 -0
  21. data/app/models/bento_search/results/pagination.rb +67 -0
  22. data/app/models/bento_search/search_engine.rb +219 -0
  23. data/app/models/bento_search/search_engine/capabilities.rb +65 -0
  24. data/app/search_engines/bento_search/#Untitled-1# +11 -0
  25. data/app/search_engines/bento_search/ebsco_host_engine.rb +356 -0
  26. data/app/search_engines/bento_search/eds_engine.rb +557 -0
  27. data/app/search_engines/bento_search/google_books_engine.rb +184 -0
  28. data/app/search_engines/bento_search/primo_engine.rb +231 -0
  29. data/app/search_engines/bento_search/scopus_engine.rb +295 -0
  30. data/app/search_engines/bento_search/summon_engine.rb +398 -0
  31. data/app/search_engines/bento_search/xerxes_engine.rb +168 -0
  32. data/app/views/bento_search/_link.html.erb +4 -0
  33. data/app/views/bento_search/_search_error.html.erb +22 -0
  34. data/app/views/bento_search/_std_item.html.erb +39 -0
  35. data/app/views/bento_search/search/search.html.erb +1 -0
  36. data/config/locales/en.yml +25 -0
  37. data/lib/bento_search.rb +29 -0
  38. data/lib/bento_search/engine.rb +5 -0
  39. data/lib/bento_search/routes.rb +45 -0
  40. data/lib/bento_search/version.rb +3 -0
  41. data/lib/generators/bento_search/pull_ebsco_dbs_generator.rb +24 -0
  42. data/lib/generators/bento_search/templates/ebsco_global_var.erb +6 -0
  43. data/lib/http_client_patch/include_client.rb +86 -0
  44. data/lib/tasks/bento_search_tasks.rake +4 -0
  45. data/test/dummy/README.rdoc +261 -0
  46. data/test/dummy/Rakefile +7 -0
  47. data/test/dummy/app/assets/javascripts/application.js +15 -0
  48. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  49. data/test/dummy/app/controllers/application_controller.rb +3 -0
  50. data/test/dummy/app/helpers/application_helper.rb +2 -0
  51. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  52. data/test/dummy/config.ru +4 -0
  53. data/test/dummy/config/application.rb +56 -0
  54. data/test/dummy/config/boot.rb +10 -0
  55. data/test/dummy/config/database.yml +25 -0
  56. data/test/dummy/config/environment.rb +5 -0
  57. data/test/dummy/config/environments/development.rb +37 -0
  58. data/test/dummy/config/environments/production.rb +67 -0
  59. data/test/dummy/config/environments/test.rb +37 -0
  60. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  61. data/test/dummy/config/initializers/inflections.rb +15 -0
  62. data/test/dummy/config/initializers/mime_types.rb +5 -0
  63. data/test/dummy/config/initializers/secret_token.rb +7 -0
  64. data/test/dummy/config/initializers/session_store.rb +8 -0
  65. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  66. data/test/dummy/config/locales/en.yml +5 -0
  67. data/test/dummy/config/routes.rb +6 -0
  68. data/test/dummy/db/test.sqlite3 +0 -0
  69. data/test/dummy/log/test.log +3100 -0
  70. data/test/dummy/public/404.html +26 -0
  71. data/test/dummy/public/422.html +26 -0
  72. data/test/dummy/public/500.html +25 -0
  73. data/test/dummy/public/favicon.ico +0 -0
  74. data/test/dummy/script/rails +6 -0
  75. data/test/functional/bento_search/search_controller_test.rb +81 -0
  76. data/test/helper/bento_search_helper_test.rb +125 -0
  77. data/test/integration/navigation_test.rb +10 -0
  78. data/test/support/mock_engine.rb +23 -0
  79. data/test/support/test_with_cassette.rb +38 -0
  80. data/test/test_helper.rb +52 -0
  81. data/test/unit/#vcr_test.rb# +68 -0
  82. data/test/unit/ebsco_host_engine_test.rb +134 -0
  83. data/test/unit/eds_engine_test.rb +105 -0
  84. data/test/unit/google_books_engine_test.rb +93 -0
  85. data/test/unit/item_decorators_test.rb +66 -0
  86. data/test/unit/multi_searcher_test.rb +49 -0
  87. data/test/unit/openurl_creator_test.rb +111 -0
  88. data/test/unit/pagination_test.rb +59 -0
  89. data/test/unit/primo_engine_test.rb +37 -0
  90. data/test/unit/register_engine_test.rb +50 -0
  91. data/test/unit/result_item_display_test.rb +39 -0
  92. data/test/unit/result_item_test.rb +36 -0
  93. data/test/unit/scopus_engine_test.rb +130 -0
  94. data/test/unit/search_engine_base_test.rb +178 -0
  95. data/test/unit/search_engine_test.rb +95 -0
  96. data/test/unit/summon_engine_test.rb +161 -0
  97. data/test/unit/xerxes_engine_test.rb +70 -0
  98. data/test/vcr_cassettes/ebscohost/error_bad_db.yml +45 -0
  99. data/test/vcr_cassettes/ebscohost/error_bad_password.yml +45 -0
  100. data/test/vcr_cassettes/ebscohost/get_info.yml +3626 -0
  101. data/test/vcr_cassettes/ebscohost/live_search.yml +45 -0
  102. data/test/vcr_cassettes/ebscohost/live_search_smoke_test.yml +1311 -0
  103. data/test/vcr_cassettes/eds/basic_search_smoke_test.yml +1811 -0
  104. data/test/vcr_cassettes/eds/get_auth_token.yml +75 -0
  105. data/test/vcr_cassettes/eds/get_auth_token_failure.yml +39 -0
  106. data/test/vcr_cassettes/eds/get_with_auth.yml +243 -0
  107. data/test/vcr_cassettes/eds/get_with_auth_recovers_from_bad_auth.yml +368 -0
  108. data/test/vcr_cassettes/gbs/error_condition.yml +40 -0
  109. data/test/vcr_cassettes/gbs/pagination.yml +702 -0
  110. data/test/vcr_cassettes/gbs/search.yml +340 -0
  111. data/test/vcr_cassettes/primo/search_smoke_test.yml +1112 -0
  112. data/test/vcr_cassettes/scopus/bad_api_key_should_return_error_response.yml +60 -0
  113. data/test/vcr_cassettes/scopus/escaped_chars.yml +187 -0
  114. data/test/vcr_cassettes/scopus/fielded_search.yml +176 -0
  115. data/test/vcr_cassettes/scopus/simple_search.yml +227 -0
  116. data/test/vcr_cassettes/scopus/zero_results_search.yml +67 -0
  117. data/test/vcr_cassettes/summon/bad_auth.yml +54 -0
  118. data/test/vcr_cassettes/summon/proper_tags_for_snippets.yml +216 -0
  119. data/test/vcr_cassettes/summon/search.yml +242 -0
  120. data/test/vcr_cassettes/xerxes/live_search.yml +2580 -0
  121. data/test/view/std_item_test.rb +98 -0
  122. metadata +421 -0
@@ -0,0 +1,134 @@
1
+ require 'test_helper'
2
+
3
+ require 'cgi'
4
+ require 'uri'
5
+
6
+ class EbscoHostEngineTest < ActiveSupport::TestCase
7
+ extend TestWithCassette
8
+
9
+ @@profile_id = (ENV['EBSCOHOST_PROFILE'] || 'DUMMY_PROFILE')
10
+ @@profile_pwd = (ENV['EBSCOHOST_PWD'] || 'DUMMY_PWD')
11
+ @@dbs_to_test = (ENV['EBSCOHOST_TEST_DBS'] || %w{a9h awn} )
12
+
13
+ VCR.configure do |c|
14
+ c.filter_sensitive_data("prof=DUMMY_PROFILE", :ebscohost) { "prof=#{@@profile_id}" }
15
+ c.filter_sensitive_data("pwd=DUMMY_PWD", :ebscohost) { "pwd=#{@@profile_pwd}" }
16
+ end
17
+
18
+
19
+ def setup
20
+ @config = {
21
+ :profile_id => @@profile_id,
22
+ :profile_password => @@profile_pwd,
23
+ :databases => @@dbs_to_test
24
+ }
25
+
26
+ @engine = BentoSearch::EbscoHostEngine.new( @config )
27
+ end
28
+
29
+
30
+ def test_url_construction
31
+ url = @engine.query_url(:query => "cancer", :start => 10, :per_page => 5)
32
+
33
+ assert_present url
34
+
35
+ query_params = CGI.parse( URI.parse(url).query )
36
+
37
+ assert_equal [@engine.configuration.profile_id], query_params["prof"]
38
+ assert_equal [@engine.configuration.profile_password], query_params["pwd"]
39
+
40
+ assert_equal ["cancer"], query_params["query"]
41
+
42
+ assert_equal ["5"], query_params["numrec"]
43
+ assert_equal ["11"], query_params["startrec"]
44
+
45
+ # default sort relevance
46
+ assert_equal ["relevance"], query_params["sort"]
47
+
48
+ @engine.configuration.databases.each do |db|
49
+ assert_include query_params["db"], db
50
+ end
51
+ end
52
+
53
+ def test_date_sort_construction
54
+ url = @engine.query_url(:query => "cancer", :sort => "date_desc")
55
+
56
+ query_params = CGI.parse( URI.parse(url).query )
57
+
58
+ assert_equal ["date"], query_params["sort"]
59
+ end
60
+
61
+ def fielded_construction
62
+ url = @engine.query_url(:query => "cancer", :search_field => "SU")
63
+
64
+ query_params = CGI.parse( URI.parse(url).query )
65
+
66
+ assert_equal ["(SU cancer)"], query_params["query"]
67
+ end
68
+
69
+ def test_prepare_query
70
+ query = @engine.ebsco_query_prepare('one :. ; two "three four" AND NOT OR five')
71
+
72
+ assert_equal 'one AND two AND "three four" AND five', query
73
+ end
74
+
75
+ def test_removes_paren_literals
76
+ url = @engine.query_url(:query => "cancer)", :sort => "date_desc")
77
+
78
+ query_params = CGI.parse( URI.parse(url).query )
79
+
80
+ assert_equal ["cancer "], query_params["query"]
81
+ end
82
+
83
+ test_with_cassette("live search smoke test", :ebscohost) do
84
+
85
+ results = @engine.search(:query => "cancer")
86
+
87
+ assert_present results
88
+ assert ! results.failed?
89
+
90
+ first = results.first
91
+
92
+ assert_present first.title
93
+ assert_present first.authors
94
+ assert_present first.year
95
+
96
+ assert_present first.format
97
+ assert_present first.format_str
98
+ end
99
+
100
+ test_with_cassette("get_info", :ebscohost) do
101
+ xml = @engine.get_info
102
+
103
+ assert_present xml
104
+
105
+ assert_present xml.xpath("./info/dbInfo/db")
106
+ end
107
+
108
+ test_with_cassette("error bad password", :ebscohost) do
109
+ error_engine = BentoSearch::EbscoHostEngine.new(
110
+ :profile_id => "bad",
111
+ :profile_password => "bad",
112
+ :databases => @@dbs_to_test
113
+ )
114
+
115
+ results = error_engine.search(:query => "cancer")
116
+ assert results.failed?
117
+ assert_present results.error[:error_info]
118
+ end
119
+
120
+
121
+ test_with_cassette("error bad db", :ebscohost) do
122
+ error_engine = BentoSearch::EbscoHostEngine.new(
123
+ :profile_id => @@profile_id,
124
+ :profile_password => @@profile_pwd,
125
+ :databases => ["bad", "does_not_exist"]
126
+ )
127
+
128
+ results = error_engine.search(:query => "cancer")
129
+ assert results.failed?
130
+ assert_present results.error[:error_info]
131
+
132
+ end
133
+
134
+ end
@@ -0,0 +1,105 @@
1
+ require 'test_helper'
2
+
3
+ class EdsEngineTest < ActiveSupport::TestCase
4
+ extend TestWithCassette
5
+
6
+ @@user_id = (ENV['EDS_USER_ID'] || 'DUMMY_USER_ID')
7
+ @@password = (ENV['EDS_PASSWORD'] || 'DUMMY_PWD')
8
+ @@profile = (ENV['EDS_PROFILE'] || 'edsapi')
9
+
10
+
11
+ VCR.configure do |c|
12
+ c.filter_sensitive_data("DUMMY_USER_ID", :eds) { @@user_id }
13
+ c.filter_sensitive_data("DUMMY_PWD", :eds) { @@password }
14
+ end
15
+
16
+ def setup
17
+ # Class-level remembered auth token messes up our VCR-recording,
18
+ # since one test will try to use an auth token fetched by a different
19
+ # test. For testing, blank out the cache before each test.
20
+ BentoSearch::EdsEngine.remembered_auth = nil
21
+
22
+
23
+ @engine = BentoSearch::EdsEngine.new(:user_id => @@user_id, :password => @@password, :profile => @@profile, :auth => true)
24
+ end
25
+
26
+ test_with_cassette("get_auth_token failure", :eds) do
27
+ engine = BentoSearch::EdsEngine.new(:user_id => "bad", :password => "bad", :profile => "bad")
28
+ exception = assert_raise(BentoSearch::EdsEngine::EdsCommException) do
29
+ token = engine.get_auth_token
30
+ end
31
+
32
+ assert_present exception.http_status
33
+ assert_present exception.http_body
34
+ end
35
+
36
+ test_with_cassette("get_auth_token", :eds) do
37
+ token = @engine.get_auth_token
38
+
39
+ assert_present token
40
+ end
41
+
42
+ # No idea why VCR is having buggy problems with record and playback of this request
43
+ # We'll emcompass it in the get_with_auth test
44
+ #
45
+ #test_with_cassette("with_session", :eds, :match_requests_on => [:method, :uri, :headers, :body]) do
46
+ # @engine.with_session do |session_token|
47
+ # assert_present session_token
48
+ # end
49
+ #end
50
+
51
+ test_with_cassette("get_with_auth", :eds) do
52
+ @engine.with_session do |session_token|
53
+ assert_present session_token
54
+
55
+ # Coudln't get 'info' request to work even as a test, let's
56
+ # try a simple search.
57
+ url = "#{@engine.configuration.base_url}info"
58
+ response = @engine.get_with_auth(url, session_token)
59
+
60
+ assert_present response
61
+ assert_kind_of Nokogiri::XML::Document, response
62
+
63
+ assert_nil response.at_xpath("//ErrorNumber"), "no error report in result"
64
+ end
65
+ end
66
+
67
+ test_with_cassette("get_with_auth recovers from bad auth", :eds) do
68
+ @engine.with_session do |session_token|
69
+ BentoSearch::EdsEngine.remembered_auth = "BAD"
70
+
71
+ url = "#{@engine.configuration.base_url}info"
72
+ response = @engine.get_with_auth(url, session_token)
73
+
74
+ assert_present response
75
+ assert_kind_of Nokogiri::XML::Document, response
76
+
77
+ assert_nil response.at_xpath("//ErrorNumber"), "no error report in result"
78
+ end
79
+
80
+ BentoSearch::EdsEngine.remembered_auth = nil
81
+ end
82
+
83
+ test_with_cassette("basic search smoke test", :eds) do
84
+ results = @engine.search("cancer")
85
+
86
+ assert_present results
87
+
88
+ assert_present results.total_items
89
+
90
+ first = results.first
91
+
92
+ assert_present first.title
93
+ assert first.title.html_safe? # yeah, for now we use EDS html
94
+
95
+ assert_present first.abstract
96
+ assert_present first.abstract.html_safe?
97
+
98
+ assert_present first.custom_data["citation_blob"]
99
+
100
+ assert_present first.format_str
101
+ end
102
+
103
+
104
+ end
105
+
@@ -0,0 +1,93 @@
1
+ require 'test_helper'
2
+
3
+ class GoogleBooksEngineTest < ActiveSupport::TestCase
4
+ extend TestWithCassette
5
+
6
+ def setup
7
+ @engine = BentoSearch::GoogleBooksEngine.new
8
+ # tell it not to send our bad API key
9
+ end
10
+
11
+
12
+
13
+ test_with_cassette("search", :gbs) do
14
+ results = @engine.search("cancer")
15
+
16
+ assert_kind_of BentoSearch::Results, results
17
+
18
+ assert ! results.failed?
19
+
20
+ assert_not_nil results.total_items
21
+ assert_equal 0, results.start
22
+ assert_equal 10, results.per_page
23
+
24
+ assert_not_empty results
25
+
26
+ first = results.first
27
+
28
+ assert_kind_of BentoSearch::ResultItem, first
29
+
30
+ assert_not_empty first.title
31
+ assert_not_empty first.publisher
32
+ assert_not_empty first.link
33
+ assert_not_empty first.format
34
+ assert_not_nil first.year
35
+ assert_not_empty first.abstract
36
+ assert first.abstract.html_safe?
37
+
38
+
39
+ assert_not_empty first.authors
40
+ assert_not_empty first.authors.first.display
41
+ end
42
+
43
+ test_with_cassette("pagination", :gbs) do
44
+ results = @engine.search("cancer", :per_page => 20, :start => 40)
45
+
46
+ assert ! results.failed?
47
+
48
+ assert_equal 20, results.length
49
+
50
+ assert_equal 20, results.per_page
51
+ assert_equal 20, results.size
52
+ assert_equal 40, results.start
53
+ end
54
+
55
+
56
+
57
+ test_with_cassette("error condition", :gbs) do
58
+ # send a bad API key on purpose to get error
59
+ @engine = BentoSearch::GoogleBooksEngine.new(:api_key => "BAD_KEY")
60
+
61
+ results = @engine.search("cancer")
62
+
63
+ assert results.failed?
64
+ assert_not_nil results.error
65
+ assert_not_nil results.error[:status]
66
+ assert_not_nil results.error[:error_info]
67
+ end
68
+
69
+
70
+ def test_sort_construction
71
+ url = @engine.send(:args_to_search_url, :query => "cancer", :sort => "date_desc")
72
+
73
+ assert_match '&sort=newest', url
74
+
75
+ url = @engine.send(:args_to_search_url, :query => "cancer", :sort => "relevance")
76
+
77
+ assert_not_match "&sort", url
78
+ end
79
+
80
+ def test_fielded_search
81
+ # Have to use protected methods to get at what we want to test.
82
+ # Is there a better way to factor this for testing?
83
+ norm_args = @engine.send(:parse_search_arguments, 'cancer "by radiation"', :search_field => :intitle)
84
+ url = @engine.send(:args_to_search_url, norm_args)
85
+
86
+ query_params = CGI.parse( URI.parse(url).query )
87
+
88
+ assert_match /^|\sintitle\:cancer\s|$/, query_params["q"].first
89
+ assert_match /^|\sintitle\:"by radiation"\s|$/, query_params["q"].first
90
+ end
91
+
92
+
93
+ end
@@ -0,0 +1,66 @@
1
+ require 'test_helper'
2
+
3
+ class LinkDecoratorsTest < ActiveSupport::TestCase
4
+ # simple decorator that replaces main link
5
+ module Decorator
6
+ def link
7
+ "http://newlink.com"
8
+ end
9
+
10
+ def other_links
11
+ super + [ BentoSearch::Link.new(:label => "One", :url => "http://one.com") ]
12
+ end
13
+ end
14
+
15
+ setup do
16
+ @engine = MockEngine.new(:item_decorators => [Decorator])
17
+ end
18
+
19
+ test "decorators" do
20
+ results = @engine.search(:query => "Query")
21
+
22
+ assert_present results
23
+
24
+ results.each do |result|
25
+ assert_kind_of Decorator, result
26
+
27
+ assert_equal "http://newlink.com", result.link
28
+
29
+ assert_present result.other_links
30
+
31
+ assert_equal "One", result.other_links.first.label
32
+ assert_equal "http://one.com", result.other_links.first.url
33
+ end
34
+ end
35
+
36
+ # Is it a good idea to have a decorator that mutates on 'extend'?
37
+ # I'm not sure, I think probably not, but it is possible.
38
+ # Here we'll use it to move an original link to other links
39
+ module MutatingDecorator
40
+ def self.extended(item)
41
+ orig_link = item.link
42
+
43
+ item.link = nil
44
+
45
+ item.other_links << BentoSearch::Link.new(:label => "Some Other", :url => orig_link)
46
+ end
47
+ end
48
+
49
+ test "mutating decorator" do
50
+ @engine = MockEngine.new(:item_decorators => [MutatingDecorator], :link => "http://example2.org")
51
+ results = @engine.search("query")
52
+
53
+ assert_present results
54
+
55
+ results.each do |result|
56
+ assert_blank result.link
57
+ assert_equal "http://example2.org", result.other_links.first.url
58
+ assert_equal "Some Other", result.other_links.first.label
59
+ end
60
+
61
+ end
62
+
63
+
64
+
65
+
66
+ end
@@ -0,0 +1,49 @@
1
+ require 'test_helper'
2
+
3
+ # Doesn't really test the concurrency, but basic smoke test with fake
4
+ # searchers.
5
+ class MultiSearcherTest < ActiveSupport::TestCase
6
+ setup do
7
+ BentoSearch.register_engine("one") do |conf|
8
+ conf.engine = "MockEngine"
9
+ end
10
+ BentoSearch.register_engine("two") do |conf|
11
+ conf.engine = "MockEngine"
12
+ end
13
+ BentoSearch.register_engine("three") do |conf|
14
+ conf.engine = "MockEngine"
15
+ end
16
+ end
17
+
18
+ teardown do
19
+ BentoSearch.reset_engine_registrations!
20
+ end
21
+
22
+
23
+ def test_multisearch
24
+ searcher = BentoSearch::MultiSearcher.new(:one, :two, :three)
25
+ start_returnval = searcher.start("cancer")
26
+
27
+ assert_same searcher, start_returnval
28
+
29
+ results = searcher.results
30
+
31
+ assert_kind_of Hash, results
32
+ assert_equal ["one", "two", "three"].sort, results.keys.sort
33
+
34
+ ["one", "two", "three"].each do |key|
35
+ assert_kind_of BentoSearch::Results, results[key]
36
+ end
37
+
38
+ # call results again, we get an empty hash, can only call
39
+ # results once per start.
40
+ new_results = searcher.results
41
+ assert_kind_of Hash, new_results
42
+ assert_empty new_results
43
+
44
+ end
45
+
46
+
47
+
48
+
49
+ end