cherby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,30 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <BusinessObject Name="JournalNote" RecID="{{rec_id}}">
3
+ <FieldList>
4
+ <!-- Fields common to all BusinessObjects -->
5
+ <Field Name="RecID">{{rec_id}}</Field>
6
+ <Field Name="CreatedDateTime">{{created_date_time}}</Field>
7
+ <Field Name="CreatedBy">{{created_by}}</Field>
8
+ <Field Name="CreatedByID"></Field>
9
+ <Field Name="LastModDateTime">{{last_mod_date_time}}</Field>
10
+ <Field Name="LastModBy">{{last_mod_by}}</Field>
11
+ <Field Name="LastModByID"></Field>
12
+ <Field Name="OwnedBy">{{owned_by}}</Field>
13
+ <Field Name="OwnedByTeam">{{owned_by_team}}</Field>
14
+ <Field Name="OwnerID"></Field>
15
+ <Field Name="OwnerTeamID"></Field>
16
+ <!-- Unused fields? -->
17
+ <Field Name="LastModTimeStamp"/>
18
+
19
+ <Field Name="JournalTypeID">{{journal_type_id}}</Field>
20
+ <Field Name="JournalTypeName">Note</Field>
21
+ <Field Name="ParentTypeID">{{parent_type_id}}</Field>
22
+ <Field Name="ParentRecordID">{{parent_record_id}}</Field>
23
+ <Field Name="Details">{{details}}</Field>
24
+ <Field Name="Priority">Normal</Field>
25
+ <Field Name="ShowInSelfService">TRUE</Field>
26
+ <Field Name="QuickJournal"/>
27
+ <Field Name="IncomingEmail">FALSE</Field>
28
+ </FieldList>
29
+ </BusinessObject>
30
+
@@ -0,0 +1,3 @@
1
+ <Relationship Name="Incident has Notes" TargetObjectID="{{target_object_id}}" TargetObjectName="JournalNote" Type="Owns">
2
+ {{{note_business_object}}}
3
+ </Relationship>
@@ -0,0 +1,67 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <BusinessObject Name="Task" RecID="{{rec_id}}">
3
+ <FieldList>
4
+ <!-- Fields common to all BusinessObjects -->
5
+ <Field Name="RecID">{{rec_id}}</Field>
6
+ <Field Name="CreatedDateTime">{{created_date_time}}</Field>
7
+ <Field Name="CreatedBy">{{created_by}}</Field>
8
+ <Field Name="CreatedByID"></Field>
9
+ <Field Name="LastModDateTime">{{last_mod_date_time}}</Field>
10
+ <Field Name="LastModBy">{{last_mod_by}}</Field>
11
+ <Field Name="LastModByID"></Field>
12
+ <Field Name="OwnedBy">{{owned_by}}</Field>
13
+ <Field Name="OwnedByTeam">{{owned_by_team}}</Field>
14
+ <Field Name="OwnerID"></Field>
15
+ <Field Name="OwnerTeamID"></Field>
16
+ <!-- Unused fields? -->
17
+ <Field Name="LastModTimeStamp"/>
18
+
19
+ <Field Name="TaskType">Action</Field>
20
+ <Field Name="TaskDescription">{{task_description}}</Field>
21
+ <Field Name="StartDateTime">{{start_date_time}}</Field>
22
+ <Field Name="ParentID">{{parent_id}}</Field>
23
+ <Field Name="ParentTypeID">{{parent_type_id}}</Field>
24
+ <Field Name="AssignedToID"></Field>
25
+ <Field Name="AssignedTo"></Field>
26
+ <Field Name="AssignedToTeamID"></Field>
27
+ <Field Name="AssignedToTeam"></Field>
28
+ <Field Name="Notes">{{notes}}</Field>
29
+ <Field Name="AcknowledgedByID"></Field>
30
+ <Field Name="AcknowledgedBy"></Field>
31
+ <Field Name="AcknowledgedDateTime">0001-01-01T00:00:00</Field>
32
+ <Field Name="AcknowledgedComment"></Field>
33
+ <Field Name="ResolvedByID"></Field>
34
+ <Field Name="ResolvedBy"></Field>
35
+ <Field Name="ResolvedDateTime">0001-01-01T00:00:00</Field>
36
+ <Field Name="ResolutionCode">{{resolution_code}}</Field>
37
+ <Field Name="CompletionDetails">{{completion_details}}</Field>
38
+ <Field Name="TaskDurationInHours">0.00</Field>
39
+ <Field Name="Status">{{status}}</Field>
40
+ <Field Name="Availabiltiy"></Field>
41
+ <Field Name="Email"></Field>
42
+ <Field Name="Phone"></Field>
43
+ <Field Name="CellPhone"></Field>
44
+ <Field Name="LimitAssigneeByTeam"></Field>
45
+ <Field Name="ParentTypeName">Incident</Field>
46
+ <Field Name="ParentPublicID">{{parent_public_id}}</Field>
47
+ <Field Name="TaskOrder">0.00</Field>
48
+ <Field Name="ParentActivity"></Field>
49
+ <Field Name="ActivityOrder">0</Field>
50
+ <Field Name="ParentActivityOrder">0</Field>
51
+ <Field Name="DependsOnName"></Field>
52
+ <Field Name="DependsOnID"></Field>
53
+ <Field Name="TaskActive">TRUE</Field>
54
+ <Field Name="DependsOnStatus"></Field>
55
+ <Field Name="Name"></Field>
56
+ <Field Name="EndDateTime">{{end_date_time}}</Field>
57
+ <Field Name="Location"></Field>
58
+ <Field Name="OwnedByNonCherwellUser">FALSE</Field>
59
+ <Field Name="TaskID">{{task_id}}</Field>
60
+ <Field Name="OwnedByEmail">{{owned_by_email}}</Field>
61
+ <Field Name="TeamNotified">FALSE</Field>
62
+ <Field Name="ActiveBy"></Field>
63
+ <Field Name="ActiveByID"></Field>
64
+ <Field Name="ActiveDateTime">0001-01-01T00:00:00</Field>
65
+ <Field Name="CreatedByCustomer">FALSE</Field>
66
+ </FieldList>
67
+ </BusinessObject>
@@ -0,0 +1,3 @@
1
+ <Relationship Name="Incident Has Tasks" TargetObjectName="Task" Type="Owns">
2
+ {{{task_business_object}}}
3
+ </Relationship>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0"?>
2
+ <BusinessObject Name="MySubclass">
3
+ <FieldList>
4
+ <Field Name="First">{{first_name}}</Field>
5
+ <Field Name="Last">{{last_name}}</Field>
6
+ <Field Name="LastModDateTime">{{last_mod_date_time}}</Field>
7
+ </FieldList>
8
+ </BusinessObject>
@@ -0,0 +1,250 @@
1
+ require_relative 'spec_helper'
2
+ require 'cherby/business_object'
3
+
4
+ # Some BusinessObject subclasses to test with
5
+ class MySubclass < Cherby::BusinessObject
6
+ @object_name = 'MySubclass'
7
+ @template = 'test/simple'
8
+ @default_values = {}
9
+ end
10
+
11
+ class MySubclassNoTemplate < Cherby::BusinessObject
12
+ @object_name = 'MySubclassNoTemplate'
13
+ @template = ''
14
+ @default_values = {}
15
+ end
16
+
17
+ class MySubclassNoTemplateFile < Cherby::BusinessObject
18
+ @object_name = 'MySubclassNoTemplateFile'
19
+ @template = 'no_such_file'
20
+ @default_values = {}
21
+ end
22
+
23
+ describe Cherby::BusinessObject do
24
+ context "Class methods" do
25
+ describe "#create" do
26
+ it "sets options in the DOM" do
27
+ obj = MySubclass.create({:first_name => 'Eric', :last_name => 'Idle'})
28
+ first_name = obj.dom.css("BusinessObject[@Name=MySubclass] Field[@Name=First]").first
29
+ last_name = obj.dom.css("BusinessObject[@Name=MySubclass] Field[@Name=Last]").first
30
+ first_name.content.should == "Eric"
31
+ last_name.content.should == "Idle"
32
+ end
33
+
34
+ it "raises an exception when no template is provided" do
35
+ lambda do
36
+ MySubclassNoTemplate.create
37
+ end.should raise_error(RuntimeError, /No template defined/)
38
+ end
39
+
40
+ it "raises an exception if the template file is nonexistent" do
41
+ lambda do
42
+ MySubclassNoTemplateFile.create
43
+ end.should raise_error(Errno::ENOENT, /No such file/)
44
+ end
45
+ end #create
46
+
47
+ describe "#parse_datetime" do
48
+ it "works with timezone offset" do
49
+ bo = Cherby::BusinessObject
50
+ dt = bo.parse_datetime("2012-02-09T09:42:13-05:00")
51
+ dt.to_s.should == "2012-02-09T14:42:13+00:00"
52
+
53
+ dt = bo.parse_datetime("2012-02-09T09:42:13.123-0500")
54
+ dt.to_s.should == "2012-02-09T14:42:13+00:00"
55
+ end
56
+
57
+ it "works without timezone offset" do
58
+ bo = Cherby::BusinessObject
59
+ dt = bo.parse_datetime("2012-02-09T09:42:13", -5)
60
+ dt.to_s.should == "2012-02-09T14:42:13+00:00"
61
+ end
62
+
63
+ it "raises ArgumentError for invalid datetime string" do
64
+ bo = Cherby::BusinessObject
65
+ lambda do
66
+ bo.parse_datetime("bogus-datetime")
67
+ end.should raise_error(ArgumentError, /Could not parse/)
68
+ end
69
+
70
+ end #parse_datetime
71
+
72
+ end # Class methods
73
+
74
+
75
+ context "Instance methods" do
76
+ describe "#initialize" do
77
+ it "accepts an XML string" do
78
+ xml = %Q{
79
+ <BusinessObject Name="MySubclass">
80
+ <FieldList>
81
+ <Field Name="First">Eric</Field>
82
+ <Field Name="Last">Idle</Field>
83
+ </FieldList>
84
+ </BusinessObject>
85
+ }
86
+ obj = MySubclass.new(xml)
87
+ first_name = obj.dom.css("BusinessObject[@Name=MySubclass] Field[@Name=First]").first
88
+ last_name = obj.dom.css("BusinessObject[@Name=MySubclass] Field[@Name=Last]").first
89
+ first_name.content.should == "Eric"
90
+ last_name.content.should == "Idle"
91
+ end
92
+
93
+ end #initialize
94
+
95
+ describe "#[]" do
96
+ it "returns the value in the named field" do
97
+ obj = MySubclass.create({:first_name => 'Eric', :last_name => 'Idle'})
98
+ obj['First'].should == 'Eric'
99
+ obj['Last'].should == 'Idle'
100
+ end
101
+ end #[]
102
+
103
+ describe "#[]=" do
104
+ it "puts a value in the named field" do
105
+ obj = MySubclass.create({:first_name => 'Eric', :last_name => 'Idle'})
106
+ obj['First'] = 'Terry'
107
+ obj['Last'] = 'Jones'
108
+ obj['First'].should == 'Terry'
109
+ obj['Last'].should == 'Jones'
110
+ end
111
+ end #[]=
112
+
113
+ describe "#modified" do
114
+ it "BusinessObject with a valid LastModDateTime value" do
115
+ # Parse the string version of now in order to truncate extra precision
116
+ # (otherwise the date won't compare equal later)
117
+ now = DateTime.parse(DateTime.now.to_s)
118
+
119
+ obj = MySubclass.create({:last_mod_date_time => now})
120
+ obj.modified.should == now
121
+ end
122
+
123
+ it "BusinessObject with an invalid LastModDateTime value" do
124
+ obj = MySubclass.create({:last_mod_date_time => 'bogus'})
125
+ lambda do
126
+ obj.modified
127
+ end.should raise_error(RuntimeError, /Cannot parse LastModDateTime: 'bogus'/)
128
+ end
129
+
130
+ it "BusinessObject without a LastModDateTime field" do
131
+ xml = %Q{
132
+ <BusinessObject Name="MySubclass">
133
+ <FieldList>
134
+ </FieldList>
135
+ </BusinessObject>
136
+ }
137
+ obj = MySubclass.new(xml)
138
+ lambda do
139
+ obj.modified
140
+ end.should raise_error(RuntimeError, /missing LastModDateTime/)
141
+ end
142
+ end #modified
143
+
144
+ describe "#mod_s" do
145
+ it "TODO"
146
+ end #mod_s
147
+
148
+ describe "#newer_than?" do
149
+ before(:each) do
150
+ @now = DateTime.now
151
+ @older = MySubclass.create({:last_mod_date_time => (@now - 1)})
152
+ @newer = MySubclass.create({:last_mod_date_time => @now})
153
+ end
154
+
155
+ it "true when this one was modified more recently than another" do
156
+ @newer.newer_than?(@older).should be_true
157
+ end
158
+
159
+ it "false when this one was modified less recently than another" do
160
+ @older.newer_than?(@newer).should be_false
161
+ end
162
+ end #newer_than?
163
+
164
+ describe "#to_xml" do
165
+ it "TODO"
166
+ end #to_xml
167
+
168
+ describe "#get_field_node" do
169
+ before(:each) do
170
+ xml = %Q{
171
+ <BusinessObject Name="MySubclass">
172
+ <FieldList>
173
+ <Field Name="First">Eric</Field>
174
+ <Field Name="Last">Idle</Field>
175
+ </FieldList>
176
+ </BusinessObject>
177
+ }
178
+ @obj = MySubclass.new(xml)
179
+ end
180
+
181
+ it "returns the Field having the given Name" do
182
+ first_node = @obj.get_field_node('First')
183
+ first_node.should be_a(Nokogiri::XML::Node)
184
+ first_node.attr('Name').should == 'First'
185
+ first_node.inner_html.should == 'Eric'
186
+ end
187
+
188
+ it "returns nil when a Field with the given Name is not found" do
189
+ @obj.get_field_node('Bogus').should be_nil
190
+ end
191
+ end #get_field_node
192
+
193
+ describe "#field_values" do
194
+ before(:each) do
195
+ xml = %Q{
196
+ <BusinessObject Name="MySubclass">
197
+ <FieldList>
198
+ <Field Name="First">Eric</Field>
199
+ <Field Name="Last">Pierce</Field>
200
+ </FieldList>
201
+ <Relationship Name="Other fields">
202
+ <FieldList>
203
+ <Field Name="Middle">Matthew</Field>
204
+ </FieldList>
205
+ </Relationship>
206
+ </BusinessObject>
207
+ }
208
+ @obj = MySubclass.new(xml)
209
+ end
210
+
211
+ it "includes fields inside the main FieldList element only" do
212
+ @obj.field_values.should include('First')
213
+ @obj.field_values.should include('Last')
214
+ @obj.field_values.should_not include('Middle')
215
+ end
216
+
217
+ it "hashes field names to their values" do
218
+ @obj.field_values['First'].should == 'Eric'
219
+ @obj.field_values['Last'].should == 'Pierce'
220
+ end
221
+ end
222
+
223
+ describe "#copy_fields_from" do
224
+ before(:each) do
225
+ xml = %Q{
226
+ <BusinessObject Name="MySubclass">
227
+ <FieldList>
228
+ <Field Name="Status">Original Status</Field>
229
+ <Field Name="Description">Original Description</Field>
230
+ <Field Name="Comment">Original Comment</Field>
231
+ </FieldList>
232
+ </BusinessObject>
233
+ }
234
+ @obj1 = MySubclass.new(xml)
235
+ @obj2 = MySubclass.new(xml)
236
+ end
237
+
238
+ it "copies fields from another BusinessObject" do
239
+ @obj2['Status'] = 'Modified Status'
240
+ @obj2['Description'] = 'Modified Description'
241
+
242
+ @obj1.copy_fields_from(@obj2, 'Status', 'Description')
243
+ @obj1['Status'].should == 'Modified Status'
244
+ @obj1['Description'].should == 'Modified Description'
245
+ @obj1['Comment'].should == 'Original Comment'
246
+ end
247
+ end
248
+ end # Instance methods
249
+ end # Cherby::BusinessObject
250
+
@@ -0,0 +1,300 @@
1
+ require_relative 'spec_helper'
2
+ require 'cherby/cherwell'
3
+ require 'cherby/exceptions'
4
+ require 'savon/mock/spec_helper'
5
+
6
+ describe Cherby::Cherwell do
7
+ include Savon::SpecHelper
8
+
9
+ before(:all) do
10
+ savon.mock!
11
+ end
12
+
13
+ after(:all) do
14
+ savon.unmock!
15
+ end
16
+
17
+ before(:each) do
18
+ # TODO: Mock this!
19
+ @config = {
20
+ 'url' => CHERWELL_WSDL,
21
+ 'username' => 'somebody',
22
+ 'password' => 'somepass',
23
+ }
24
+ @cherwell = Cherby::Cherwell.new(CHERWELL_WSDL)
25
+ end
26
+
27
+ describe "#initialize" do
28
+ it "sets configuration from a hash"
29
+ it "creates a new Cherby::Client instance" do
30
+ @cherwell.client.should be_a(Cherby::Client)
31
+ end
32
+ end #initialize
33
+
34
+ describe "#login" do
35
+ it "success when Cherwell returns a true status" do
36
+ login_response = savon_response('Login', 'true')
37
+ savon.expects(:login).with(:message => :any).
38
+ returns(login_response)
39
+ @cherwell.login.should be_true
40
+ end
41
+
42
+ it "raises Cherby::LoginFailed when client.login raises any exception" do
43
+ error = "Arbitrary exception message"
44
+ @cherwell.client.stub(:call).with(:login, :message => anything).
45
+ and_raise(RuntimeError.new(error))
46
+ lambda do
47
+ @cherwell.login
48
+ end.should raise_error(Cherby::LoginFailed, error)
49
+ end
50
+
51
+ it "raises Cherby::LoginFailed when Cherwell returns a false status" do
52
+ savon.expects(:login).with(:message => :any).
53
+ returns(savon_response('Login', 'false'))
54
+ lambda do
55
+ @cherwell.login
56
+ end.should raise_error(
57
+ Cherby::LoginFailed,
58
+ /Cherwell returned false status/)
59
+ end
60
+ end #login
61
+
62
+ describe "#logout" do
63
+ it "returns true when Cherwell returns a true status" do
64
+ savon.expects(:logout).with(:message => :any).
65
+ returns(savon_response('Logout', 'true'))
66
+ @cherwell.logout.should be_true
67
+ end
68
+
69
+ it "returns false when Cherwell returns a false status" do
70
+ savon.expects(:logout).with(:message => :any).
71
+ returns(savon_response('Logout', 'false'))
72
+ @cherwell.logout.should be_false
73
+ end
74
+ end #logout
75
+
76
+ describe "#incident" do
77
+ it "returns a Cherby::Incident instance" do
78
+ incident_id = '51949'
79
+ incident_xml = File.read(File.join(DATA_DIR, 'incident.xml'))
80
+ @cherwell.stub(:get_object_xml).
81
+ with('Incident', incident_id).
82
+ and_return(incident_xml)
83
+ @cherwell.incident(incident_id).should be_a(Cherby::Incident)
84
+ end
85
+ end #incident
86
+
87
+ describe "#task" do
88
+ it "returns a Cherby::Task instance" do
89
+ task_id = '12345'
90
+ task_xml = File.read(File.join(DATA_DIR, 'task.xml'))
91
+ @cherwell.stub(:get_object_xml).
92
+ with('Task', task_id).
93
+ and_return(task_xml)
94
+ @cherwell.task(task_id).should be_a(Cherby::Task)
95
+ end
96
+ end #task
97
+
98
+ describe "#get_object_xml" do
99
+ before(:each) do
100
+ @name = 'Thing'
101
+ @rec_id = '12345678901234567890123456789012'
102
+ @public_id = '12345'
103
+ @thing_xml = %Q{
104
+ <FieldList>
105
+ <Field Name="Name">#{@name}</Field>
106
+ <Field Name="RecID">#{@rec_id}</Field>
107
+ </FieldList>
108
+ }
109
+ end
110
+
111
+ it "invokes GetBusinessObject for 32-character RecID" do
112
+ savon.expects(:get_business_object).with(
113
+ :message => {
114
+ :busObNameOrId => @name,
115
+ :busObRecId => @rec_id,
116
+ }
117
+ ).returns(
118
+ savon_response('GetBusinessObject', @thing_xml)
119
+ )
120
+ @cherwell.get_object_xml(@name, @rec_id)
121
+ end
122
+
123
+ it "invokes GetBusinessObjectByPublicId for < 32-character IDs" do
124
+ savon.expects(:get_business_object_by_public_id).with(
125
+ :message => {
126
+ :busObNameOrId => @name,
127
+ :busObPublicId => @public_id,
128
+ }
129
+ ).returns(
130
+ savon_response('GetBusinessObjectByPublicId', @thing_xml)
131
+ )
132
+ @cherwell.get_object_xml(@name, @public_id)
133
+ end
134
+
135
+ it "returns a raw XML response string" do
136
+ xml = "<Foo>Bar</Foo>"
137
+ savon.expects(:get_business_object_by_public_id).with(
138
+ :message => :any
139
+ ).returns(
140
+ savon_response('GetBusinessObjectByPublicId', xml)
141
+ )
142
+ result = @cherwell.get_object_xml(@name, @public_id)
143
+ result.should == xml
144
+ end
145
+
146
+ it "raises a Cherby::SoapError if a Savon::Error occurs" do
147
+ soap_fault = Savon::Error.new("Kaboom")
148
+ @cherwell.client.stub(:call).and_raise(soap_fault)
149
+ lambda do
150
+ @cherwell.get_object_xml(@name, @public_id)
151
+ end.should raise_error(
152
+ Cherby::SoapError, /Kaboom/)
153
+ end
154
+ end #get_object_xml
155
+
156
+ describe "#update_object_xml" do
157
+ before(:each) do
158
+ @public_id = '80909'
159
+ @xml = %Q{
160
+ <Foo>Bar</Foo>
161
+ }
162
+ end
163
+
164
+ it "invokes UpdateBusinessObjectByPublicId with the given XML" do
165
+ savon.expects(:update_business_object_by_public_id).with(
166
+ :message => {
167
+ :busObNameOrId => 'Incident',
168
+ :busObPublicId => @public_id,
169
+ :updateXml => @xml
170
+ }
171
+ ).returns(
172
+ savon_response('UpdateBusinessObjectByPublicId', 'true')
173
+ )
174
+ @cherwell.stub(:last_error => nil)
175
+ @cherwell.update_object_xml('Incident', @public_id, @xml)
176
+ end
177
+
178
+ it "returns the #last_error string" do
179
+ savon.expects(:update_business_object_by_public_id).
180
+ with(:message => :any).
181
+ returns(savon_response('UpdateBusinessObjectByPublicId', 'false'))
182
+
183
+ error_message = "Failed to update object"
184
+ @cherwell.stub(:last_error => error_message)
185
+ result = @cherwell.update_object_xml('Incident', @public_id, @xml)
186
+ result.should == error_message
187
+ end
188
+ end #update_object_xml
189
+
190
+ describe "#save_incident" do
191
+ before(:each) do
192
+ @public_id = '62521'
193
+ @incident_data = {
194
+ :incident_id => @public_id,
195
+ :service => 'Consulting Services',
196
+ :sub_category => 'New/Modified Functionality',
197
+ :priority => '4',
198
+ }
199
+ @incident = Cherby::Incident.create(@incident_data)
200
+ @cherwell.stub(:last_error => nil)
201
+ end
202
+
203
+ it "invokes UpdateBusinessObjectByPublicId with the Incident XML" do
204
+ savon.expects(:update_business_object_by_public_id).with(
205
+ :message => {
206
+ :busObNameOrId => 'Incident',
207
+ :busObPublicId => @public_id,
208
+ :updateXml => @incident.to_xml
209
+ }
210
+ ).returns(
211
+ savon_response('UpdateBusinessObjectByPublicId', 'true')
212
+ )
213
+ @cherwell.save_incident(@incident)
214
+ end
215
+ end #save_incident
216
+
217
+ describe "#save_task" do
218
+ before(:each) do
219
+ @public_id = '90210'
220
+ @task_data = {
221
+ :task_id => @public_id,
222
+ :parent_id => '90000'
223
+ }
224
+ @task = Cherby::Task.create(@task_data)
225
+ @cherwell.stub(:last_error => nil)
226
+ end
227
+
228
+ it "invokes UpdateBusinessObjectByPublicId with the Task XML" do
229
+ savon.expects(:update_business_object_by_public_id).with(
230
+ :message => {
231
+ :busObNameOrId => 'Task',
232
+ :busObPublicId => @public_id,
233
+ :updateXml => @task.to_xml
234
+ }
235
+ ).returns(
236
+ savon_response('UpdateBusinessObjectByPublicId', 'true')
237
+ )
238
+ @cherwell.save_task(@task)
239
+ end
240
+ end #save_task
241
+
242
+ describe "#create_incident" do
243
+ before(:each) do
244
+ @incident_data = {
245
+ :service => 'Consulting Services',
246
+ :sub_category => 'New/Modified Functionality',
247
+ :priority => '4',
248
+ }
249
+ @public_id = '54321'
250
+ end
251
+
252
+ it "invokes CreateBusinessObject with incident XML" do
253
+ savon.expects(:create_business_object).with(
254
+ :message => {
255
+ :busObNameOrId => 'Incident',
256
+ :creationXml => Cherby::Incident.create(@incident_data).to_xml
257
+ }
258
+ ).returns(
259
+ savon_response('CreateBusinessObject', @public_id)
260
+ )
261
+ @cherwell.create_incident(@incident_data)
262
+ end
263
+
264
+ it "returns a Cherby::Incident instance with IncidentID set" do
265
+ savon.expects(:create_business_object).with(:message => :any).returns(
266
+ savon_response('CreateBusinessObject', @public_id)
267
+ )
268
+ result = @cherwell.create_incident(@incident_data)
269
+ result.should be_a(Cherby::Incident)
270
+ result['IncidentID'].should == @public_id
271
+ end
272
+
273
+ it "returns nil if incident creation failed (Cherwell returned nil)" do
274
+ savon.expects(:create_business_object).with(:message => :any).returns(
275
+ savon_response('CreateBusinessObject', nil)
276
+ )
277
+ result = @cherwell.create_incident(@incident_data)
278
+ result.should be_nil
279
+ end
280
+ end #create_incident
281
+
282
+ describe "#last_error" do
283
+ it "returns the GetLastError response text" do
284
+ error_message = "Object reference not set to an instance of an object"
285
+ savon.expects(:get_last_error).with(:message => {}).returns(
286
+ savon_response('GetLastError', error_message)
287
+ )
288
+ @cherwell.last_error.should == error_message
289
+ end
290
+
291
+ it "returns nil if GetLastError returns nil" do
292
+ savon.expects(:get_last_error).with(:message => {}).returns(
293
+ savon_response('GetLastError', nil)
294
+ )
295
+ @cherwell.last_error.should be_nil
296
+ end
297
+ end #last_error
298
+
299
+ end # describe Cherby::Cherwell
300
+