rummageable 0.1.2
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.
- data/lib/rummageable.rb +74 -0
- data/test/rummageable_test.rb +133 -0
- metadata +102 -0
data/lib/rummageable.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require "rest_client"
|
2
|
+
require "json"
|
3
|
+
require "plek"
|
4
|
+
|
5
|
+
module Rummageable
|
6
|
+
|
7
|
+
InvalidDocument = Class.new(RuntimeError)
|
8
|
+
CHUNK_SIZE = 20
|
9
|
+
|
10
|
+
attr_writer :rummager_service_name
|
11
|
+
def rummager_service_name
|
12
|
+
@rummager_service_name || "search"
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_writer :rummager_host
|
16
|
+
def rummager_host
|
17
|
+
@rummager_host || Plek.current.find(rummager_service_name)
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_writer :path_prefix
|
21
|
+
def path_prefix
|
22
|
+
@path_prefix || ""
|
23
|
+
end
|
24
|
+
|
25
|
+
# documents must be either a hash (for one document) or an array of hashes
|
26
|
+
# (for multiple documents)
|
27
|
+
#
|
28
|
+
def index(documents)
|
29
|
+
documents = [documents].flatten
|
30
|
+
documents.each do |document|
|
31
|
+
validate_structure document
|
32
|
+
end
|
33
|
+
url = rummager_host + path_prefix + "/documents"
|
34
|
+
0.step(documents.length - 1, CHUNK_SIZE).each do |i|
|
35
|
+
body = JSON.dump(documents[i, CHUNK_SIZE])
|
36
|
+
RestClient.post url, body, content_type: :json, accept: :json
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def delete(link)
|
41
|
+
url = rummager_host + path_prefix + "/documents/" + CGI.escape(link)
|
42
|
+
RestClient.delete url, content_type: :json, accept: :json
|
43
|
+
end
|
44
|
+
|
45
|
+
VALID_KEYS = [
|
46
|
+
%w[title],
|
47
|
+
%w[description],
|
48
|
+
%w[format],
|
49
|
+
%w[section],
|
50
|
+
%w[link],
|
51
|
+
%w[indexable_content],
|
52
|
+
%w[additional_links title],
|
53
|
+
%w[additional_links link],
|
54
|
+
%w[additional_links link_order],
|
55
|
+
]
|
56
|
+
|
57
|
+
def validate_structure(hash, parents=[])
|
58
|
+
hash.each do |key, value|
|
59
|
+
full_key = parents + [key]
|
60
|
+
case value
|
61
|
+
when Array
|
62
|
+
value.each do |el|
|
63
|
+
validate_structure el, full_key
|
64
|
+
end
|
65
|
+
when Hash
|
66
|
+
validate_structure value, full_key
|
67
|
+
else
|
68
|
+
raise InvalidDocument unless VALID_KEYS.include?(full_key)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
extend self
|
74
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require "minitest/autorun"
|
2
|
+
require "webmock/minitest"
|
3
|
+
require "rummageable"
|
4
|
+
ENV["RACK_ENV"] = "test"
|
5
|
+
|
6
|
+
class RummageableTest < MiniTest::Unit::TestCase
|
7
|
+
API = Plek.current.find("search")
|
8
|
+
|
9
|
+
def test_should_index_a_single_document_by_posting_it_as_json
|
10
|
+
document = {
|
11
|
+
"title" => "TITLE",
|
12
|
+
"description" => "DESCRIPTION",
|
13
|
+
"format" => "NAME OF FORMAT",
|
14
|
+
"section" => "NAME OF SECTION",
|
15
|
+
"link" => "/link",
|
16
|
+
"indexable_content" => "TEXT",
|
17
|
+
"additional_links" => [
|
18
|
+
{"title" => "LINK1", "link" => "/link1"},
|
19
|
+
{"title" => "LINK2", "link" => "/link2"},
|
20
|
+
]
|
21
|
+
}
|
22
|
+
json = JSON.dump([document])
|
23
|
+
|
24
|
+
stub_request(:post, "#{API}/documents").
|
25
|
+
with(body: json).
|
26
|
+
to_return(status: 200, body: '{"status":"OK"}')
|
27
|
+
|
28
|
+
Rummageable.index(document)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_should_index_multiple_documents_by_posting_them_as_json
|
32
|
+
documents = [
|
33
|
+
{"title" => "DOC1"},
|
34
|
+
{"title" => "DOC2"}
|
35
|
+
]
|
36
|
+
json = JSON.dump(documents)
|
37
|
+
|
38
|
+
stub_request(:post, "#{API}/documents").
|
39
|
+
with(body: json).
|
40
|
+
to_return(status: 200, body: '{"status":"OK"}')
|
41
|
+
|
42
|
+
Rummageable.index(documents)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_should_send_documents_in_batches_of_20
|
46
|
+
documents = 21.times.map { |i| {"title" => "DOC#{i}"} }
|
47
|
+
|
48
|
+
stub_request(:post, "#{API}/documents").
|
49
|
+
to_return(status: 200, body: '{"status":"OK"}')
|
50
|
+
|
51
|
+
Rummageable.index(documents)
|
52
|
+
assert_requested :post, "#{API}/documents", body: JSON.dump(documents[0, 20])
|
53
|
+
assert_requested :post, "#{API}/documents", body: JSON.dump(documents[20, 1])
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_should_raise_an_exception_if_a_document_has_symbol_keys
|
57
|
+
document = {title: "TITLE"}
|
58
|
+
assert_raises Rummageable::InvalidDocument do
|
59
|
+
Rummageable.index(document)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_should_raise_an_exception_if_a_document_has_unrecognised_keys
|
64
|
+
document = {"foo" => "bar"}
|
65
|
+
assert_raises Rummageable::InvalidDocument do
|
66
|
+
Rummageable.index(document)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_should_raise_an_exception_if_a_document_has_unrecognised_nested_keys
|
71
|
+
document = {
|
72
|
+
"additional_links" => [
|
73
|
+
{"foo" => "bar"}
|
74
|
+
]
|
75
|
+
}
|
76
|
+
assert_raises Rummageable::InvalidDocument do
|
77
|
+
Rummageable.index(document)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_should_post_to_rummageable_host_determined_by_rummager_service_name
|
82
|
+
document = {"title" => "TITLE"}
|
83
|
+
stub_request(:post, "#{API}/documents")
|
84
|
+
stub_request(:post, "http://whitehall-search.test.alphagov.co.uk/documents")
|
85
|
+
with_rummager_service_name("whitehall-search") do
|
86
|
+
Rummageable.index(document)
|
87
|
+
end
|
88
|
+
assert_not_requested(:post, "#{API}/documents")
|
89
|
+
assert_requested(:post, "http://whitehall-search.test.alphagov.co.uk/documents")
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_should_delete_a_document_by_its_link
|
93
|
+
link = "http://example.com/foo"
|
94
|
+
|
95
|
+
stub_request(:delete, "#{API}/documents/http%3A%2F%2Fexample.com%2Ffoo").
|
96
|
+
to_return(status: 200, body: '{"status":"OK"}')
|
97
|
+
|
98
|
+
Rummageable.delete(link)
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_should_delete_to_rummageable_host_determined_by_rummager_service_name
|
102
|
+
link = "http://example.com/foo"
|
103
|
+
stub_request(:delete, "#{API}/documents/http%3A%2F%2Fexample.com%2Ffoo")
|
104
|
+
stub_request(:delete, "http://whitehall-search.test.alphagov.co.uk/documents/http%3A%2F%2Fexample.com%2Ffoo")
|
105
|
+
with_rummager_service_name("whitehall-search") do
|
106
|
+
Rummageable.delete(link)
|
107
|
+
end
|
108
|
+
assert_not_requested(:delete, "#{API}/#{API}/documents/http%3A%2F%2Fexample.com%2Ffoo")
|
109
|
+
assert_requested(:delete, "http://whitehall-search.test.alphagov.co.uk/documents/http%3A%2F%2Fexample.com%2Ffoo")
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_should_defer_to_plek_for_the_location_of_the_rummager_host
|
113
|
+
assert_equal Plek.current.find("search"), Rummageable.rummager_host
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_should_allow_the_rummager_host_to_be_set_manually_so_that_we_can_connect_to_rummager_running_at_arbitrary_locations
|
117
|
+
Rummageable.rummager_host = "http://example.com"
|
118
|
+
assert_equal "http://example.com", Rummageable.rummager_host
|
119
|
+
ensure
|
120
|
+
Rummageable.rummager_host = nil
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def with_rummager_service_name(service_name)
|
126
|
+
original_rummager_service_name = Rummageable.rummager_service_name
|
127
|
+
Rummageable.rummager_service_name = "whitehall-search"
|
128
|
+
yield
|
129
|
+
ensure
|
130
|
+
Rummageable.rummager_service_name = original_rummager_service_name
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
metadata
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rummageable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- GovUK Beta Team
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-01-12 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: json
|
16
|
+
requirement: &70235750717760 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70235750717760
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rest-client
|
27
|
+
requirement: &70235750717320 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70235750717320
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: plek
|
38
|
+
requirement: &70235750716900 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70235750716900
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rake
|
49
|
+
requirement: &70235750716480 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70235750716480
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: webmock
|
60
|
+
requirement: &70235750708840 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70235750708840
|
69
|
+
description: Mediator for apps that want their content to be in the search index
|
70
|
+
email:
|
71
|
+
executables: []
|
72
|
+
extensions: []
|
73
|
+
extra_rdoc_files: []
|
74
|
+
files:
|
75
|
+
- lib/rummageable.rb
|
76
|
+
- test/rummageable_test.rb
|
77
|
+
homepage: https://github.com/alphagov/rummageable
|
78
|
+
licenses: []
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ! '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
requirements: []
|
96
|
+
rubyforge_project:
|
97
|
+
rubygems_version: 1.8.10
|
98
|
+
signing_key:
|
99
|
+
specification_version: 3
|
100
|
+
summary: Mediator for apps that want their content to be in the search index
|
101
|
+
test_files:
|
102
|
+
- test/rummageable_test.rb
|