lucid_works 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +1 -0
- data/.gitignore +5 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +11 -0
- data/Rakefile +7 -0
- data/lib/lucid_works.rb +26 -0
- data/lib/lucid_works/associations.rb +118 -0
- data/lib/lucid_works/base.rb +274 -0
- data/lib/lucid_works/collection.rb +14 -0
- data/lib/lucid_works/collection/index.rb +9 -0
- data/lib/lucid_works/collection/info.rb +9 -0
- data/lib/lucid_works/collection/settings.rb +9 -0
- data/lib/lucid_works/datasource.rb +40 -0
- data/lib/lucid_works/datasource/history.rb +17 -0
- data/lib/lucid_works/datasource/index.rb +9 -0
- data/lib/lucid_works/datasource/schedule.rb +9 -0
- data/lib/lucid_works/datasource/status.rb +9 -0
- data/lib/lucid_works/exceptions.rb +6 -0
- data/lib/lucid_works/patch_restclient.rb +29 -0
- data/lib/lucid_works/server.rb +23 -0
- data/lib/lucid_works/version.rb +3 -0
- data/lucid_works.gemspec +26 -0
- data/spec/lib/lucid_works/associations_spec.rb +130 -0
- data/spec/lib/lucid_works/base_spec.rb +399 -0
- data/spec/lib/lucid_works/collection_spec.rb +231 -0
- data/spec/lib/lucid_works/datasource_spec.rb +280 -0
- data/spec/lib/lucid_works/server_spec.rb +39 -0
- data/spec/spec_helper.rb +47 -0
- metadata +133 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
module LucidWorks
|
2
|
+
|
3
|
+
class Datasource < Base
|
4
|
+
belongs_to :collection
|
5
|
+
has_many :histories, :class_name => :history
|
6
|
+
has_one :status, :history, :schedule, :index
|
7
|
+
|
8
|
+
TYPES = {
|
9
|
+
:FileSystemDataSource => {
|
10
|
+
:name_l10n_key => 'data_source.short_type.filesystem',
|
11
|
+
:crawler => 'lucid.aperture',
|
12
|
+
:type => 'file'
|
13
|
+
},
|
14
|
+
:WebDataSource => {
|
15
|
+
:name_l10n_key => 'data_source.short_type.web_site',
|
16
|
+
:crawler => 'lucid.aperture',
|
17
|
+
:type => 'web'
|
18
|
+
},
|
19
|
+
:SolrXmlDataSource => {
|
20
|
+
:name_l10n_key => 'data_source.short_type.solr',
|
21
|
+
:crawler => 'lucid.solrxml',
|
22
|
+
:type => 'solrxml'
|
23
|
+
},
|
24
|
+
:JDBCDataSource => {
|
25
|
+
:name_l10n_key => 'data_source.short_type.database',
|
26
|
+
:crawler => 'lucid.jdbc',
|
27
|
+
:type => 'jdbc'
|
28
|
+
},
|
29
|
+
:SharePointDataSource => {
|
30
|
+
:name_l10n_key => 'data_source.short_type.sharepoint',
|
31
|
+
:crawler => 'lucid.gcm',
|
32
|
+
:type => 'sharepoint'
|
33
|
+
}
|
34
|
+
}.with_indifferent_access
|
35
|
+
|
36
|
+
def empty!
|
37
|
+
build_index.destroy
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module LucidWorks
|
2
|
+
class Datasource
|
3
|
+
|
4
|
+
class History < Base
|
5
|
+
belongs_to :datasource
|
6
|
+
self.collection_name = 'history' # i.e. not the plural 'histories'
|
7
|
+
|
8
|
+
def doc_count
|
9
|
+
numUpdated + numNew + numUnchanged
|
10
|
+
end
|
11
|
+
|
12
|
+
def elapsed_time
|
13
|
+
crawlStopped.to_datetime - crawlStarted.to_datetime
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module RestClient
|
2
|
+
class Request
|
3
|
+
|
4
|
+
# Extract the query parameters for get request and append them to the url
|
5
|
+
def process_get_params url, headers
|
6
|
+
# LucidWorks: we also need params on a :delete
|
7
|
+
if [:get, :head, :delete].include? method
|
8
|
+
# if [:get, :head].include? method
|
9
|
+
get_params = {}
|
10
|
+
headers.delete_if do |key, value|
|
11
|
+
if 'params' == key.to_s.downcase && value.is_a?(Hash)
|
12
|
+
get_params.merge! value
|
13
|
+
true
|
14
|
+
else
|
15
|
+
false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
unless get_params.empty?
|
19
|
+
query_string = get_params.collect { |k, v| "#{k.to_s}=#{CGI::escape(v.to_s)}" }.join('&')
|
20
|
+
url + "?#{query_string}"
|
21
|
+
else
|
22
|
+
url
|
23
|
+
end
|
24
|
+
else
|
25
|
+
url
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module LucidWorks
|
2
|
+
#
|
3
|
+
# The LucidWorks::Server class is the starting point for access to a LucidWorks Solr search server.
|
4
|
+
#
|
5
|
+
class Server
|
6
|
+
include Associations
|
7
|
+
|
8
|
+
has_many :collections
|
9
|
+
|
10
|
+
DEFAULT_REST_API_PATH = "/api"
|
11
|
+
|
12
|
+
attr_accessor :host, :path
|
13
|
+
|
14
|
+
def initialize(server_uri, options = {})
|
15
|
+
@host = server_uri
|
16
|
+
@path = options.delete(:path) || DEFAULT_REST_API_PATH
|
17
|
+
end
|
18
|
+
|
19
|
+
def uri
|
20
|
+
@host + @path
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lucid_works.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "lucid_works/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "lucid_works"
|
7
|
+
s.version = LucidWorks::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Sam Pierson"]
|
10
|
+
s.email = ["sam.pierson@lucidimagination.com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{Ruby wrapper for the LucidWorks REST API}
|
13
|
+
s.description = %q{Ruby wrapper for the LucidWorks REST API}
|
14
|
+
|
15
|
+
s.rubyforge_project = "lucid_works"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_runtime_dependency 'activesupport', '>= 3'
|
23
|
+
s.add_runtime_dependency 'activemodel', '>= 3'
|
24
|
+
s.add_runtime_dependency 'rest-client', '>= 1.6.1'
|
25
|
+
s.add_runtime_dependency 'json'
|
26
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe LucidWorks::Associations do
|
4
|
+
before :all do
|
5
|
+
@fake_server_uri = "http://fakehost.com:8888"
|
6
|
+
@server = LucidWorks::Server.new(@fake_server_uri)
|
7
|
+
|
8
|
+
class ::Blog < LucidWorks::Base
|
9
|
+
has_many :posts
|
10
|
+
has_one :homepage
|
11
|
+
end
|
12
|
+
@blog = ::Blog.new(:parent => @server)
|
13
|
+
|
14
|
+
class ::Post < LucidWorks::Base
|
15
|
+
belongs_to :blog
|
16
|
+
end
|
17
|
+
|
18
|
+
class ::Homepage < LucidWorks::Base
|
19
|
+
self.singleton = true
|
20
|
+
belongs_to :blog
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe ".has_one" do
|
25
|
+
describe "#<child>!" do
|
26
|
+
it "should call Child.find" do
|
27
|
+
Homepage.should_receive(:find).with(:parent => @blog)
|
28
|
+
@blog.homepage!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#<child>" do
|
33
|
+
it "should call child! the first time then return the cached value thereafter" do
|
34
|
+
mock_homepage = double('homepage')
|
35
|
+
Homepage.should_receive(:find).once.and_return(mock_homepage)
|
36
|
+
@blog.homepage.should == mock_homepage
|
37
|
+
@blog.homepage.should == mock_homepage
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#build_<child>" do
|
42
|
+
it "should create a new child with persisted = true" do
|
43
|
+
homepage = @blog.build_homepage
|
44
|
+
homepage.should be_a(Homepage)
|
45
|
+
homepage.should be_persisted
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe ".has_many" do
|
51
|
+
describe "#<children>!" do
|
52
|
+
it "should call Child.all" do
|
53
|
+
Post.should_receive(:all).with(:parent => @blog)
|
54
|
+
@blog.posts!
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#<children>" do
|
59
|
+
it "should call children! the first time then return the cached value thereafter" do
|
60
|
+
mock_posts = double('some posts')
|
61
|
+
Post.should_receive(:find).once.and_return(mock_posts)
|
62
|
+
@blog.posts.should == mock_posts
|
63
|
+
@blog.posts.should == mock_posts
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "#<child>" do
|
68
|
+
it "should call Child.find" do
|
69
|
+
Post.should_receive(:find).with('child_id', :parent => @blog)
|
70
|
+
@blog.post('child_id')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "create_<child>" do
|
75
|
+
it "should call Child.create" do
|
76
|
+
Post.should_receive(:create).with(:name => 'child_name', :parent => @blog)
|
77
|
+
@blog.create_post(:name => 'child_name')
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "#build_<child>" do
|
82
|
+
it "should create a new child with persisted = true" do
|
83
|
+
post = @blog.build_post
|
84
|
+
post.should be_a(Post)
|
85
|
+
post.should_not be_persisted
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe ".belongs_to" do
|
91
|
+
|
92
|
+
describe ".belongs_to_association_name (private)" do
|
93
|
+
it "should return the name of the association" do
|
94
|
+
Post.send(:belongs_to_association_name).should == :blog
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe ".parent_class" do
|
99
|
+
it "should return the parent class" do
|
100
|
+
Post.parent_class.should == Blog
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "#initialize" do
|
105
|
+
it "should allow :<association_name> instead of :parent" do
|
106
|
+
lambda {
|
107
|
+
Post.new(:blog => @blog)
|
108
|
+
}.should_not raise_error
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "#collection_url" do
|
113
|
+
it "should generate a url using its parents url and it's own name" do
|
114
|
+
@blog.id = 'fake_blog_id'
|
115
|
+
post = Post.new(:parent => @blog)
|
116
|
+
post.id = 'fake_post_id'
|
117
|
+
post.collection_url.should == "http://fakehost.com:8888/api/blogs/fake_blog_id/posts"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe "#member_url" do
|
122
|
+
it "should generate a url using its parents url and it's own name and id" do
|
123
|
+
@blog.id = 'fake_blog_id'
|
124
|
+
post = Post.new(:parent => @blog)
|
125
|
+
post.id = 'fake_post_id'
|
126
|
+
post.send(:member_url).should == "http://fakehost.com:8888/api/blogs/fake_blog_id/posts/fake_post_id"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,399 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe LucidWorks::Base do
|
4
|
+
before :all do
|
5
|
+
fake_server = "http://127.0.0.1:123456"
|
6
|
+
@server = LucidWorks::Server.new(fake_server)
|
7
|
+
@fake_server_uri = "#{fake_server}/api"
|
8
|
+
|
9
|
+
class Widget < LucidWorks::Base
|
10
|
+
has_one :singleton_widget
|
11
|
+
end
|
12
|
+
WIDGET1_JSON = '{"id":1,"name":"widget1","size":"small"}'
|
13
|
+
WIDGET2_JSON = '{"id":2,"name":"widget2","size":"medium"}'
|
14
|
+
WIDGETS_JSON = "[#{WIDGET1_JSON},#{WIDGET2_JSON}]"
|
15
|
+
|
16
|
+
class SingletonWidget < LucidWorks::Base
|
17
|
+
self.singleton = true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "class methods" do
|
22
|
+
describe ".new" do
|
23
|
+
it "should require a hash argument" do
|
24
|
+
lambda {
|
25
|
+
Widget.new(@server)
|
26
|
+
}.should raise_error(ArgumentError)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should raise if not supplied with a server or parent" do
|
30
|
+
lambda {
|
31
|
+
Widget.new({})
|
32
|
+
}.should raise_error(ArgumentError)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should raise if the provided parent is not a LucidWorks::Server or LucidWorks::Base" do
|
36
|
+
lambda {
|
37
|
+
Widget.new(:parent => "bogoserver")
|
38
|
+
}.should raise_error(ArgumentError)
|
39
|
+
|
40
|
+
lambda {
|
41
|
+
@parent = Widget.new(:parent => @server)
|
42
|
+
}.should_not raise_error
|
43
|
+
|
44
|
+
lambda {
|
45
|
+
Widget.new(:parent => @parent)
|
46
|
+
}.should_not raise_error
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should raise if the provided parent is not a LucidWorks::Base" do
|
50
|
+
lambda {
|
51
|
+
Widget.new(:parent => "bogoparent")
|
52
|
+
}.should raise_error(ArgumentError)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should save the parent" do
|
56
|
+
widget = Widget.new(:parent => @server)
|
57
|
+
widget.parent.should == @server
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should save all its attributes" do
|
61
|
+
widget = Widget.new(:name => 'fake_name', :size => 'fake_size', :parent => @server)
|
62
|
+
widget.name.should == 'fake_name'
|
63
|
+
widget.size.should == 'fake_size'
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should default persisted to false" do
|
67
|
+
widget = Widget.new(:parent => @server)
|
68
|
+
widget.should_not be_persisted
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should save persisted if provided" do
|
72
|
+
widget = Widget.new(:persisted => true, :parent => @server)
|
73
|
+
widget.should be_persisted
|
74
|
+
end
|
75
|
+
|
76
|
+
context "for a singleton" do
|
77
|
+
it "should always set singleton" do
|
78
|
+
widget = SingletonWidget.new(:parent => @server)
|
79
|
+
widget.should be_persisted
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe ".create" do
|
85
|
+
it "should call new and save" do
|
86
|
+
mock_widget = double('a mock widget')
|
87
|
+
Widget.should_receive(:new).with('fake_args').and_return(mock_widget)
|
88
|
+
mock_widget.should_receive(:save)
|
89
|
+
Widget.create('fake_args')
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe ".find" do
|
94
|
+
context ":all" do
|
95
|
+
it "should call RestClient.get with the appropriate URL and parse the response into models" do
|
96
|
+
correct_url = "#{@fake_server_uri}/widgets"
|
97
|
+
RestClient.should_receive(:get).with(correct_url).and_return(WIDGETS_JSON)
|
98
|
+
|
99
|
+
widgets = Widget.find(:all, :parent => @server)
|
100
|
+
widgets.size.should == 2
|
101
|
+
|
102
|
+
widget1 = widgets.find { |c| c.id == 1 }
|
103
|
+
widget1.should be_a(Widget)
|
104
|
+
widget1.name.should == 'widget1'
|
105
|
+
widget1.size.should == 'small'
|
106
|
+
|
107
|
+
widget2 = widgets.find { |c| c.id == 2 }
|
108
|
+
widget2.should be_a(Widget)
|
109
|
+
widget2.name.should == 'widget2'
|
110
|
+
widget2.size.should == 'medium'
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context ":one" do
|
115
|
+
it "should call RestClient.get with the appropriate URL and parse the response into a model" do
|
116
|
+
correct_url = "#{@fake_server_uri}/widgets/1"
|
117
|
+
RestClient.should_receive(:get).with(correct_url).and_return(WIDGET1_JSON)
|
118
|
+
|
119
|
+
widget = Widget.find(:one, 1, :parent => @server)
|
120
|
+
widget.should be_a(Widget)
|
121
|
+
widget.name.should == 'widget1'
|
122
|
+
widget.size.should == 'small'
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context ":singleton" do
|
127
|
+
it "should call RestClient.get with the appropriate URL and parse the response into a model" do
|
128
|
+
correct_url = "#{@fake_server_uri}/singleton_widget"
|
129
|
+
RestClient.should_receive(:get).with(correct_url).and_return(WIDGET1_JSON)
|
130
|
+
|
131
|
+
widget = SingletonWidget.find(:singleton, :parent => @server)
|
132
|
+
widget.should be_a(SingletonWidget)
|
133
|
+
widget.name.should == 'widget1'
|
134
|
+
widget.size.should == 'small'
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe ":include option" do
|
139
|
+
context "with a single argument" do
|
140
|
+
it "should retrieve the :included submodel" do
|
141
|
+
RestClient.should_receive(:get).with("#{@fake_server_uri}/widgets").and_return(WIDGETS_JSON)
|
142
|
+
mock_singleton1 = double('singleton widget1')
|
143
|
+
mock_singleton2 = double('singleton widget2')
|
144
|
+
SingletonWidget.should_receive(:find).and_return(mock_singleton1, mock_singleton2)
|
145
|
+
|
146
|
+
widgets = Widget.find(:all, :include => :singleton_widget, :parent => @server)
|
147
|
+
|
148
|
+
widgets.first.singleton_widget.should == mock_singleton1
|
149
|
+
widgets.last.singleton_widget.should == mock_singleton2
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context "with a list of submodels" do
|
154
|
+
before :all do
|
155
|
+
# Give widget a second submodel
|
156
|
+
class Widget < LucidWorks::Base ; has_many :other_widgets ; end
|
157
|
+
class OtherWidget < LucidWorks::Base ; belongs_to :widget ; end
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should retrieve all the :included submodels" do
|
161
|
+
RestClient.should_receive(:get).with("#{@fake_server_uri}/widgets").and_return(WIDGETS_JSON)
|
162
|
+
mock_singleton1 = double('singleton widget1')
|
163
|
+
mock_singleton2 = double('singleton widget2')
|
164
|
+
mock_other_widgets_1 = double('other widgets 1')
|
165
|
+
mock_other_widgets_2 = double('other widgets 2')
|
166
|
+
SingletonWidget.should_receive(:find).and_return(mock_singleton1, mock_singleton2)
|
167
|
+
OtherWidget.should_receive(:find).and_return(mock_other_widgets_1, mock_other_widgets_2)
|
168
|
+
|
169
|
+
widgets = Widget.find(:all, :include => [:singleton_widget, :other_widgets], :parent => @server)
|
170
|
+
|
171
|
+
widgets.first.singleton_widget.should == mock_singleton1
|
172
|
+
widgets.first.other_widgets.should == mock_other_widgets_1
|
173
|
+
widgets.last.singleton_widget.should == mock_singleton2
|
174
|
+
widgets.last.other_widgets.should == mock_other_widgets_2
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe ".all" do
|
181
|
+
it "should call find(:all)" do
|
182
|
+
Widget.should_receive(:find).with(:all, :parent => @server).and_return([])
|
183
|
+
|
184
|
+
Widget.all(:parent => @server)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
describe ".first" do
|
189
|
+
it "should call find(:all) and return the first" do
|
190
|
+
mock_coll1 = double("collection 1")
|
191
|
+
mock_coll2 = double("collection 2")
|
192
|
+
Widget.should_receive(:find).with(:all, :parent => @server).and_return([mock_coll1, mock_coll2])
|
193
|
+
|
194
|
+
Widget.first(:parent => @server).should == mock_coll1
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
describe "instance methods" do
|
200
|
+
|
201
|
+
describe "collection_url" do
|
202
|
+
it "should generate a url from the server and its name" do
|
203
|
+
widget = Widget.new(:parent => @server, :id => 1234)
|
204
|
+
widget.collection_url.should == "#{@fake_server_uri}/widgets"
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
describe "member_url" do
|
209
|
+
it "should generate a url from the server, its name and its id" do
|
210
|
+
widget = Widget.new(:parent => @server, :id => 1234)
|
211
|
+
widget.member_url.should == "#{@fake_server_uri}/widgets/1234"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
describe "attributes" do
|
216
|
+
before { @widget = Widget.new(:known_attr => 'known_value', :nil_attr => nil, :parent => @server) }
|
217
|
+
|
218
|
+
describe '#attr=' do
|
219
|
+
context "for an unknown attr" do
|
220
|
+
it "should set an attribute" do
|
221
|
+
@widget.new_attr = "fake_value"
|
222
|
+
@widget.new_attr.should == 'fake_value'
|
223
|
+
end
|
224
|
+
end
|
225
|
+
context "for a known attr" do
|
226
|
+
it "should set an attribute" do
|
227
|
+
@widget.known_attr = "new_value"
|
228
|
+
@widget.known_attr.should == 'new_value'
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
describe "#attr" do
|
234
|
+
context "for an unknown attr" do
|
235
|
+
it "should raise an error" do
|
236
|
+
lambda {
|
237
|
+
@widget.bogus_attr
|
238
|
+
}.should raise_error("Unknown attribute: 'bogus_attr'")
|
239
|
+
end
|
240
|
+
end
|
241
|
+
context "for a known attr" do
|
242
|
+
it "should return the attr" do
|
243
|
+
@widget.known_attr.should == 'known_value'
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
describe "#attr?" do
|
249
|
+
context "for an unknown attr" do
|
250
|
+
it "should raise an error" do
|
251
|
+
lambda {
|
252
|
+
@widget.bogus_attr?
|
253
|
+
}.should raise_error("Unknown attribute: 'bogus_attr'")
|
254
|
+
end
|
255
|
+
end
|
256
|
+
context "for a known attr" do
|
257
|
+
it "should return true or false" do
|
258
|
+
@widget.known_attr?.should be_true
|
259
|
+
@widget.nil_attr?.should be_false
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
describe "#save" do
|
266
|
+
context "for a new model" do
|
267
|
+
context "with valid attributes" do
|
268
|
+
before do
|
269
|
+
@widget_attrs = { :name => 'widget3', :size => 'large' }
|
270
|
+
@widget = Widget.new @widget_attrs.merge(:parent => @server)
|
271
|
+
end
|
272
|
+
|
273
|
+
it "should post to the correct address" do
|
274
|
+
correct_url = "#{@fake_server_uri}/widgets"
|
275
|
+
expected_json = @widget_attrs.to_json
|
276
|
+
RestClient.should_receive(:post).with(correct_url, expected_json, :content_type => :json)
|
277
|
+
@widget.save
|
278
|
+
end
|
279
|
+
|
280
|
+
it "should set persisted" do
|
281
|
+
RestClient.should_receive(:post)
|
282
|
+
@widget.save
|
283
|
+
@widget.should be_persisted
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
context "with invalid attributes" do
|
288
|
+
before :all do
|
289
|
+
@widget_attrs = { :name => '', :size => ''}
|
290
|
+
ERROR_422_RESPONSE = '{"errors":[{"message":"name is a required key","key":"name"},{"message":"name must consist of only A-Z a-z 0-9 - _","key":"name"}],"http_status_name":"Unprocessable Entity","http_status_code":422}'
|
291
|
+
# ERROR_500_RESPONSE = '{"errors":[{"message":"The server encountered an unexpected condition which prevented it from fulfilling the request","key":""}],"http_status_name":"Internal Server Error","http_status_code":500}'
|
292
|
+
RestClient.stub(:post) {
|
293
|
+
e = RestClient::UnprocessableEntity.new
|
294
|
+
e.response = ERROR_422_RESPONSE
|
295
|
+
raise e
|
296
|
+
}
|
297
|
+
|
298
|
+
@widget = Widget.new @widget_attrs.merge(:parent => @server)
|
299
|
+
@returncode = @widget.save
|
300
|
+
end
|
301
|
+
|
302
|
+
it "should set errors on the model" do
|
303
|
+
@widget.errors.should_not be_empty
|
304
|
+
@widget.errors['name'].should_not be_empty
|
305
|
+
end
|
306
|
+
|
307
|
+
it "should not set persisted" do
|
308
|
+
@widget.should_not be_persisted
|
309
|
+
end
|
310
|
+
|
311
|
+
it "should return false" do
|
312
|
+
@returncode.should be_false
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
describe "local validation" do
|
317
|
+
before do
|
318
|
+
class WidgetRequiringName < LucidWorks::Base
|
319
|
+
validates_presence_of :name
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
it "should validate presence of" do
|
324
|
+
widget = WidgetRequiringName.new(:parent => @server)
|
325
|
+
RestClient.should_not_receive(:post)
|
326
|
+
widget.should_not be_valid
|
327
|
+
widget.errors[:name].should == ["can't be blank"]
|
328
|
+
widget.save
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
context "for an existing model" do
|
334
|
+
it "should PUT to the correct address" do
|
335
|
+
@widget_attrs = { :name => 'widget3', :size => 'large' }
|
336
|
+
@widget = Widget.new @widget_attrs.merge(:parent => @server)
|
337
|
+
@widget.persisted = true
|
338
|
+
@widget.id = 1234
|
339
|
+
correct_url = "#{@fake_server_uri}/widgets/#{@widget.id}"
|
340
|
+
expected_json = @widget_attrs.to_json
|
341
|
+
|
342
|
+
RestClient.should_receive(:put).with(correct_url, expected_json, :content_type => :json)
|
343
|
+
@widget.save
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
context "for a singleton" do
|
348
|
+
before do
|
349
|
+
@widget_attrs = { :name => 'widget3', :size => 'large' }
|
350
|
+
@widget = SingletonWidget.new(@widget_attrs.merge :parent => @server, :persisted => true)
|
351
|
+
end
|
352
|
+
|
353
|
+
it "should put to the correct address" do
|
354
|
+
expected_json = @widget_attrs.to_json
|
355
|
+
correct_url = "#{@fake_server_uri}/singleton_widget"
|
356
|
+
RestClient.should_receive(:put).with(correct_url, expected_json, :content_type => :json)
|
357
|
+
|
358
|
+
@widget.save
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
describe "#destroy" do
|
364
|
+
it "should call RestClient.delete with the appropriate URL" do
|
365
|
+
widget = Widget.new(:parent => @server)
|
366
|
+
widget.id = 27
|
367
|
+
RestClient.should_receive(:delete).with("#{@fake_server_uri}/widgets/27", {})
|
368
|
+
widget.destroy
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
describe "for a model with primary key other than 'id'" do
|
374
|
+
before :all do
|
375
|
+
class NamedWidget < LucidWorks::Base
|
376
|
+
self.primary_key = :name
|
377
|
+
end
|
378
|
+
NAMED_WIDGET1_JSON = '{"name":"widget1","size":"small"}'
|
379
|
+
NAMED_WIDGET2_JSON = '{"name":"widget2","size":"medium"}'
|
380
|
+
NAMED_WIDGETS_JSON = "[#{WIDGET1_JSON},#{WIDGET2_JSON}]"
|
381
|
+
end
|
382
|
+
|
383
|
+
describe "#id" do
|
384
|
+
it "should return the primary key's value" do
|
385
|
+
w = NamedWidget.new(:name => 'fake_name', :parent => @server)
|
386
|
+
w.id.should == 'fake_name'
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
describe "#id=" do
|
391
|
+
it "should set the primary key's value" do
|
392
|
+
w = NamedWidget.new(:name => 'fake_name', :parent => @server)
|
393
|
+
w.id = 'new_name'
|
394
|
+
w.id.should == 'new_name'
|
395
|
+
w.name.should == 'new_name'
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|