bento_search 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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