cherby 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.
@@ -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
+