treequel 1.2.2 → 1.3.0pre384

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/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