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.
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ BEGIN {
4
+ require 'pathname'
5
+ basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
6
+
7
+ libdir = basedir + "lib"
8
+
9
+ $LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
10
+ $LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
11
+ }
12
+
13
+ require 'rspec'
14
+
15
+ require 'spec/lib/helpers'
16
+
17
+ require 'treequel/model'
18
+ require 'treequel/model/errors'
19
+ require 'treequel/branchset'
20
+
21
+
22
+
23
+ #####################################################################
24
+ ### C O N T E X T S
25
+ #####################################################################
26
+
27
+ describe Treequel::Model::Errors do
28
+
29
+ before( :all ) do
30
+ setup_logging( :fatal )
31
+ end
32
+
33
+ before( :each ) do
34
+ @errors = Treequel::Model::Errors.new
35
+ end
36
+
37
+ after( :all ) do
38
+ reset_logging()
39
+ end
40
+
41
+
42
+ it "allows the addition of errors" do
43
+ @errors.add( :cn, "Not a common name." )
44
+ @errors[:cn].should have( 1 ).member
45
+ @errors[:cn].should include( "Not a common name." )
46
+ end
47
+
48
+ it "knows how many errors there are" do
49
+ @errors.add( :l, "is not valid" )
50
+ @errors.add( :description, "must " )
51
+ @errors.add( :description, "must have at least one description" )
52
+
53
+ @errors.count.should == 3
54
+ end
55
+
56
+ it "is empty if there haven't been any errors registered" do
57
+ @errors.should be_empty()
58
+ end
59
+
60
+ it "isn't empty if there have been errors registered" do
61
+ @errors.add( :uid, 'duplicate value' )
62
+ @errors.should_not be_empty()
63
+ end
64
+
65
+ it "can build an array of error messages" do
66
+ @errors.add( :l, "is not a valid location" )
67
+ @errors.add( [:givenName, :sn, :displayName], "must be unique" )
68
+
69
+ @errors.full_messages.should have( 2 ).members
70
+ @errors.full_messages.should include( "givenName and sn and displayName must be unique" )
71
+ @errors.full_messages.should include( "l is not a valid location" )
72
+ end
73
+
74
+ end
75
+
76
+
77
+ # vim: set nosta noet ts=4 sw=4:
@@ -12,34 +12,29 @@ BEGIN {
12
12
 
13
13
  require 'rspec'
14
14
 
15
- require 'spec/lib/constants'
16
15
  require 'spec/lib/helpers'
17
- require 'spec/lib/matchers'
18
16
 
19
17
  require 'treequel/model'
20
18
  require 'treequel/model/objectclass'
21
19
  require 'treequel/branchset'
22
20
 
23
21
 
24
- include Treequel::TestConstants
25
- include Treequel::Constants
26
22
 
27
23
  #####################################################################
28
24
  ### C O N T E X T S
29
25
  #####################################################################
30
26
 
31
27
  describe Treequel::Model::ObjectClass do
32
- include Treequel::SpecHelpers,
33
- Treequel::Matchers
34
-
35
- class << self
36
- alias_method :they, :it
37
- end
38
28
 
39
29
  before( :all ) do
40
30
  setup_logging( :fatal )
41
31
  end
42
32
 
33
+ after( :each ) do
34
+ Treequel::Model.objectclass_registry.clear
35
+ Treequel::Model.base_registry.clear
36
+ end
37
+
43
38
  after( :all ) do
44
39
  reset_logging()
45
40
  end
@@ -54,14 +49,9 @@ describe Treequel::Model::ObjectClass do
54
49
  end
55
50
 
56
51
 
57
- describe "modules" do
58
-
59
- after( :each ) do
60
- Treequel::Model.objectclass_registry.clear
61
- Treequel::Model.base_registry.clear
62
- end
52
+ context "extended module" do
63
53
 
64
- they "can declare a required objectClass" do
54
+ it "can declare a required objectClass" do
65
55
  mixin = Module.new do
66
56
  extend Treequel::Model::ObjectClass
67
57
  model_objectclasses :inetOrgPerson
@@ -70,7 +60,7 @@ describe Treequel::Model::ObjectClass do
70
60
  mixin.model_objectclasses.should == [:inetOrgPerson]
71
61
  end
72
62
 
73
- they "can declare a required objectClass as a String" do
63
+ it "can declare a required objectClass as a String" do
74
64
  mixin = Module.new do
75
65
  extend Treequel::Model::ObjectClass
76
66
  model_objectclasses 'apple-computer-list'
@@ -79,7 +69,7 @@ describe Treequel::Model::ObjectClass do
79
69
  mixin.model_objectclasses.should == [:'apple-computer-list']
80
70
  end
81
71
 
82
- they "can declare multiple required objectClasses" do
72
+ it "can declare multiple required objectClasses" do
83
73
  mixin = Module.new do
84
74
  extend Treequel::Model::ObjectClass
85
75
  model_objectclasses :inetOrgPerson, :acmeAccount
@@ -88,9 +78,10 @@ describe Treequel::Model::ObjectClass do
88
78
  mixin.model_objectclasses.should == [ :inetOrgPerson, :acmeAccount ]
89
79
  end
90
80
 
91
- they "can declare a single base" do
81
+ it "can declare a single base" do
92
82
  mixin = Module.new do
93
- extend Treequel::Model::ObjectClass
83
+ extend Treequel::Model::ObjectClass,
84
+ Treequel::TestConstants
94
85
  model_objectclasses :device
95
86
  model_bases TEST_PHONES_DN
96
87
  end
@@ -98,7 +89,7 @@ describe Treequel::Model::ObjectClass do
98
89
  mixin.model_bases.should == [TEST_PHONES_DN]
99
90
  end
100
91
 
101
- they "can declare base with spaces" do
92
+ it "can declare a base with spaces" do
102
93
  mixin = Module.new do
103
94
  extend Treequel::Model::ObjectClass
104
95
  model_objectclasses :device
@@ -108,9 +99,10 @@ describe Treequel::Model::ObjectClass do
108
99
  mixin.model_bases.should == ['ou=phones,dc=acme,dc=com']
109
100
  end
110
101
 
111
- they "can declare multiple bases" do
102
+ it "can declare multiple bases" do
112
103
  mixin = Module.new do
113
- extend Treequel::Model::ObjectClass
104
+ extend Treequel::Model::ObjectClass,
105
+ Treequel::TestConstants
114
106
  model_objectclasses :ipHost
115
107
  model_bases TEST_HOSTS_DN,
116
108
  TEST_SUBHOSTS_DN
@@ -119,7 +111,7 @@ describe Treequel::Model::ObjectClass do
119
111
  mixin.model_bases.should include( TEST_HOSTS_DN, TEST_SUBHOSTS_DN )
120
112
  end
121
113
 
122
- they "raises an exception when creating a search for a mixin that hasn't declared " +
114
+ it "raises an exception when creating a search for a mixin that hasn't declared " +
123
115
  "at least one objectClass or base" do
124
116
  mixin = Module.new do
125
117
  extend Treequel::Model::ObjectClass
@@ -130,7 +122,7 @@ describe Treequel::Model::ObjectClass do
130
122
  }.to raise_exception( Treequel::ModelError, /has no search criteria defined/ )
131
123
  end
132
124
 
133
- they "default to using Treequel::Model as their model class" do
125
+ it "defaults to using Treequel::Model as its model class" do
134
126
  mixin = Module.new do
135
127
  extend Treequel::Model::ObjectClass
136
128
  end
@@ -138,7 +130,7 @@ describe Treequel::Model::ObjectClass do
138
130
  mixin.model_class.should == Treequel::Model
139
131
  end
140
132
 
141
- they "can declare a model class other than Treequel::Model" do
133
+ it "can declare a model class other than Treequel::Model" do
142
134
  class MyModel < Treequel::Model; end
143
135
  mixin = Module.new do
144
136
  extend Treequel::Model::ObjectClass
@@ -148,7 +140,7 @@ describe Treequel::Model::ObjectClass do
148
140
  mixin.model_class.should == MyModel
149
141
  end
150
142
 
151
- they "re-register objectClasses that have already been declared when declaring a " +
143
+ it "re-registers objectClasses that have already been declared when declaring a " +
152
144
  "new model class" do
153
145
  class MyModel < Treequel::Model; end
154
146
 
@@ -162,7 +154,7 @@ describe Treequel::Model::ObjectClass do
162
154
  MyModel.objectclass_registry[:inetOrgPerson].should include( mixin )
163
155
  end
164
156
 
165
- they "re-register bases that have already been declared when declaring a " +
157
+ it "re-registers bases that have already been declared when declaring a " +
166
158
  "new model class" do
167
159
  class MyModel < Treequel::Model; end
168
160
 
@@ -175,10 +167,88 @@ describe Treequel::Model::ObjectClass do
175
167
  Treequel::Model.base_registry['ou=people,dc=acme,dc=com'].should_not include( mixin )
176
168
  MyModel.base_registry['ou=people,dc=acme,dc=com'].should include( mixin )
177
169
  end
170
+ end
171
+
172
+ context "model instantiation" do
173
+
174
+ before( :each ) do
175
+ @conn = mock( "ldap connection object" )
176
+ @directory = get_fixtured_directory( @conn )
177
+ end
178
+
179
+ it "can instantiate a new model object with its declared objectClasses" do
180
+ mixin = Module.new do
181
+ extend Treequel::Model::ObjectClass
182
+ model_objectclasses :inetOrgPerson
183
+ end
184
+
185
+ result = mixin.create( @directory, TEST_PERSON_DN )
186
+ result.should be_a( Treequel::Model )
187
+ result[:objectClass].should include( 'inetOrgPerson' )
188
+ result[TEST_PERSON_DN_ATTR].should include( TEST_PERSON_DN_VALUE )
189
+ end
190
+
191
+ it "merges objectClasses passed to the creation method" do
192
+ mixin = Module.new do
193
+ extend Treequel::Model::ObjectClass
194
+ model_objectclasses :inetOrgPerson
195
+ end
196
+
197
+ result = mixin.create( @directory, TEST_PERSON_DN,
198
+ :objectClass => [:person, :inetOrgPerson] )
199
+ result.should be_a( Treequel::Model )
200
+ result[:objectClass].should have( 2 ).members
201
+ result[:objectClass].should include( 'inetOrgPerson', 'person' )
202
+ result[TEST_PERSON_DN_ATTR].should include( TEST_PERSON_DN_VALUE )
203
+ end
204
+
205
+ it "handles the creation of objects with multi-value DNs" do
206
+ mixin = Module.new do
207
+ extend Treequel::Model::ObjectClass
208
+ model_objectclasses :ipHost, :ieee802Device, :device
209
+ end
210
+
211
+ result = mixin.create( @directory, TEST_HOST_MULTIVALUE_DN )
212
+ result.should be_a( Treequel::Model )
213
+ result[:objectClass].should have( 3 ).members
214
+ result[:objectClass].should include( 'ipHost', 'ieee802Device', 'device' )
215
+ result[TEST_HOST_MULTIVALUE_DN_ATTR1].should include( TEST_HOST_MULTIVALUE_DN_VALUE1 )
216
+ result[TEST_HOST_MULTIVALUE_DN_ATTR2].should include( TEST_HOST_MULTIVALUE_DN_VALUE2 )
217
+ end
218
+
219
+ it "can instantiate a new model object with its declared objectClasses" do
220
+ conn = mock( "ldap connection object" )
221
+ directory = get_fixtured_directory( conn )
222
+
223
+ mixin = Module.new do
224
+ extend Treequel::Model::ObjectClass
225
+ model_objectclasses :inetOrgPerson
226
+ end
227
+
228
+ result = mixin.create( directory, TEST_PERSON_DN )
229
+ result.should be_a( Treequel::Model )
230
+ result[:objectClass].should include( 'inetOrgPerson' )
231
+ end
232
+
233
+ it "merges objectClasses passed to the creation method" do
234
+ conn = mock( "ldap connection object" )
235
+ directory = get_fixtured_directory( conn )
236
+
237
+ mixin = Module.new do
238
+ extend Treequel::Model::ObjectClass
239
+ model_objectclasses :inetOrgPerson
240
+ end
241
+
242
+ result = mixin.create( directory, TEST_PERSON_DN,
243
+ :objectClass => [:person, :inetOrgPerson] )
244
+ result.should be_a( Treequel::Model )
245
+ result[:objectClass].should have( 2 ).members
246
+ result[:objectClass].should include( 'inetOrgPerson', 'person' )
247
+ end
178
248
 
179
249
  end
180
250
 
181
- describe "module that has one required objectClass declared" do
251
+ context "module that has one required objectClass declared" do
182
252
 
183
253
  before( :each ) do
184
254
  @mixin = Module.new do
@@ -216,7 +286,7 @@ describe Treequel::Model::ObjectClass do
216
286
 
217
287
  end
218
288
 
219
- describe "module that has more than one required objectClass declared" do
289
+ context "module that has more than one required objectClass declared" do
220
290
 
221
291
  before( :each ) do
222
292
  @mixin = Module.new do
@@ -256,10 +326,11 @@ describe Treequel::Model::ObjectClass do
256
326
 
257
327
  end
258
328
 
259
- describe "module that has one base declared" do
329
+ context "module that has one base declared" do
260
330
  before( :each ) do
261
331
  @mixin = Module.new do
262
- extend Treequel::Model::ObjectClass
332
+ extend Treequel::Model::ObjectClass,
333
+ Treequel::TestConstants
263
334
  model_bases TEST_PEOPLE_DN
264
335
  end
265
336
  end
@@ -293,10 +364,11 @@ describe Treequel::Model::ObjectClass do
293
364
 
294
365
  end
295
366
 
296
- describe "module that has more than one base declared" do
367
+ context "module that has more than one base declared" do
297
368
  before( :each ) do
298
369
  @mixin = Module.new do
299
- extend Treequel::Model::ObjectClass
370
+ extend Treequel::Model::ObjectClass,
371
+ Treequel::TestConstants
300
372
  model_bases TEST_HOSTS_DN,
301
373
  TEST_SUBHOSTS_DN
302
374
  end
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ BEGIN {
4
+ require 'pathname'
5
+ basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
6
+
7
+ libdir = basedir + "lib"
8
+
9
+ $LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
10
+ $LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
11
+ }
12
+
13
+ require 'rspec'
14
+
15
+ require 'spec/lib/helpers'
16
+
17
+ require 'treequel/model'
18
+ require 'treequel/model/schemavalidations'
19
+
20
+
21
+
22
+ #####################################################################
23
+ ### C O N T E X T S
24
+ #####################################################################
25
+
26
+ describe Treequel::Model::SchemaValidations do
27
+
28
+ before( :all ) do
29
+ setup_logging( :fatal )
30
+ end
31
+
32
+ before( :each ) do
33
+ @conn = double( "LDAP connection", :bound? => false )
34
+ @directory = get_fixtured_directory( @conn )
35
+ @modelobj = Treequel::Model.new( @directory, TEST_PERSON_DN )
36
+ end
37
+
38
+ after( :all ) do
39
+ reset_logging()
40
+ end
41
+
42
+ # StructuralObjectClass ( 2.5.6.6 NAME 'person'
43
+ # DESC 'RFC2256: a person'
44
+ # SUP top STRUCTURAL
45
+ # MUST ( sn $ cn )
46
+ # MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )
47
+
48
+ it "adds an error if the object doesn't have at least one value for all of its MUST attributes" do
49
+ @conn.stub( :search_ext2 ).and_return( [] )
50
+ @modelobj.object_class = 'person'
51
+ @modelobj.validate
52
+ @modelobj.errors.should have( 2 ).members
53
+ @modelobj.errors.full_messages.should include( 'cn MUST have at least one value' )
54
+ @modelobj.errors.full_messages.should include( 'sn MUST have at least one value' )
55
+ end
56
+
57
+ it "adds an error if the object has a value for an attribute that isn't in one of its MAY attributes" do
58
+ # First set the object classes to include one which MAY have a 'displayName'
59
+ entry = {
60
+ 'objectClass' => ['person', 'inetOrgPerson'],
61
+ 'cn' => ['J. Random'],
62
+ 'sn' => ['Hacker'],
63
+ 'displayName' => ['Trinket the Trivial']
64
+ }
65
+ @conn.stub( :search_ext2 ).and_return([ entry ])
66
+
67
+ # ..then remove the objectclass that grants it and validate
68
+ @modelobj.object_class -= ['inetOrgPerson']
69
+ @modelobj.validate
70
+
71
+ @modelobj.errors.full_messages.
72
+ should == [%{displayName is not allowed by entry's objectClasses}]
73
+ end
74
+
75
+ # AuxiliaryObjectClass ( 1.3.6.1.1.1.2.0 NAME 'posixAccount'
76
+ # DESC 'Abstraction of an account with POSIX attributes'
77
+ # SUP top AUXILIARY
78
+ # MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
79
+ # MAY ( userPassword $ loginShell $ gecos $ description ) )
80
+
81
+ it "adds an error if the object has a value for an attribute that doesn't match the " +
82
+ "attribute's syntax" do
83
+ @conn.stub( :search_ext2 ).and_return( [] )
84
+
85
+ @modelobj.object_class = ['inetOrgPerson', 'posixAccount']
86
+ @modelobj.cn = 'J. Random'
87
+ @modelobj.sn = 'Hacker'
88
+ @modelobj.uid = 'jrandom'
89
+ @modelobj.home_directory = '/users/j/jrandom'
90
+
91
+ # Set the 'Integer' attributes to values that can't be cast to integers
92
+ @modelobj.uid_number = "something that's not a number"
93
+ @modelobj.gid_number = "also not a number"
94
+
95
+ @modelobj.validate
96
+
97
+ @modelobj.errors.should have( 2 ).members
98
+ @modelobj.errors.full_messages.should include( "uidNumber isn't a valid Integer value" )
99
+ @modelobj.errors.full_messages.should include( "gidNumber isn't a valid Integer value" )
100
+ end
101
+
102
+ it "does nothing if :with_schema => false is passed to #validate" do
103
+ @conn.stub( :search_ext2 ).and_return( [] )
104
+ @modelobj.object_class = 'person' # MUST ( sn $ cn )
105
+ @modelobj.validate( :with_schema => false )
106
+ @modelobj.errors.should be_empty()
107
+ end
108
+
109
+ end
110
+
111
+
112
+ # vim: set nosta noet ts=4 sw=4: