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.tar.gz.sig +0 -0
- data/ChangeLog +3374 -0
- data/History.md +39 -0
- data/LICENSE +27 -0
- data/README.md +25 -2
- data/Rakefile +64 -29
- data/bin/treequel +16 -25
- data/bin/treewhat +318 -0
- data/lib/treequel.rb +13 -3
- data/lib/treequel/behavior/control.rb +40 -0
- data/lib/treequel/branch.rb +56 -28
- data/lib/treequel/branchset.rb +10 -2
- data/lib/treequel/controls/pagedresults.rb +4 -2
- data/lib/treequel/directory.rb +40 -50
- data/lib/treequel/exceptions.rb +18 -0
- data/lib/treequel/mixins.rb +44 -14
- data/lib/treequel/model.rb +338 -21
- data/lib/treequel/model/errors.rb +79 -0
- data/lib/treequel/model/objectclass.rb +26 -2
- data/lib/treequel/model/schemavalidations.rb +69 -0
- data/lib/treequel/monkeypatches.rb +99 -17
- data/lib/treequel/schema.rb +19 -5
- data/spec/lib/constants.rb +20 -2
- data/spec/lib/helpers.rb +25 -8
- data/spec/treequel/branch_spec.rb +73 -10
- data/spec/treequel/controls/contentsync_spec.rb +2 -11
- data/spec/treequel/controls/pagedresults_spec.rb +25 -9
- data/spec/treequel/controls/sortedresults_spec.rb +8 -10
- data/spec/treequel/directory_spec.rb +74 -63
- data/spec/treequel/model/errors_spec.rb +77 -0
- data/spec/treequel/model/objectclass_spec.rb +107 -35
- data/spec/treequel/model/schemavalidations_spec.rb +112 -0
- data/spec/treequel/model_spec.rb +294 -81
- data/spec/treequel/monkeypatches_spec.rb +49 -3
- metadata +28 -16
- metadata.gz.sig +0 -0
- data/spec/lib/control_behavior.rb +0 -47
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::
|
78
|
-
level = Treequel::
|
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( :
|
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 ==
|
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 ==
|
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 => [
|
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 => [
|
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
|
758
|
-
@branch[ :
|
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
|
-
@
|
35
|
-
@
|
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
|
38
|
-
@
|
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
|
-
@
|
36
|
-
@
|
37
|
-
|
38
|
-
@
|
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
|
-
|
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
|
-
|
84
|
-
|
85
|
-
|
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
|
-
|
88
|
-
|
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
|
-
|
93
|
-
|
94
|
-
|
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
|
-
|
105
|
+
dir = Treequel::Directory.new( @options )
|
100
106
|
|
101
|
-
|
107
|
+
dir.results_class = subtype
|
102
108
|
|
103
|
-
|
104
|
-
|
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
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
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 "
|
511
|
-
|
512
|
-
|
513
|
-
:
|
514
|
-
:
|
515
|
-
|
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,
|
540
|
+
@conn.should_receive( :add ).with( TEST_PERSON_DN, mods )
|
537
541
|
|
538
|
-
@dir.create(
|
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.
|
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.
|
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.
|
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.
|
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
|
|