treequel 1.2.2 → 1.3.0pre384

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: