lucid_works 0.1.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.
- 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
|