treequel 1.2.2 → 1.3.0pre384

Sign up to get free protection for your applications and to get access to all the features.
data/spec/lib/helpers.rb CHANGED
@@ -12,7 +12,6 @@ BEGIN {
12
12
 
13
13
  require 'rspec'
14
14
 
15
- require 'yaml'
16
15
  require 'treequel'
17
16
 
18
17
  require 'spec/lib/constants'
@@ -23,10 +22,6 @@ require 'spec/lib/matchers'
23
22
  module Treequel::SpecHelpers
24
23
  include Treequel::TestConstants
25
24
 
26
- SCHEMA_DUMPFILE = Pathname( __FILE__ ).dirname.parent + 'data' + 'schema.yml'
27
- SCHEMAHASH = LDAP::Schema.new( YAML.load_file(SCHEMA_DUMPFILE) )
28
- SCHEMA = Treequel::Schema.new( SCHEMAHASH )
29
-
30
25
  class ArrayLogger
31
26
  ### Create a new ArrayLogger that will append content to +array+.
32
27
  def initialize( array )
@@ -74,8 +69,8 @@ module Treequel::SpecHelpers
74
69
  def setup_logging( level=Logger::FATAL )
75
70
 
76
71
  # Turn symbol-style level config into Logger's expected Fixnum level
77
- if Treequel::Loggable::LEVEL.key?( level )
78
- level = Treequel::Loggable::LEVEL[ level ]
72
+ if Treequel::LOG_LEVELS.key?( level.to_s )
73
+ level = Treequel::LOG_LEVELS[ level.to_s ]
79
74
  end
80
75
 
81
76
  logger = Logger.new( $stderr )
@@ -98,14 +93,36 @@ module Treequel::SpecHelpers
98
93
  ### external data.
99
94
  def get_fixtured_directory( conn )
100
95
  LDAP::SSLConn.stub( :new ).and_return( @conn )
101
- conn.stub( :root_dse ).and_return( nil )
96
+ conn.stub( :search_ext2 ).
97
+ with( "", 0, "(objectClass=*)", ["+"], false, nil, nil, 0, 0, 0, "", nil ).
98
+ and_return( TEST_DSE )
102
99
  conn.stub( :set_option )
100
+
101
+ # Avoid parsing the whole schema with every example
103
102
  directory = Treequel.directory( TEST_LDAPURI )
104
103
  directory.stub( :schema ).and_return( SCHEMA )
105
104
 
106
105
  return directory
107
106
  end
108
107
 
108
+ ### Shorthand method for creating LDAP::Mod DELETE objects
109
+ def ldap_mod_delete( attribute, *values )
110
+ return LDAP::Mod.new( LDAP::LDAP_MOD_DELETE, attribute.to_s, values.flatten )
111
+ end
112
+
113
+
114
+ ### Shorthand method for creating LDAP::Mod REPLACE objects
115
+ def ldap_mod_replace( attribute, *values )
116
+ return LDAP::Mod.new( LDAP::LDAP_MOD_REPLACE, attribute.to_s, values.flatten )
117
+ end
118
+
119
+
120
+ ### Shorthand method for creating LDAP::Mod ADD objects
121
+ def ldap_mod_add( attribute, *values )
122
+ return LDAP::Mod.new( LDAP::LDAP_MOD_ADD, attribute.to_s, values.flatten )
123
+ end
124
+
125
+
109
126
  end
110
127
 
111
128
 
@@ -41,7 +41,7 @@ describe Treequel::Branch do
41
41
  end
42
42
 
43
43
  before( :each ) do
44
- @conn = mock( "ldap connection object" )
44
+ @conn = mock( "ldap connection object", :bound? => false )
45
45
  @directory = get_fixtured_directory( @conn )
46
46
  end
47
47
 
@@ -69,7 +69,8 @@ describe Treequel::Branch do
69
69
  branch = Treequel::Branch.new_from_entry( entry, @directory )
70
70
 
71
71
  branch.rdn_attributes.should == { TEST_PERSON_DN_ATTR => [TEST_PERSON_DN_VALUE] }
72
- branch.entry.should == entry
72
+ branch.entry.should == { TEST_PERSON_DN_ATTR => TEST_PERSON_DN_VALUE }
73
+ branch.dn.should == entry['dn'].first
73
74
  end
74
75
 
75
76
  it "can be constructed from an entry with Symbol keys" do
@@ -81,9 +82,9 @@ describe Treequel::Branch do
81
82
 
82
83
  branch.rdn_attributes.should == { TEST_PERSON_DN_ATTR => [TEST_PERSON_DN_VALUE] }
83
84
  branch.entry.should == {
84
- 'dn' => [TEST_PERSON_DN],
85
85
  TEST_PERSON_DN_ATTR => TEST_PERSON_DN_VALUE,
86
86
  }
87
+ branch.dn.should == entry[:dn].first
87
88
  end
88
89
 
89
90
  it "can be instantiated with a Hash with Symbol keys" do
@@ -232,7 +233,10 @@ describe Treequel::Branch do
232
233
  yielded_val = val
233
234
  end
234
235
  yielded_val.should be_a( Treequel::Branch )
235
- yielded_val.entry.should == subentry
236
+ yielded_val.entry.should == {
237
+ 'objectClass' => ['ipHost'],
238
+ TEST_HOST_DN_ATTR => [TEST_HOST_DN_VALUE],
239
+ }
236
240
  end
237
241
 
238
242
  it "clears any cached values if its include_operational_attrs attribute is changed" do
@@ -313,6 +317,11 @@ describe Treequel::Branch do
313
317
  end
314
318
 
315
319
 
320
+ it "returns nil if a Branch for the base DN is asked for its parent" do
321
+ @branch.parent.parent.should be_nil()
322
+ end
323
+
324
+
316
325
  it "can construct a Treequel::Branchset that uses it as its base" do
317
326
  @branch.branchset.should be_a( Treequel::Branchset )
318
327
  @branch.branchset.base_dn.should == @branch.dn
@@ -325,6 +334,14 @@ describe Treequel::Branch do
325
334
  branchset.filter_string.should =~ /\(cn=acme\)/
326
335
  end
327
336
 
337
+ it "can create a Treequel::Branchset from itself that returns instances of another class" do
338
+ otherclass = Class.new( Treequel::Branch )
339
+ branchset = @branch.as( otherclass )
340
+
341
+ branchset.should be_a( Treequel::Branchset )
342
+ branchset.branch.should be_a( otherclass )
343
+ end
344
+
328
345
  it "doesn't restrict the number of arguments passed to #filter (bugfix)" do
329
346
  branchset = @branch.filter( :uid => [:rev, :grumpy, :glee] )
330
347
 
@@ -399,7 +416,7 @@ describe Treequel::Branch do
399
416
  and_return([ {'objectClass' => %w[ipHost device ieee802device]} ])
400
417
 
401
418
  @branch.must_attributes_hash.
402
- should include({ :cn => [''], :ipHostNumber => [''], :objectClass => [:top] })
419
+ should include({ :cn => [''], :ipHostNumber => [''], :objectClass => ['top'] })
403
420
  end
404
421
 
405
422
 
@@ -457,7 +474,7 @@ describe Treequel::Branch do
457
474
  it "can return a Hash pre-populated with pairs that correspond to all of its valid " +
458
475
  "attributes" do
459
476
  @branch.valid_attributes_hash.should == {
460
- :objectClass => [:top],
477
+ :objectClass => ['top'],
461
478
  :ou => [''],
462
479
  :userPassword => [],
463
480
  :searchGuide => [],
@@ -535,8 +552,7 @@ describe Treequel::Branch do
535
552
  @conn.should_receive( :add ).
536
553
  with( "cn=chillyt,#{TEST_HOSTS_DN}",
537
554
  "ipHostNumber"=>["127.0.0.1"],
538
- "objectClass"=>["ipHost", "device"],
539
- "cn"=>["chillyt"] )
555
+ "objectClass"=>["ipHost", "device"] )
540
556
 
541
557
  res = @branch.cn( :chillyt ).create( newattrs )
542
558
  res.should be_a( Treequel::Branch )
@@ -596,6 +612,13 @@ describe Treequel::Branch do
596
612
  @branch.delete( :objectClass => 'apple-user' )
597
613
  end
598
614
 
615
+ it "can delete one particular non-String value of its entry's individual attributes" do
616
+ mod = LDAP::Mod.new( LDAP::LDAP_MOD_DELETE, 'pwdChangedTime', ['20000101201501Z'] )
617
+ @conn.should_receive( :modify ).with( TEST_HOSTS_DN, [mod] )
618
+
619
+ @branch.delete( :pwdChangedTime => Time.gm(2000,"jan",1,20,15,1) )
620
+ end
621
+
599
622
  it "can delete particular values of more than one of its entry's individual attributes" do
600
623
  mod1 = LDAP::Mod.new( LDAP::LDAP_MOD_DELETE, 'objectClass',
601
624
  ['apple-user', 'inetOrgPerson'] )
@@ -732,6 +755,17 @@ describe Treequel::Branch do
732
755
  @branch[ :l ].should include( 'Galapagos', 'Antartica' )
733
756
  end
734
757
 
758
+ it "fetches an empty Array if a record doesn't have an attribute set" do
759
+ @branch[ :cn ].should == []
760
+ end
761
+
762
+ it "fetches an empty Array for an attribute if the entry doesn't exist" do
763
+ @conn.stub( :search_ext2 ).
764
+ with( TEST_HOSTS_DN, LDAP::LDAP_SCOPE_BASE, "(objectClass=*)" ).
765
+ and_return( [] )
766
+ @branch[ :cn ].should == []
767
+ end
768
+
735
769
  it "fetches a single-value attribute as a scalar String" do
736
770
  test_dn = "cn=ssh,cn=www,#{TEST_HOSTS_DN}"
737
771
  entry = {
@@ -754,8 +788,8 @@ describe Treequel::Branch do
754
788
  @branch[ :rev ].should == [ '03eca02ba232' ]
755
789
  end
756
790
 
757
- it "returns nil if record doesn't have the attribute set" do
758
- @branch[ :cn ].should == nil
791
+ it "returns nil if a record doesn't have a SINGLE-type attribute set" do
792
+ @branch[ :displayName ].should == nil
759
793
  end
760
794
 
761
795
  it "caches the value fetched from its entry" do
@@ -767,6 +801,35 @@ describe Treequel::Branch do
767
801
  2.times { @branch[ :description ] }
768
802
  end
769
803
 
804
+ it "freezes the values fetched from its entry by default to prevent accidental " +
805
+ "in-place modification" do
806
+ @conn.should_receive( :search_ext2 ).
807
+ with( TEST_HOSTS_DN, LDAP::LDAP_SCOPE_BASE, "(objectClass=*)" ).
808
+ exactly( :once ).
809
+ and_return([ @entry ])
810
+
811
+ expect {
812
+ @branch[ :description ] << "Another description"
813
+ }.to raise_error( /can't modify frozen/i )
814
+ end
815
+
816
+ it "doesn't freeze the values fetched from its entry if it's told not to" do
817
+ @conn.should_receive( :search_ext2 ).
818
+ with( TEST_HOSTS_DN, LDAP::LDAP_SCOPE_BASE, "(objectClass=*)" ).
819
+ exactly( :once ).
820
+ and_return([ @entry ])
821
+
822
+ begin
823
+ Treequel::Branch.freeze_converted_values = false
824
+
825
+ expect {
826
+ @branch[ :description ] << "Another description"
827
+ }.to_not raise_error()
828
+ ensure
829
+ Treequel::Branch.freeze_converted_values = true
830
+ end
831
+ end
832
+
770
833
  it "converts objects via the conversions set in its directory" do
771
834
  test_dn = "cn=ssh,cn=www,#{TEST_HOSTS_DN}"
772
835
  entry = {
@@ -2,7 +2,7 @@
2
2
 
3
3
  BEGIN {
4
4
  require 'pathname'
5
- basedir = Pathname.new( __FILE__ ).dirname.parent.parent
5
+ basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
6
6
 
7
7
  libdir = basedir + "lib"
8
8
 
@@ -12,26 +12,17 @@ BEGIN {
12
12
 
13
13
  require 'rspec'
14
14
 
15
- require 'spec/lib/constants'
16
15
  require 'spec/lib/helpers'
17
- require 'spec/lib/control_behavior'
18
16
 
19
17
  require 'treequel'
18
+ require 'treequel/behavior/control'
20
19
  require 'treequel/controls/contentsync'
21
20
 
22
- include Treequel::TestConstants
23
- include Treequel::Constants
24
21
 
25
22
  #####################################################################
26
23
  ### C O N T E X T S
27
24
  #####################################################################
28
25
  describe Treequel::ContentSyncControl do
29
- include Treequel::SpecHelpers
30
-
31
- before( :each ) do
32
- # Used by the shared behavior
33
- @control = Treequel::ContentSyncControl
34
- end
35
26
 
36
27
  it_should_behave_like "A Treequel::Control"
37
28
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  BEGIN {
4
4
  require 'pathname'
5
- basedir = Pathname.new( __FILE__ ).dirname.parent.parent
5
+ basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
6
6
 
7
7
  libdir = basedir + "lib"
8
8
 
@@ -12,11 +12,10 @@ BEGIN {
12
12
 
13
13
  require 'rspec'
14
14
 
15
- require 'spec/lib/constants'
16
15
  require 'spec/lib/helpers'
17
- require 'spec/lib/control_behavior'
18
16
 
19
17
  require 'treequel'
18
+ require 'treequel/behavior/control'
20
19
  require 'treequel/controls/pagedresults'
21
20
 
22
21
 
@@ -24,19 +23,19 @@ require 'treequel/controls/pagedresults'
24
23
  ### C O N T E X T S
25
24
  #####################################################################
26
25
  describe Treequel::PagedResultsControl do
27
- include Treequel::SpecHelpers
28
26
 
29
27
  before( :all ) do
30
28
  setup_logging( :fatal )
31
29
  end
32
30
 
33
31
  before( :each ) do
34
- @branch = mock( "Branch", :dn => 'cn=example,dc=acme,dc=com' )
35
- @directory = mock( "Directory" )
32
+ @conn = mock( "ldap connection object" )
33
+ @conn.stub( :bound? ).and_return( false )
34
+ @directory = get_fixtured_directory( @conn )
35
+ @directory.register_controls( Treequel::PagedResultsControl )
36
36
 
37
- @branch.stub( :directory ).and_return( @directory )
38
- @directory.stub( :registered_controls ).and_return([ Treequel::PagedResultsControl ])
39
- @branchset = Treequel::Branchset.new( @branch )
37
+ @branch = Treequel::Branch.new( @directory, TEST_PEOPLE_DN )
38
+ @branchset = @branch.branchset
40
39
  end
41
40
 
42
41
  after( :all ) do
@@ -80,6 +79,23 @@ describe Treequel::PagedResultsControl do
80
79
  paged_branchset.paged_results_setsize.should == nil
81
80
  end
82
81
 
82
+ it "knows that there are (potentially) more paged results if the cookie isn't set" do
83
+ paged_branchset = @branchset.with_paged_results( 25 )
84
+ paged_branchset.should_not be_done_paging()
85
+ end
86
+
87
+ it "knows that there are more paged results if the cookie is set" do
88
+ paged_branchset = @branchset.with_paged_results( 25 )
89
+ paged_branchset.paged_results_cookie = "\230\t\000\000\000\000\000\000"
90
+ paged_branchset.should_not be_done_paging()
91
+ end
92
+
93
+ it "knows that there are no more paged results if the cookie is blank" do
94
+ paged_branchset = @branchset.with_paged_results( 25 )
95
+ paged_branchset.paged_results_cookie = ''
96
+ paged_branchset.should be_done_paging()
97
+ end
98
+
83
99
  it "injects the correct server-control structure into the search when iterating" do
84
100
  oid = Treequel::PagedResultsControl::OID
85
101
  expected_asn1_string = "0\005\002\001\031\004\000"
@@ -2,7 +2,7 @@
2
2
 
3
3
  BEGIN {
4
4
  require 'pathname'
5
- basedir = Pathname.new( __FILE__ ).dirname.parent.parent
5
+ basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
6
6
 
7
7
  libdir = basedir + "lib"
8
8
 
@@ -12,12 +12,11 @@ BEGIN {
12
12
 
13
13
  require 'rspec'
14
14
 
15
- require 'spec/lib/constants'
16
15
  require 'spec/lib/helpers'
17
- require 'spec/lib/control_behavior'
18
16
 
19
17
  require 'treequel'
20
18
  require 'treequel/branchset'
19
+ require 'treequel/behavior/control'
21
20
  require 'treequel/controls/sortedresults'
22
21
 
23
22
 
@@ -25,20 +24,19 @@ require 'treequel/controls/sortedresults'
25
24
  ### C O N T E X T S
26
25
  #####################################################################
27
26
  describe Treequel::SortedResultsControl do
28
- include Treequel::SpecHelpers
29
27
 
30
28
  before( :all ) do
31
29
  setup_logging( :fatal )
32
30
  end
33
31
 
34
32
  before( :each ) do
35
- @branch = mock( "Branch", :dn => 'cn=example,dc=acme,dc=com' )
36
- @directory = mock( "Directory" )
37
-
38
- @branch.stub( :directory ).and_return( @directory )
39
- @directory.stub( :registered_controls ).and_return([ Treequel::SortedResultsControl ])
40
- @branchset = Treequel::Branchset.new( @branch )
33
+ @conn = mock( "ldap connection object" )
34
+ @conn.stub( :bound? ).and_return( false )
35
+ @directory = get_fixtured_directory( @conn )
36
+ @directory.register_controls( Treequel::SortedResultsControl )
41
37
 
38
+ @branch = Treequel::Branch.new( @directory, TEST_PEOPLE_DN )
39
+ @branchset = @branch.branchset
42
40
  end
43
41
 
44
42
  after( :all ) do
@@ -46,17 +46,22 @@ describe Treequel::Directory do
46
46
  }
47
47
  @conn = mock( "LDAP connection", :set_option => true, :bound? => false )
48
48
  LDAP::SSLConn.stub( :new ).and_return( @conn )
49
- @conn.stub( :root_dse ).and_return( nil )
49
+
50
+ @conn.stub( :schema ).and_return( SCHEMAHASH )
50
51
  end
51
52
 
52
53
 
53
54
  it "is created with reasonable default options if none are specified" do
55
+ @conn.stub( :search_ext2 ).
56
+ with( "", 0, "(objectClass=*)", ["+"], false, nil, nil, 0, 0, 0, "", nil ).
57
+ and_return( TEST_DSE )
58
+
54
59
  dir = Treequel::Directory.new
55
60
 
56
61
  dir.host.should == 'localhost'
57
62
  dir.port.should == 389
58
63
  dir.connect_type.should == :tls
59
- dir.base_dn.should == ''
64
+ dir.base_dn.should == 'dc=acme,dc=com'
60
65
  end
61
66
 
62
67
  it "is created with the specified options if options are specified" do
@@ -80,36 +85,37 @@ describe Treequel::Directory do
80
85
  end
81
86
 
82
87
  it "uses the first namingContext from the Root DSE if no base is specified" do
83
- conn = mock( "LDAP connection", :set_option => true )
84
- LDAP::Conn.stub( :new ).and_return( conn )
85
- conn.should_receive( :root_dse ).and_return( TEST_DSE )
88
+ LDAP::Conn.stub( :new ).and_return( @conn )
89
+ @conn.stub( :search_ext2 ).
90
+ with( "", 0, "(objectClass=*)", ["+"], false, nil, nil, 0, 0, 0, "", nil ).
91
+ and_return( TEST_DSE )
86
92
 
87
- @dir = Treequel::Directory.new( @options.merge(:base_dn => nil) )
88
- @dir.base_dn.should == TEST_BASE_DN
93
+ dir = Treequel::Directory.new( @options.merge(:base_dn => nil) )
94
+ dir.base_dn.should == TEST_BASE_DN
89
95
  end
90
96
 
91
97
  it "can return its root element as a Branch instance" do
92
- @dir = Treequel::Directory.new( @options )
93
- @dir.base.should be_a( Treequel::Branch )
94
- @dir.base.dn.should == TEST_BASE_DN
98
+ dir = Treequel::Directory.new( @options )
99
+ dir.base.should be_a( Treequel::Branch )
100
+ dir.base.dn.should == TEST_BASE_DN
95
101
  end
96
102
 
97
103
  it "can return its root element as an instance of its results class if it's been set" do
98
104
  subtype = Class.new( Treequel::Branch )
99
- @dir = Treequel::Directory.new( @options )
105
+ dir = Treequel::Directory.new( @options )
100
106
 
101
- @dir.results_class = subtype
107
+ dir.results_class = subtype
102
108
 
103
- @dir.base.should be_a( subtype )
104
- @dir.base.dn.should == TEST_BASE_DN
109
+ dir.base.should be_a( subtype )
110
+ dir.base.dn.should == TEST_BASE_DN
105
111
  end
106
112
 
107
113
 
108
114
  describe "instances without existing connections" do
109
115
 
110
116
  before( :each ) do
117
+ @conn = mock( "ldap connection", :bound? => false, :set_option => true )
111
118
  @dir = Treequel::Directory.new( @options )
112
- @conn = mock( "ldap connection", :set_option => true )
113
119
  end
114
120
 
115
121
 
@@ -344,6 +350,35 @@ describe Treequel::Directory do
344
350
  }.to raise_error( LDAP::ResultError, /can't contact/i )
345
351
  end
346
352
 
353
+
354
+ it "can reconnect if its underlying connection goes away" do
355
+ @conn.stub( :search_ext2 ).and_raise( LDAP::ResultError.new("Can't contact LDAP server") )
356
+
357
+ second_conn = mock( "LDAP connection", :set_option => true, :bound? => false )
358
+ LDAP::Conn.should_receive( :new ).and_return( second_conn )
359
+ second_conn.should_receive( :search_ext2 ).and_return([])
360
+
361
+ already_tried_reconnect = false
362
+ begin
363
+ @dir.search( TEST_PEOPLE_DN, :base, '(objectClass=*)' )
364
+ rescue
365
+ unless already_tried_reconnect
366
+ already_tried_reconnect = true
367
+ @dir.reconnect and retry
368
+ end
369
+ end
370
+ end
371
+
372
+ it "re-raises an exception rescued during a reconnect as a RuntimeError" do
373
+ LDAP::Conn.should_receive( :new ).
374
+ and_raise( LDAP::ResultError.new("Can't contact LDAP server") )
375
+
376
+ expect {
377
+ @dir.reconnect
378
+ }.to raise_exception( RuntimeError, /couldn't reconnect/i )
379
+ end
380
+
381
+
347
382
  describe "and a custom search results class" do
348
383
 
349
384
  before( :each ) do
@@ -482,63 +517,31 @@ describe Treequel::Directory do
482
517
  :desc => 'Audi like Jetta',
483
518
  :objectClass => :room,
484
519
  }
485
- rdn_attrs = {
486
- TEST_PERSON_DN_ATTR => [TEST_PERSON_DN_VALUE]
487
- }
488
- addattrs = {
520
+
521
+ branch = Treequel::Branch.new( @directory, TEST_PERSON_DN, newattrs )
522
+
523
+ @conn.should_receive( :add ).with( TEST_PERSON_DN, {
489
524
  'cn' => ['Chilly T'],
490
525
  'desc' => ['Audi like Jetta'],
491
526
  'objectClass' => ['room'],
492
- TEST_PERSON_DN_ATTR => [TEST_PERSON_DN_VALUE],
493
- }
494
-
495
- branch = mock( "new person branch" )
496
- branch.should_receive( :dn ).and_return( TEST_PERSON_DN )
497
- branch.should_receive( :rdn_attributes ).at_least( :once ).and_return( rdn_attrs )
498
-
499
- room_objectclass = stub( 'room objectClass', :structural? => true )
500
- @schema.should_receive( :object_classes ).at_least( :once ).and_return({
501
- :room => room_objectclass,
502
527
  })
503
528
 
504
- @conn.should_receive( :add ).with( TEST_PERSON_DN, addattrs )
505
-
506
529
  @dir.create( branch, newattrs )
507
530
  end
508
531
 
509
532
 
510
- it "doesn't include duplicates when smushing RDN attributes" do
511
- newattrs = {
512
- TEST_PERSON_DN_ATTR => [TEST_PERSON_DN_VALUE],
513
- :cn => 'Chilly T',
514
- :desc => 'Audi like Jetta',
515
- :objectClass => :room,
516
- }
517
- rdn_attrs = {
518
- TEST_PERSON_DN_ATTR => [TEST_PERSON_DN_VALUE]
519
- }
520
- addattrs = {
521
- 'cn' => ['Chilly T'],
522
- 'desc' => ['Audi like Jetta'],
523
- 'objectClass' => ['room'],
524
- TEST_PERSON_DN_ATTR => [TEST_PERSON_DN_VALUE],
525
- }
526
-
527
- branch = mock( "new person branch" )
528
- branch.should_receive( :dn ).and_return( TEST_PERSON_DN )
529
- branch.should_receive( :rdn_attributes ).at_least( :once ).and_return( rdn_attrs )
530
-
531
- room_objectclass = stub( 'room objectClass', :structural? => true )
532
- @schema.should_receive( :object_classes ).at_least( :once ).and_return({
533
- :room => room_objectclass,
534
- })
533
+ it "can create an entry with a DN and LDAP::Mod objects instead of an attribute hash" do
534
+ mods = [
535
+ ldap_mod_add( :cn, 'Chilly T' ),
536
+ ldap_mod_add( :desc, 'Audi like Jetta' ),
537
+ ldap_mod_add( :objectClass, 'room' ),
538
+ ]
535
539
 
536
- @conn.should_receive( :add ).with( TEST_PERSON_DN, addattrs )
540
+ @conn.should_receive( :add ).with( TEST_PERSON_DN, mods )
537
541
 
538
- @dir.create( branch, newattrs )
542
+ @dir.create( TEST_PERSON_DN, mods )
539
543
  end
540
544
 
541
-
542
545
  it "can move a record to a new dn within the same branch" do
543
546
  @dir.stub( :bound? ).and_return( false )
544
547
  branch = mock( "sibling branch obj" )
@@ -596,7 +599,9 @@ describe Treequel::Directory do
596
599
  describe "to a server that supports controls introspection" do
597
600
  before( :each ) do
598
601
  @control = Module.new { include Treequel::Control }
599
- @conn.should_receive( :root_dse ).and_return( TEST_DSE )
602
+ @conn.stub( :search_ext2 ).
603
+ with( "", 0, "(objectClass=*)", ["+"], false, nil, nil, 0, 0, 0, "", nil ).
604
+ and_return( TEST_DSE )
600
605
  end
601
606
 
602
607
 
@@ -635,7 +640,9 @@ describe Treequel::Directory do
635
640
 
636
641
  describe "to a server that supports extensions introspection" do
637
642
  before( :each ) do
638
- @conn.should_receive( :root_dse ).and_return( TEST_DSE )
643
+ @conn.stub( :search_ext2 ).
644
+ with( "", 0, "(objectClass=*)", ["+"], false, nil, nil, 0, 0, 0, "", nil ).
645
+ and_return( TEST_DSE )
639
646
  end
640
647
 
641
648
 
@@ -653,7 +660,9 @@ describe Treequel::Directory do
653
660
 
654
661
  describe "to a server that supports features introspection" do
655
662
  before( :each ) do
656
- @conn.should_receive( :root_dse ).and_return( TEST_DSE )
663
+ @conn.stub( :search_ext2 ).
664
+ with( "", 0, "(objectClass=*)", ["+"], false, nil, nil, 0, 0, 0, "", nil ).
665
+ and_return( TEST_DSE )
657
666
  end
658
667
 
659
668
 
@@ -670,7 +679,9 @@ describe Treequel::Directory do
670
679
 
671
680
  describe "to a server that doesn't support features introspection" do
672
681
  before( :each ) do
673
- @conn.should_receive( :root_dse ).and_return( TEST_DSE )
682
+ @conn.stub( :search_ext2 ).
683
+ with( "", 0, "(objectClass=*)", ["+"], false, nil, nil, 0, 0, 0, "", nil ).
684
+ and_return( TEST_DSE )
674
685
  end
675
686
 
676
687