eloqua 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/.gitignore +11 -0
  2. data/.yardopts +2 -0
  3. data/CHANGELOG.md +23 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +81 -0
  6. data/LICENSE +21 -0
  7. data/README.md +245 -0
  8. data/Rakefile +13 -0
  9. data/TODO.md +8 -0
  10. data/eloqua.gemspec +32 -0
  11. data/eloqua_initializer.tpl.rb +3 -0
  12. data/lib/eloqua.rb +51 -0
  13. data/lib/eloqua/api.rb +119 -0
  14. data/lib/eloqua/api/action.rb +41 -0
  15. data/lib/eloqua/api/service.rb +240 -0
  16. data/lib/eloqua/asset.rb +31 -0
  17. data/lib/eloqua/builder/templates.rb +31 -0
  18. data/lib/eloqua/builder/xml.rb +129 -0
  19. data/lib/eloqua/entity.rb +72 -0
  20. data/lib/eloqua/exceptions.rb +5 -0
  21. data/lib/eloqua/helper/attribute_map.rb +78 -0
  22. data/lib/eloqua/query.rb +291 -0
  23. data/lib/eloqua/remote_object.rb +274 -0
  24. data/lib/eloqua/version.rb +3 -0
  25. data/lib/eloqua/wsdl/action.wsdl +1 -0
  26. data/lib/eloqua/wsdl/data.wsdl +1 -0
  27. data/lib/eloqua/wsdl/email.wsdl +1 -0
  28. data/lib/eloqua/wsdl/service.wsdl +1 -0
  29. data/lib/tasks/test.rake +24 -0
  30. data/rspec.watchr +74 -0
  31. data/spec/fixtures/add_group_member/success.xml +18 -0
  32. data/spec/fixtures/create/contact_duplicate.xml +30 -0
  33. data/spec/fixtures/create/contact_success.xml +25 -0
  34. data/spec/fixtures/create_asset/failure.xml +30 -0
  35. data/spec/fixtures/create_asset/group_success.xml +25 -0
  36. data/spec/fixtures/delete_asset/access_deny.xml +31 -0
  37. data/spec/fixtures/describe_asset/success.xml +72 -0
  38. data/spec/fixtures/describe_asset_type/success.xml +23 -0
  39. data/spec/fixtures/describe_entity/success.xml +54 -0
  40. data/spec/fixtures/describe_entity_type/success.xml +45 -0
  41. data/spec/fixtures/get_member_count_in_step_by_status/success.xml +15 -0
  42. data/spec/fixtures/list_asset_types/success.xml +28 -0
  43. data/spec/fixtures/list_entity_types/success.xml +21 -0
  44. data/spec/fixtures/list_group_membership/success.xml +25 -0
  45. data/spec/fixtures/list_members_in_step_by_status/success.xml +15 -0
  46. data/spec/fixtures/query/contact_email_one.xml +38 -0
  47. data/spec/fixtures/query/contact_email_two.xml +56 -0
  48. data/spec/fixtures/query/contact_missing.xml +19 -0
  49. data/spec/fixtures/query/fault.xml +43 -0
  50. data/spec/fixtures/remove_group_member/success.xml +18 -0
  51. data/spec/fixtures/retrieve/contact_missing.xml +17 -0
  52. data/spec/fixtures/retrieve/contact_multiple.xml +3460 -0
  53. data/spec/fixtures/retrieve/contact_single.xml +38 -0
  54. data/spec/fixtures/retrieve_asset/failure.xml +17 -0
  55. data/spec/fixtures/retrieve_asset/success.xml +50 -0
  56. data/spec/fixtures/update/contact_success.xml +26 -0
  57. data/spec/lib/eloqua/api/action_spec.rb +36 -0
  58. data/spec/lib/eloqua/api/service_spec.rb +498 -0
  59. data/spec/lib/eloqua/api_spec.rb +133 -0
  60. data/spec/lib/eloqua/asset_spec.rb +63 -0
  61. data/spec/lib/eloqua/builder/templates_spec.rb +68 -0
  62. data/spec/lib/eloqua/builder/xml_spec.rb +254 -0
  63. data/spec/lib/eloqua/entity_spec.rb +224 -0
  64. data/spec/lib/eloqua/helper/attribute_map_spec.rb +14 -0
  65. data/spec/lib/eloqua/query_spec.rb +596 -0
  66. data/spec/lib/eloqua/remote_object_spec.rb +742 -0
  67. data/spec/lib/eloqua_spec.rb +171 -0
  68. data/spec/shared/attribute_map.rb +173 -0
  69. data/spec/shared/class_to_api_delegation.rb +50 -0
  70. data/spec/spec_helper.rb +48 -0
  71. data/spec/support/helper.rb +73 -0
  72. metadata +366 -0
@@ -0,0 +1,742 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for 'remote operation that converts attribute values' do |operation|
4
+
5
+ let(:method) { "#{operation}_object".to_sym }
6
+
7
+ let(:klass) do
8
+ Class.new(subject) do
9
+ map :C_California1 => :california
10
+ attr_checkbox(:california)
11
+ end
12
+ end
13
+
14
+ context "when #{operation.to_s.pluralize} object" do
15
+ it 'should convert value before saving' do
16
+ if(operation == :update)
17
+ object = klass.new(:id => 1)
18
+ flexmock(object.class).should_receive(method).\
19
+ with(1, {'C_California1' => 'Yes'}).once
20
+ else
21
+ object = klass.new
22
+ flexmock(object.class).should_receive(method).\
23
+ with({'C_California1' => 'Yes'}).once
24
+ end
25
+
26
+
27
+ object.california = true
28
+ object.save
29
+ end
30
+
31
+ end
32
+ end
33
+
34
+ shared_examples_for "class method delegates to set_callback" do |method, callback, state|
35
+
36
+ context "#self.#{method}" do
37
+
38
+ it "should delegate to set_callback #{callback}, #{state}, &block" do
39
+ block = Proc.new {}
40
+ klass = flexmock(subject)
41
+ klass.should_receive(:set_callback).with(callback, state, block).once
42
+ klass.send(method, &block)
43
+ end
44
+
45
+
46
+ it "should be able to set a symbol as the final argument for a method" do
47
+ callback_method = :object_id
48
+
49
+ klass = flexmock(subject)
50
+ klass.should_receive(:set_callback).with(callback, state, callback_method).once
51
+ klass.send(method, callback_method)
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+
58
+ describe Eloqua::RemoteObject do
59
+
60
+ subject do
61
+ Class.new(Eloqua::RemoteObject) do
62
+ self.remote_type = Eloqua::Api.remote_type('Contact')
63
+ self.remote_group = :entity
64
+
65
+ attr_accessor :callbacks_called
66
+ attr_accessor :test_callbacks
67
+
68
+ def test_callback(type, state, &block)
69
+ class_eval do
70
+ set_callback(type, state, &block)
71
+ end
72
+ end
73
+
74
+ [:save, :update, :create].each do |callback_type|
75
+ [:before, :after].each do |callback_state|
76
+ set_callback(callback_type, callback_state) do
77
+ self.callbacks_called ||= {}
78
+ self.callbacks_called[callback_type] ||= []
79
+ self.callbacks_called[callback_type] << callback_state
80
+ end
81
+ end
82
+ end
83
+
84
+ def self.name
85
+ 'ContactEntity'
86
+ end
87
+
88
+ end
89
+ end
90
+
91
+ let(:remote_type) do
92
+ subject.api.remote_type('Contact')
93
+ end
94
+
95
+ it_behaves_like 'uses attribute map'
96
+ it_behaves_like 'class level delegation of remote operations for', :entity
97
+
98
+ [:save, :update, :create].each do |callback_type|
99
+ [:before, :after].each do |callback_state|
100
+ it_behaves_like "class method delegates to set_callback",
101
+ "#{callback_state}_#{callback_type}".to_sym, callback_type, callback_state
102
+ end
103
+ end
104
+
105
+ context "#self.remote_group" do
106
+ specify { subject.remote_group.should == :entity }
107
+ end
108
+
109
+
110
+ context "#initialize" do
111
+
112
+ context "when :remote" do
113
+ before do
114
+ @class = Class.new(subject) do
115
+ map :ContactID => :id
116
+ map :C_EmailAddress => :email
117
+ attr_checkbox :california, :arizona
118
+ end
119
+ end
120
+
121
+ let(:input) do
122
+ {
123
+ :C_EmailAddress => 'email@address.com',
124
+ :ContactID => '1',
125
+ :normal_id => 'wow',
126
+ :C_California => 'Yes',
127
+ :C_Arizona => 'No'
128
+ }
129
+ end
130
+
131
+ let(:expected) do
132
+ {
133
+ :email => 'email@address.com',
134
+ :id => '1',
135
+ :normal_id => 'wow',
136
+ :california => true,
137
+ :arizona => false
138
+ }.with_indifferent_access
139
+ end
140
+
141
+ it 'should map objects for adding them to #attributes' do
142
+ object = @class.new(input, :remote) # true is remote == true
143
+ object.attributes.should == expected
144
+ end
145
+
146
+
147
+
148
+ end
149
+
150
+
151
+ end
152
+
153
+ context "#reload" do
154
+
155
+ let(:new_attr) { {:C_EmailAddress => 'new'} }
156
+
157
+ before do
158
+ flexmock(subject).should_receive(:find_object, 1).\
159
+ and_return(new_attr).\
160
+ once
161
+
162
+ @object = subject.new({:id => 1, :C_EmailAddress => 'old'}, :remote)
163
+ @object.reload
164
+ end
165
+
166
+ it 'should have updated email to new' do
167
+ @object.email_address.should == 'new'
168
+ end
169
+
170
+ it 'should not be dirty' do
171
+ @object.attribute_changed?(:email_address).should be_false
172
+ end
173
+
174
+ end
175
+
176
+ context '#persisted?' do
177
+
178
+ it 'should be false when created with new' do
179
+ subject.new.should_not be_persisted
180
+ end
181
+
182
+ it 'should be true when initializing with id' do
183
+ subject.new(:id => '1').should be_persisted
184
+ end
185
+
186
+ context 'when initialized with :remote' do
187
+ it 'should be considered persisted' do
188
+ subject.new({:C_EmailAddress => 'email'}, :remote).should be_persisted
189
+ end
190
+ end
191
+ end
192
+
193
+ context "#valid?" do
194
+ let(:klass) do
195
+ Class.new(subject) do
196
+ map :C_EmailAddress => :email
197
+ validates_presence_of :email
198
+
199
+ def self.name
200
+ 'Contact'
201
+ end
202
+
203
+ end
204
+ end
205
+
206
+ context 'when valid' do
207
+
208
+ before do
209
+ @object = klass.new(:email => 'wow')
210
+ end
211
+
212
+ it 'should be valid?' do
213
+ @object.should be_valid
214
+ end
215
+
216
+ it 'should not have any errors' do
217
+ @object.valid?
218
+ @object.errors[:email].should be_empty
219
+ end
220
+
221
+ end
222
+
223
+ context 'when invalid' do
224
+
225
+ before do
226
+ @object = klass.new()
227
+ @results = @object.valid?
228
+ end
229
+
230
+ it 'should be invalid?' do
231
+ @object.should be_invalid
232
+ end
233
+
234
+ it 'should have errors on :email' do
235
+ @object.errors[:email].should_not be_empty
236
+ end
237
+
238
+ end
239
+
240
+ end
241
+
242
+ context "#read_attribute" do
243
+ let(:object) { subject.new(:email => 'address') }
244
+ specify { object.read_attribute(:email).should == 'address' }
245
+ end
246
+
247
+ context '#write_attribute' do
248
+ let(:object) { subject.new(:email => 'address') }
249
+
250
+ it 'should set attribute' do
251
+ object.write_attribute(:email, 'test')
252
+ object.attributes[:email].should == 'test'
253
+ end
254
+ end
255
+
256
+ context "#is_attribute_method?" do
257
+
258
+ let(:object) { subject.new(:email => 'address') }
259
+
260
+ it 'should return true for writers' do
261
+ object.is_attribute_method?(:email=).should == :write
262
+ end
263
+
264
+ it 'should return true for readers' do
265
+ object.is_attribute_method?(:email).should == :read
266
+ end
267
+
268
+ it 'should not return true for missing attrs' do
269
+ object.attributes.delete(:email)
270
+ object.is_attribute_method?(:email).should be_false
271
+ end
272
+
273
+ end
274
+
275
+ context "when calling attribute method without concrete definition" do
276
+
277
+ let(:klass) do
278
+ Class.new(subject) do
279
+ map :C_EmailAddress => 'email'
280
+ end
281
+ end
282
+
283
+
284
+ let(:object) do
285
+ klass.new({:C_EmailAddress => 'james@lightsofapollo.com'}, :remote)
286
+ end
287
+
288
+ specify { object.respond_to?(:email) }
289
+ specify { object.respond_to?(:email=) }
290
+
291
+ it 'should allow us to access attributes via accessors (email)' do
292
+ object.email.should == 'james@lightsofapollo.com'
293
+ end
294
+
295
+ it 'should allow us to alter email via email=' do
296
+ object.email = 'newemail'
297
+ object.email.should == 'newemail'
298
+ object.attributes[:email].should == 'newemail'
299
+ end
300
+
301
+ context 'when initalizing empty object' do
302
+ let(:object) { klass.new }
303
+
304
+ it 'should respond to mapped attribute email' do
305
+ object.respond_to?(:email).should be_true
306
+ end
307
+
308
+ it 'should allow us to set and read attribute' do
309
+ object.email = 'email'
310
+ object.email.should == 'email'
311
+ end
312
+
313
+ end
314
+
315
+ end
316
+
317
+ context 'dirty attributes' do
318
+
319
+ let(:klass) do
320
+ Class.new(subject) do
321
+ map :C_EmailAddress => :email
322
+ end
323
+ end
324
+
325
+ let(:object) do
326
+ klass.new
327
+ end
328
+
329
+ it 'should call attribute_will_change! when using attribute_write' do
330
+ flexmock(object).should_receive(:attribute_will_change!).with("email").once
331
+ object.email = 'email'
332
+ end
333
+
334
+ context 'when email has changed' do
335
+ before do
336
+ object.email = 'old'
337
+ object.email = 'new'
338
+ end
339
+
340
+ it 'should have old value available via attribute_was' do
341
+ object.attribute_was(:email).should == 'old'
342
+ end
343
+
344
+ it 'should have old and new value available via attribue_change' do
345
+ object.attribute_change(:email).should == ['old', 'new']
346
+ end
347
+
348
+ it 'should provide a list of all changed attributes via changed' do
349
+ object.changed.should == ['email']
350
+ end
351
+ end
352
+ end
353
+
354
+ context "when persisting object" do
355
+ let(:input) do
356
+ {:email => 'email', :name => 'first'}
357
+ end
358
+
359
+ let(:klass) do
360
+ Class.new(subject) do
361
+ map :C_EmailAddress => :email
362
+ map :C_FirstName => :name
363
+ map :ContactID => :id
364
+
365
+ validates_presence_of :email
366
+ end
367
+ end
368
+
369
+ let(:object) { klass.new(:id => 1) }
370
+
371
+ let(:expected) do
372
+ {
373
+ :C_EmailAddress => 'email',
374
+ :C_FirstName => 'first'
375
+ }.with_indifferent_access
376
+ end
377
+
378
+
379
+ it_behaves_like 'remote operation that converts attribute values', :update
380
+
381
+
382
+ context "#update" do
383
+
384
+ before do
385
+ flexmock(klass).should_receive(:update_object).\
386
+ with(1, expected).and_return(true)
387
+
388
+ object.email = 'email'
389
+ object.name = 'first'
390
+
391
+ @result = object.update
392
+ end
393
+
394
+ it "should have called before and after callbacks for update" do
395
+ object.callbacks_called[:update].should == [:before, :after]
396
+ end
397
+
398
+ it 'should call update entity to make the api call' do
399
+ @result.should be_true
400
+ end
401
+
402
+ specify { object.email.should == 'email' }
403
+ specify { object.name.should == 'first' }
404
+ end
405
+
406
+
407
+ it_behaves_like 'remote operation that converts attribute values', :create
408
+
409
+ context "#create" do
410
+ context "when successfully creating record" do
411
+ let(:object) { klass.new }
412
+
413
+ before do
414
+ flexmock(klass).should_receive(:create_object).\
415
+ with(expected).and_return({:id => 1})
416
+
417
+ object.email = 'email'
418
+ object.name = 'first'
419
+ @result = object.create
420
+ end
421
+
422
+ it "should call before and after callbacks" do
423
+ object.callbacks_called[:create].should == [:before, :after]
424
+ end
425
+
426
+ it 'should call update entity to make the api call' do
427
+ @result.should be_true
428
+ end
429
+
430
+ specify { object.id.should == 1 }
431
+ specify { object.email.should == 'email' }
432
+ specify { object.name.should == 'first' }
433
+ end
434
+ end
435
+
436
+ context "#save" do
437
+
438
+ context 'when save will create' do
439
+ let(:object) do
440
+ klass.new(:email => 'james@lightsofapollo.com')
441
+ end
442
+
443
+ before do
444
+ flexmock(klass).should_receive(:create_object).\
445
+ with({'C_EmailAddress' => 'james@lightsofapollo.com'}).\
446
+ and_return({:id => 1}).once
447
+ object.save
448
+ end
449
+
450
+ it 'should now be persisted?' do
451
+ object.should be_persisted
452
+ end
453
+
454
+ it 'should now have an id' do
455
+ object.id.should == 1
456
+ end
457
+
458
+ it "should call before and after callbacks" do
459
+ object.callbacks_called[:save].should == [:before, :after]
460
+ end
461
+
462
+ end
463
+
464
+ context 'when save will update' do
465
+
466
+ let(:object) do
467
+ klass.new(:id => 1, :email => 'james@lightsofapollo.com')
468
+ end
469
+
470
+ before do
471
+ flexmock(klass).should_receive(:update_object).\
472
+ with(1, {'C_EmailAddress' => 'new'}).\
473
+ and_return(true).once
474
+
475
+ object.email = 'new'
476
+ object.save
477
+ end
478
+
479
+ it 'should now be persisted?' do
480
+ object.should be_persisted
481
+ end
482
+
483
+ it 'should have updated email address to "new"' do
484
+ object.email.should == 'new'
485
+ end
486
+
487
+ end
488
+
489
+ context "when record is invalid" do
490
+
491
+ let(:object) do
492
+ klass.new(:id => 1)
493
+ end
494
+
495
+ it "should not have called any callbacks" do
496
+ object.callbacks_called.should be_nil
497
+ end
498
+
499
+ it 'should not be valid' do
500
+ object.should_not be_valid
501
+ end
502
+
503
+ it 'should return false when saving' do
504
+ object.save.should be_false
505
+ end
506
+
507
+ end
508
+
509
+ end
510
+
511
+ context "#update_attributes" do
512
+
513
+ context "when successfuly updating the record and ignoring sanitization" do
514
+ let(:klass) do
515
+ Class.new(subject) do
516
+ map :C_EmailAddress => :email
517
+ map :C_FirstName => :name
518
+ map :ContactID => :id
519
+
520
+ attr_accessible :email
521
+ end
522
+ end
523
+
524
+ let(:object) { klass.new(:id => 1, :name => 'james') }
525
+
526
+ before do
527
+ flexmock(klass).should_receive(:update_object).\
528
+ with(1, {'C_EmailAddress' => 'new', 'C_FirstName' => 'gomez'}).\
529
+ and_return(true)
530
+
531
+ @result = object.update_attributes({
532
+ :email => 'new',
533
+ :name => 'gomez'
534
+ }, true)
535
+ end
536
+
537
+ it 'should call update entity to make the api call' do
538
+ @result.should be_true
539
+ end
540
+
541
+ specify { object.email.should == 'new' }
542
+ specify { object.name.should == 'gomez' }
543
+
544
+ end
545
+
546
+ context "when successfuly updating record" do
547
+ let(:klass) do
548
+ Class.new(subject) do
549
+ map :C_EmailAddress => :email
550
+ map :C_FirstName => :name
551
+ map :ContactID => :id
552
+
553
+ attr_accessible :email
554
+ end
555
+ end
556
+
557
+ let(:object) { klass.new(:id => 1, :name => 'james') }
558
+
559
+ let(:expected) do
560
+ {
561
+ :email => 'email',
562
+ }.with_indifferent_access
563
+ end
564
+
565
+ before do
566
+ flexmock(klass).should_receive(:update_object).\
567
+ with(1, {'C_EmailAddress' => 'email'}).and_return(true)
568
+
569
+ @result = object.update_attributes(input)
570
+ end
571
+
572
+ it 'should call update entity to make the api call' do
573
+ @result.should be_true
574
+ end
575
+
576
+ specify { object.email.should == 'email' }
577
+ specify { object.name.should == 'james' }
578
+
579
+ end
580
+
581
+
582
+ context 'when updating attributes of invalid object' do
583
+
584
+ let(:input) do
585
+ {}
586
+ end
587
+
588
+ let(:object) { klass.new }
589
+
590
+ before do
591
+ flexmock(object).should_receive(:create).never
592
+ flexmock(object).should_receive(:update).never
593
+ end
594
+
595
+ it 'should be invalid' do
596
+ object.should_not be_valid
597
+ end
598
+
599
+ it 'should return false' do
600
+ object = klass.new
601
+ object.update_attributes(input).should be_false
602
+ end
603
+
604
+ end
605
+
606
+ end
607
+
608
+
609
+ end
610
+
611
+
612
+ context "#self.attr_type_hash" do
613
+
614
+ let(:expected) do
615
+ {
616
+ :type => :my_name,
617
+ :import => :import_my_name,
618
+ :export => :export_my_name
619
+ }
620
+ end
621
+
622
+ it 'should return a hash with the expected output' do
623
+ subject.attr_type_hash(:my_name).should == expected
624
+ end
625
+
626
+ end
627
+
628
+ context '#convert_attribute_values' do
629
+ let(:klass) do
630
+ Class.new(subject) do
631
+ map :C_California1 => :california
632
+ attr_checkbox(:california)
633
+ end
634
+ end
635
+
636
+ context 'when :import' do
637
+ it 'should call import_boolean_checkbox' do
638
+ object = klass.new(:california => 'Yes')
639
+ flexmock(object.class).should_receive(:import_boolean_checkbox).with(:california, 'Yes').and_return(true)
640
+ attrs = object.convert_attribute_values(object.attributes)
641
+ attrs[:california].should === true
642
+ end
643
+ end
644
+
645
+ context 'when :export' do
646
+
647
+ it 'should call export_boolean_checkbox' do
648
+ object = klass.new(:california => 'Yes')
649
+ flexmock(object.class).should_receive(:export_boolean_checkbox).with(:california, true).and_return('Yes')
650
+ attrs = object.convert_attribute_values(object.attributes, :export)
651
+ attrs[:california].should === 'Yes'
652
+ end
653
+
654
+ end
655
+
656
+ end
657
+
658
+ context '#export_boolean_checkbox' do
659
+ let(:object) { subject.new }
660
+
661
+ it 'should return Yes when given true' do
662
+ object.send(:export_boolean_checkbox, :mock, true).should == 'Yes'
663
+ end
664
+
665
+ it 'should return No when given false' do
666
+ object.send(:export_boolean_checkbox, :mock, false).should == 'No'
667
+ end
668
+
669
+ end
670
+
671
+ context "#self.attr_checkbox" do
672
+
673
+ let(:klass) do
674
+ Class.new(subject) do
675
+ map :C_California1 => :california
676
+ attr_checkbox :california
677
+ end
678
+ end
679
+
680
+ it 'should have registered "california" as :checkbox in attribute_types' do
681
+ klass.attribute_types[:california].should == {
682
+ :type => :boolean_checkbox,
683
+ :import => :import_boolean_checkbox,
684
+ :export => :export_boolean_checkbox
685
+ }.with_indifferent_access
686
+ end
687
+
688
+ context "when creating object with checkbox as Yes" do
689
+ let(:object) { klass.new(:california => 'Yes') }
690
+ specify { object.attributes[:california].should == true }
691
+ end
692
+
693
+ context 'when creating object with checkbox as No' do
694
+ let(:object) { klass.new(:california => 'No') }
695
+ specify { object.attributes[:california].should == false }
696
+ end
697
+
698
+ context 'when creating object with checkbox as true' do
699
+ let(:object) { klass.new(:california => true) }
700
+ specify { object.attributes[:california].should == true }
701
+ end
702
+
703
+ context 'when creating object with checkbox as false' do
704
+ let(:object) { klass.new(:california => false) }
705
+ specify { object.attributes[:california].should == false }
706
+ end
707
+
708
+ end
709
+
710
+ context '#self.primary_key' do
711
+ it 'is "id" by default' do
712
+ subject.primary_key.should == 'id'
713
+ end
714
+ end
715
+
716
+ context '#self.eloqua_attribute' do
717
+
718
+ before do
719
+ @class = Class.new(subject) do
720
+ map :C_EmailAddress => :email
721
+ end
722
+ end
723
+
724
+ it 'should return eloqua name "C_EmailAddress"' do
725
+ @class.eloqua_attribute(:email).should == 'C_EmailAddress'
726
+ end
727
+
728
+ end
729
+
730
+ context "#self.api" do
731
+ it 'should have api on the class level' do
732
+ subject.api.should == Eloqua::Api::Service
733
+ end
734
+ end
735
+
736
+ context "#api" do
737
+ it "should have api on the instance level" do
738
+ subject.new.api.should == Eloqua::Api::Service
739
+ end
740
+ end
741
+
742
+ end