treequel 1.0.1 → 1.0.4
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/ChangeLog +176 -14
- data/LICENSE +1 -1
- data/Rakefile +61 -45
- data/Rakefile.local +20 -0
- data/bin/treequel +502 -269
- data/examples/ldap-rack-auth.rb +2 -0
- data/lib/treequel.rb +221 -18
- data/lib/treequel/branch.rb +410 -201
- data/lib/treequel/branchcollection.rb +25 -13
- data/lib/treequel/branchset.rb +42 -40
- data/lib/treequel/constants.rb +233 -3
- data/lib/treequel/control.rb +95 -0
- data/lib/treequel/controls/contentsync.rb +138 -0
- data/lib/treequel/controls/pagedresults.rb +162 -0
- data/lib/treequel/controls/sortedresults.rb +216 -0
- data/lib/treequel/directory.rb +212 -65
- data/lib/treequel/exceptions.rb +11 -12
- data/lib/treequel/filter.rb +1 -12
- data/lib/treequel/mixins.rb +83 -47
- data/lib/treequel/monkeypatches.rb +29 -0
- data/lib/treequel/schema.rb +23 -19
- data/lib/treequel/schema/attributetype.rb +33 -3
- data/lib/treequel/schema/ldapsyntax.rb +0 -11
- data/lib/treequel/schema/matchingrule.rb +0 -11
- data/lib/treequel/schema/matchingruleuse.rb +0 -11
- data/lib/treequel/schema/objectclass.rb +36 -10
- data/lib/treequel/schema/table.rb +159 -0
- data/lib/treequel/sequel_integration.rb +7 -7
- data/lib/treequel/utils.rb +4 -66
- data/rake/documentation.rb +89 -0
- data/rake/helpers.rb +375 -307
- data/rake/hg.rb +16 -2
- data/rake/manual.rb +11 -6
- data/rake/packaging.rb +20 -35
- data/rake/publishing.rb +22 -62
- data/spec/lib/constants.rb +20 -0
- data/spec/lib/control_behavior.rb +44 -0
- data/spec/lib/matchers.rb +51 -0
- data/spec/treequel/branch_spec.rb +88 -29
- data/spec/treequel/branchcollection_spec.rb +24 -1
- data/spec/treequel/branchset_spec.rb +123 -51
- data/spec/treequel/control_spec.rb +48 -0
- data/spec/treequel/controls/contentsync_spec.rb +38 -0
- data/spec/treequel/controls/pagedresults_spec.rb +138 -0
- data/spec/treequel/controls/sortedresults_spec.rb +171 -0
- data/spec/treequel/directory_spec.rb +186 -16
- data/spec/treequel/mixins_spec.rb +42 -3
- data/spec/treequel/schema/attributetype_spec.rb +22 -20
- data/spec/treequel/schema/objectclass_spec.rb +67 -46
- data/spec/treequel/schema/table_spec.rb +134 -0
- data/spec/treequel_spec.rb +277 -15
- metadata +89 -108
- data/bin/treequel.orig +0 -963
- data/examples/ldap-monitor.rb +0 -143
- data/examples/ldap-monitor/public/css/master.css +0 -328
- data/examples/ldap-monitor/public/images/card_small.png +0 -0
- data/examples/ldap-monitor/public/images/chain_small.png +0 -0
- data/examples/ldap-monitor/public/images/globe_small.png +0 -0
- data/examples/ldap-monitor/public/images/globe_small_green.png +0 -0
- data/examples/ldap-monitor/public/images/plug.png +0 -0
- data/examples/ldap-monitor/public/images/shadows/large-30-down.png +0 -0
- data/examples/ldap-monitor/public/images/tick.png +0 -0
- data/examples/ldap-monitor/public/images/tick_circle.png +0 -0
- data/examples/ldap-monitor/public/images/treequel-favicon.png +0 -0
- data/examples/ldap-monitor/views/backends.erb +0 -41
- data/examples/ldap-monitor/views/connections.erb +0 -74
- data/examples/ldap-monitor/views/databases.erb +0 -39
- data/examples/ldap-monitor/views/dump_subsystem.erb +0 -14
- data/examples/ldap-monitor/views/index.erb +0 -14
- data/examples/ldap-monitor/views/layout.erb +0 -35
- data/examples/ldap-monitor/views/listeners.erb +0 -30
- data/rake/rdoc.rb +0 -30
- data/rake/win32.rb +0 -190
data/rake/hg.rb
CHANGED
@@ -22,6 +22,8 @@ unless defined?( HG_DOTDIR )
|
|
22
22
|
###
|
23
23
|
|
24
24
|
module MercurialHelpers
|
25
|
+
require './helpers.rb' unless defined?( RakefileHelpers )
|
26
|
+
include RakefileHelpers
|
25
27
|
|
26
28
|
###############
|
27
29
|
module_function
|
@@ -83,7 +85,7 @@ unless defined?( HG_DOTDIR )
|
|
83
85
|
|
84
86
|
### Return the list of files which are of status 'unknown'
|
85
87
|
def get_unknown_files
|
86
|
-
list = read_command_output( 'hg', 'status', '-un', '--
|
88
|
+
list = read_command_output( 'hg', 'status', '-un', '--color', 'never' )
|
87
89
|
list = list.split( /\n/ )
|
88
90
|
|
89
91
|
trace "New files: %p" % [ list ]
|
@@ -208,8 +210,20 @@ unless defined?( HG_DOTDIR )
|
|
208
210
|
task :add => :newfiles
|
209
211
|
|
210
212
|
|
213
|
+
desc "Pull and update from the default repo"
|
214
|
+
task :pull do
|
215
|
+
paths = get_repo_paths()
|
216
|
+
if origin_url = paths['default']
|
217
|
+
ask_for_confirmation( "Pull and update from '#{origin_url}'?", false ) do
|
218
|
+
run 'hg', 'pull', '-u'
|
219
|
+
end
|
220
|
+
else
|
221
|
+
trace "Skipping pull: No 'default' path."
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
211
225
|
desc "Check the current code in if tests pass"
|
212
|
-
task :checkin => ['hg:newfiles', 'test', COMMIT_MSG_FILE] do
|
226
|
+
task :checkin => ['hg:pull', 'hg:newfiles', 'test', COMMIT_MSG_FILE] do
|
213
227
|
targets = get_target_args()
|
214
228
|
$stderr.puts '---', File.read( COMMIT_MSG_FILE ), '---'
|
215
229
|
ask_for_confirmation( "Continue with checkin?" ) do
|
data/rake/manual.rb
CHANGED
@@ -147,9 +147,14 @@ module Manual
|
|
147
147
|
|
148
148
|
layout = self.config['layout'].sub( /\.page$/, '' )
|
149
149
|
templatepath = @layouts_dir + "#{layout}.page"
|
150
|
-
template =
|
151
|
-
|
150
|
+
template = nil
|
151
|
+
if Object.const_defined?( :Encoding )
|
152
|
+
template = ERB.new( templatepath.read(:encoding => 'UTF-8') )
|
153
|
+
else
|
154
|
+
template = ERB.new( templatepath.read )
|
155
|
+
end
|
152
156
|
|
157
|
+
page = self
|
153
158
|
html = template.result( binding() )
|
154
159
|
|
155
160
|
# Use Tidy to clean up the html if 'cleanup' is turned on, but remove the Tidy
|
@@ -565,7 +570,7 @@ module Manual
|
|
565
570
|
manual_pages = setup_page_conversion_tasks( sourcedir, outputdir, catalog )
|
566
571
|
|
567
572
|
desc "Build the manual"
|
568
|
-
task :build => [ :
|
573
|
+
task :build => [ :apidocs, :copy_resources, :copy_apidocs, :generate_pages ]
|
569
574
|
|
570
575
|
task :clobber do
|
571
576
|
RakeFileUtils.verbose( $verbose ) do
|
@@ -686,8 +691,8 @@ module Manual
|
|
686
691
|
end
|
687
692
|
|
688
693
|
desc "Copy API documentation to the manual output directory"
|
689
|
-
task :copy_apidocs => :
|
690
|
-
cp_r(
|
694
|
+
task :copy_apidocs => :apidocs do
|
695
|
+
cp_r( API_DOCSDIR, outputdir )
|
691
696
|
end
|
692
697
|
|
693
698
|
# Now group all the resource file tasks into a containing task
|
@@ -713,7 +718,7 @@ if MANUALDIR.exist?
|
|
713
718
|
|
714
719
|
Manual::GenTask.new do |manual|
|
715
720
|
manual.metadata.version = PKG_VERSION
|
716
|
-
manual.metadata.api_dir =
|
721
|
+
manual.metadata.api_dir = API_DOCSDIR
|
717
722
|
manual.output_dir = MANUALOUTPUTDIR
|
718
723
|
manual.base_dir = MANUALDIR
|
719
724
|
manual.source_dir = 'src'
|
data/rake/packaging.rb
CHANGED
@@ -1,17 +1,27 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
#
|
1
|
+
#####################################################################
|
2
|
+
### P A C K A G I N G T A S K S
|
3
|
+
#####################################################################
|
5
4
|
|
6
5
|
require 'rbconfig'
|
7
6
|
require 'pathname'
|
8
|
-
require '
|
9
|
-
require 'rake/gempackagetask'
|
7
|
+
require 'rubygems/package_task'
|
10
8
|
|
11
|
-
require Pathname( __FILE__ ).dirname.expand_path + 'hg.rb'
|
12
9
|
|
13
10
|
include Config
|
14
11
|
|
12
|
+
### Task: prerelease
|
13
|
+
desc "Append the package build number to package versions"
|
14
|
+
task :prerelease do
|
15
|
+
GEMSPEC.version.version << ".#{PKG_BUILD}"
|
16
|
+
Rake::Task[:gem].clear
|
17
|
+
|
18
|
+
Gem::PackageTask.new( GEMSPEC ) do |pkg|
|
19
|
+
pkg.need_zip = true
|
20
|
+
pkg.need_tar = true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
15
25
|
### Task: gem
|
16
26
|
### Task: package
|
17
27
|
Rake::PackageTask.new( PKG_NAME, PKG_VERSION ) do |task|
|
@@ -24,34 +34,9 @@ end
|
|
24
34
|
task :package => [:gem]
|
25
35
|
|
26
36
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
desc "Build a RubyGem package (#{GEM_FILE_NAME})"
|
31
|
-
task :gem => gempath.to_s
|
32
|
-
file gempath.to_s => [PKGDIR.to_s] + GEMSPEC.files do
|
33
|
-
when_writing( "Creating GEM" ) do
|
34
|
-
Gem::Builder.new( GEMSPEC ).build
|
35
|
-
verbose( true ) do
|
36
|
-
mv GEM_FILE_NAME, gempath
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
|
42
|
-
prerelease_gempath = PKGDIR + SNAPSHOT_GEM_NAME
|
43
|
-
|
44
|
-
desc "Build a pre-release RubyGem package"
|
45
|
-
task :prerelease_gem => prerelease_gempath.to_s
|
46
|
-
file prerelease_gempath.to_s => [PKGDIR.to_s] + GEMSPEC.files do
|
47
|
-
when_writing( "Creating prerelease GEM" ) do
|
48
|
-
gemspec = GEMSPEC.clone
|
49
|
-
gemspec.version = Gem::Version.create( "%s.%s" % [GEMSPEC.version, PKG_BUILD] )
|
50
|
-
Gem::Builder.new( gemspec ).build
|
51
|
-
verbose( true ) do
|
52
|
-
mv SNAPSHOT_GEM_NAME, prerelease_gempath
|
53
|
-
end
|
54
|
-
end
|
37
|
+
Gem::PackageTask.new( GEMSPEC ) do |pkg|
|
38
|
+
pkg.need_zip = true
|
39
|
+
pkg.need_tar = true
|
55
40
|
end
|
56
41
|
|
57
42
|
|
data/rake/publishing.rb
CHANGED
@@ -34,7 +34,13 @@ class Net::SMTP
|
|
34
34
|
|
35
35
|
def do_ssl_start( helodomain, user, secret, authtype )
|
36
36
|
raise IOError, 'SMTP session already started' if @started
|
37
|
-
|
37
|
+
if user or secret
|
38
|
+
if self.method( :check_auth_args ).arity == 3
|
39
|
+
check_auth_args( user, secret, authtype )
|
40
|
+
else
|
41
|
+
check_auth_args( user, secret )
|
42
|
+
end
|
43
|
+
end
|
38
44
|
|
39
45
|
# Open the connection
|
40
46
|
@debug_output << "opening connection to #{@address}...\n" if @debug_output
|
@@ -85,7 +91,6 @@ begin
|
|
85
91
|
require 'tmail'
|
86
92
|
require 'net/smtp'
|
87
93
|
require 'etc'
|
88
|
-
require 'rubyforge'
|
89
94
|
require 'socket'
|
90
95
|
require 'text/format'
|
91
96
|
|
@@ -134,11 +139,11 @@ begin
|
|
134
139
|
task :project => :upload # the old name
|
135
140
|
|
136
141
|
desc "Publish the project docs to #{PROJECT_HOST}"
|
137
|
-
task :upload_docs => [ :
|
142
|
+
task :upload_docs => [ :apidocs ] do
|
138
143
|
when_writing( "Publishing docs to #{PROJECT_SCPDOCURL}" ) do
|
139
144
|
log "Uploading API documentation to %s:%s" % [ PROJECT_HOST, PROJECT_DOCDIR ]
|
140
145
|
run 'ssh', PROJECT_HOST, "rm -rf #{PROJECT_DOCDIR}"
|
141
|
-
run 'scp', '-qCr',
|
146
|
+
run 'scp', '-qCr', API_DOCSDIR, PROJECT_SCPDOCURL
|
142
147
|
end
|
143
148
|
end
|
144
149
|
|
@@ -195,15 +200,20 @@ begin
|
|
195
200
|
desc 'Send out a release announcement'
|
196
201
|
task :announce => [RELEASE_ANNOUNCE_FILE] do
|
197
202
|
email = TMail::Mail.new
|
198
|
-
|
203
|
+
|
204
|
+
if $publish_privately || RELEASE_ANNOUNCE_ADDRESSES.empty?
|
199
205
|
trace "Sending private announce mail"
|
200
206
|
email.to = 'rubymage@gmail.com'
|
201
207
|
else
|
202
208
|
trace "Sending public announce mail"
|
203
|
-
email.to =
|
209
|
+
email.to = RELEASE_ANNOUNCE_ADDRESSES
|
204
210
|
email.bcc = 'rubymage@gmail.com'
|
205
211
|
end
|
206
|
-
|
212
|
+
|
213
|
+
from = prompt_with_default( "Send announcement as:",
|
214
|
+
'Michael Granger <ged@FaerieMUD.org>' ) or fail
|
215
|
+
|
216
|
+
email.from = from
|
207
217
|
email.subject = "[ANN] #{PKG_NAME} #{PKG_VERSION}"
|
208
218
|
email.body = File.read( RELEASE_ANNOUNCE_FILE )
|
209
219
|
email.date = Time.new
|
@@ -236,61 +246,11 @@ begin
|
|
236
246
|
end
|
237
247
|
|
238
248
|
|
239
|
-
desc 'Publish the new release to
|
240
|
-
task :publish => [:clean, :
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
log "Skipping push of release files to RubyForge"
|
245
|
-
else
|
246
|
-
rf = RubyForge.new
|
247
|
-
log "Loading RubyForge config"
|
248
|
-
rf.configure
|
249
|
-
|
250
|
-
group_id = rf.autoconfig['group_ids'][RUBYFORGE_GROUP] or
|
251
|
-
fail "Your configuration doesn't have a group id for '#{RUBYFORGE_GROUP}'"
|
252
|
-
|
253
|
-
# If this project doesn't yet exist, create it
|
254
|
-
unless rf.autoconfig['package_ids'].key?( project )
|
255
|
-
ask_for_confirmation( "Package '#{project}' doesn't exist on RubyForge. Create it?" ) do
|
256
|
-
log "Creating new package '#{project}'"
|
257
|
-
rf.create_package( group_id, project )
|
258
|
-
end
|
259
|
-
end
|
260
|
-
|
261
|
-
package_id = rf.autoconfig['package_ids'][ project ]
|
262
|
-
|
263
|
-
# Make sure this release doesn't already exist
|
264
|
-
releases = rf.autoconfig['release_ids']
|
265
|
-
if releases.key?( GEMSPEC.name ) && releases[ GEMSPEC.name ].key?( PKG_VERSION )
|
266
|
-
log "Rubyforge seems to already have #{ PKG_FILE_NAME }"
|
267
|
-
else
|
268
|
-
config = rf.userconfig or
|
269
|
-
fail "You apparently haven't set up your RubyForge credentials on this machine."
|
270
|
-
config['release_notes'] = GEMSPEC.description
|
271
|
-
config['release_changes'] = File.read( RELEASE_NOTES_FILE )
|
272
|
-
|
273
|
-
files = FileList[ PKGDIR + GEM_FILE_NAME ]
|
274
|
-
files.include PKGDIR + "#{PKG_FILE_NAME}.tar.gz"
|
275
|
-
files.include PKGDIR + "#{PKG_FILE_NAME}.tar.bz2"
|
276
|
-
files.include PKGDIR + "#{PKG_FILE_NAME}.zip"
|
277
|
-
|
278
|
-
log "Releasing #{PKG_FILE_NAME}"
|
279
|
-
when_writing do
|
280
|
-
log "Publishing to RubyForge: \n",
|
281
|
-
"\tproject: #{RUBYFORGE_GROUP}\n",
|
282
|
-
"\tpackage: #{PKG_NAME.downcase}\n",
|
283
|
-
"\tpackage version: #{PKG_VERSION}\n",
|
284
|
-
"\tfiles: " + files.collect {|f| f.to_s }.join(', ') + "\n"
|
285
|
-
|
286
|
-
ask_for_confirmation( "Publish to RubyForge?" ) do
|
287
|
-
log 'Logging in...'
|
288
|
-
rf.login
|
289
|
-
log "Adding the new release to the '#{project}' project"
|
290
|
-
rf.add_release( group_id, package_id, PKG_VERSION, *files )
|
291
|
-
end
|
292
|
-
end
|
293
|
-
end
|
249
|
+
desc 'Publish the new release to Gemcutter'
|
250
|
+
task :publish => [:clean, :gem, :notes] do |task|
|
251
|
+
ask_for_confirmation( "Publish #{GEM_FILE_NAME} to Gemcutter?", false ) do
|
252
|
+
gempath = PKGDIR + GEM_FILE_NAME
|
253
|
+
sh 'gem', 'push', gempath
|
294
254
|
end
|
295
255
|
end
|
296
256
|
end
|
data/spec/lib/constants.rb
CHANGED
@@ -68,6 +68,11 @@ module Treequel::TestConstants # :nodoc:all
|
|
68
68
|
TEST_SUBHOSTS_RDN = "#{TEST_HOSTS_DN_ATTR}=#{TEST_HOSTS_DN_VALUE}"
|
69
69
|
TEST_SUBHOSTS_DN = "#{TEST_HOSTS_RDN},#{TEST_SUBDOMAIN_DN}"
|
70
70
|
|
71
|
+
TEST_SUBHOST_DN_ATTR = 'cn'
|
72
|
+
TEST_SUBHOST_DN_VALUE = 'ronky'
|
73
|
+
TEST_SUBHOST_RDN = "#{TEST_SUBHOST_DN_ATTR}=#{TEST_SUBHOST_DN_VALUE}"
|
74
|
+
TEST_SUBHOST_DN = "#{TEST_SUBHOST_RDN},#{TEST_SUBHOSTS_DN}"
|
75
|
+
|
71
76
|
TEST_PEOPLE_DN_ATTR = 'ou'
|
72
77
|
TEST_PEOPLE_DN_VALUE = 'People'
|
73
78
|
TEST_PEOPLE_RDN = "#{TEST_PEOPLE_DN_ATTR}=#{TEST_PEOPLE_DN_VALUE}"
|
@@ -83,6 +88,21 @@ module Treequel::TestConstants # :nodoc:all
|
|
83
88
|
TEST_PERSON2_RDN = "#{TEST_PERSON2_DN_ATTR}=#{TEST_PERSON2_DN_VALUE}"
|
84
89
|
TEST_PERSON2_DN = "#{TEST_PERSON2_RDN},#{TEST_PEOPLE_DN}"
|
85
90
|
|
91
|
+
TEST_PHONES_DN_ATTR = 'ou'
|
92
|
+
TEST_PHONES_DN_VALUE = 'Phones'
|
93
|
+
TEST_PHONES_RDN = "#{TEST_PHONES_DN_ATTR}=#{TEST_PHONES_DN_VALUE}"
|
94
|
+
TEST_PHONES_DN = "#{TEST_PHONES_RDN},#{TEST_BASE_DN}"
|
95
|
+
|
96
|
+
TEST_ROOMS_DN_ATTR = 'ou'
|
97
|
+
TEST_ROOMS_DN_VALUE = 'Rooms'
|
98
|
+
TEST_ROOMS_RDN = "#{TEST_ROOMS_DN_ATTR}=#{TEST_ROOMS_DN_VALUE}"
|
99
|
+
TEST_ROOMS_DN = "#{TEST_ROOMS_RDN},#{TEST_BASE_DN}"
|
100
|
+
|
101
|
+
TEST_ROOM_DN_ATTR = 'cn'
|
102
|
+
TEST_ROOM_DN_VALUE = 'broomcloset'
|
103
|
+
TEST_ROOM_RDN = "#{TEST_ROOM_DN_ATTR}=#{TEST_ROOM_DN_VALUE}"
|
104
|
+
TEST_ROOM_DN = "#{TEST_ROOM_RDN},#{TEST_ROOMS_DN}"
|
105
|
+
|
86
106
|
constants.each do |cname|
|
87
107
|
const_get(cname).freeze
|
88
108
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
BEGIN {
|
4
|
+
require 'pathname'
|
5
|
+
basedir = Pathname.new( __FILE__ ).dirname.parent.parent
|
6
|
+
|
7
|
+
libdir = basedir + "lib"
|
8
|
+
|
9
|
+
$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
|
10
|
+
}
|
11
|
+
|
12
|
+
require 'spec'
|
13
|
+
require 'spec/lib/constants'
|
14
|
+
require 'spec/lib/helpers'
|
15
|
+
|
16
|
+
require 'treequel'
|
17
|
+
require 'treequel/control'
|
18
|
+
|
19
|
+
include Treequel::TestConstants
|
20
|
+
include Treequel::Constants
|
21
|
+
|
22
|
+
#####################################################################
|
23
|
+
### C O N T E X T S
|
24
|
+
#####################################################################
|
25
|
+
describe "A Treequel::Control", :shared => true do
|
26
|
+
include Treequel::SpecHelpers
|
27
|
+
|
28
|
+
before( :each ) do
|
29
|
+
raise "Spec doesn't set @control before the Control shared behavior" unless @control
|
30
|
+
end
|
31
|
+
|
32
|
+
it "implements one of either #get_client_controls or #get_server_controls" do
|
33
|
+
methods = [
|
34
|
+
'get_client_controls', # 1.8.x
|
35
|
+
'get_server_controls',
|
36
|
+
:get_client_controls, # 1.9.x
|
37
|
+
:get_server_controls
|
38
|
+
]
|
39
|
+
(@control.instance_methods( false ) | methods).should_not be_empty()
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
BEGIN {
|
5
|
+
require 'pathname'
|
6
|
+
basedir = Pathname.new( __FILE__ ).dirname.parent
|
7
|
+
|
8
|
+
libdir = basedir + "lib"
|
9
|
+
|
10
|
+
$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
|
11
|
+
}
|
12
|
+
|
13
|
+
require 'yaml'
|
14
|
+
require 'treequel'
|
15
|
+
|
16
|
+
require 'spec/lib/constants'
|
17
|
+
|
18
|
+
### RSpec matchers
|
19
|
+
module Treequel::Matchers
|
20
|
+
|
21
|
+
class ArrayIncludingMatcher
|
22
|
+
def initialize( expected )
|
23
|
+
@expected = expected
|
24
|
+
end
|
25
|
+
|
26
|
+
def ==( actual )
|
27
|
+
@expected.each do |value|
|
28
|
+
return false unless actual.include?( value )
|
29
|
+
end
|
30
|
+
true
|
31
|
+
rescue NoMethodError => ex
|
32
|
+
return false
|
33
|
+
end
|
34
|
+
|
35
|
+
def description
|
36
|
+
"array_including(#{ @expected.inspect.sub(/^\[|\]$/,"") })"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
###############
|
42
|
+
module_function
|
43
|
+
###############
|
44
|
+
|
45
|
+
### Return true if the actual value includes the specified +objects+.
|
46
|
+
def array_including( *objects )
|
47
|
+
ArrayIncludingMatcher.new( objects )
|
48
|
+
end
|
49
|
+
|
50
|
+
end # module Treequel::Matchers
|
51
|
+
|
@@ -9,22 +9,14 @@ BEGIN {
|
|
9
9
|
$LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
|
10
10
|
}
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
require 'treequel/branch'
|
18
|
-
require 'treequel/branchset'
|
19
|
-
require 'treequel/branchcollection'
|
20
|
-
rescue LoadError
|
21
|
-
unless Object.const_defined?( :Gem )
|
22
|
-
require 'rubygems'
|
23
|
-
retry
|
24
|
-
end
|
25
|
-
raise
|
26
|
-
end
|
12
|
+
require 'spec'
|
13
|
+
require 'spec/lib/constants'
|
14
|
+
require 'spec/lib/helpers'
|
15
|
+
require 'spec/lib/matchers'
|
27
16
|
|
17
|
+
require 'treequel/branch'
|
18
|
+
require 'treequel/branchset'
|
19
|
+
require 'treequel/branchcollection'
|
28
20
|
|
29
21
|
include Treequel::TestConstants
|
30
22
|
include Treequel::Constants
|
@@ -34,7 +26,8 @@ include Treequel::Constants
|
|
34
26
|
#####################################################################
|
35
27
|
|
36
28
|
describe Treequel::Branch do
|
37
|
-
include Treequel::SpecHelpers
|
29
|
+
include Treequel::SpecHelpers,
|
30
|
+
Treequel::Matchers
|
38
31
|
|
39
32
|
before( :all ) do
|
40
33
|
setup_logging( :fatal )
|
@@ -150,6 +143,22 @@ describe Treequel::Branch do
|
|
150
143
|
@branch.entry.should == :the_extended_entry
|
151
144
|
end
|
152
145
|
|
146
|
+
it "can search its directory for values using itself as a base" do
|
147
|
+
@directory.should_receive( :search ).with( @branch, :one, '(objectClass=*)', {} ).
|
148
|
+
and_return( :entries )
|
149
|
+
@branch.search( :one, '(objectClass=*)' ).should == :entries
|
150
|
+
end
|
151
|
+
|
152
|
+
it "can search its directory for values with a block" do
|
153
|
+
@directory.should_receive( :search ).with( @branch, :one, '(objectClass=*)', {} ).
|
154
|
+
and_yield( :an_entry )
|
155
|
+
yielded_val = nil
|
156
|
+
@branch.search( :one, '(objectClass=*)' ) do |val|
|
157
|
+
yielded_val = val
|
158
|
+
end
|
159
|
+
yielded_val.should == :an_entry
|
160
|
+
end
|
161
|
+
|
153
162
|
it "clears any cached values if its include_operational_attrs attribute is changed" do
|
154
163
|
@directory.should_receive( :get_entry ).with( @branch ).exactly( :once ).
|
155
164
|
and_return( :the_entry )
|
@@ -201,13 +210,20 @@ describe Treequel::Branch do
|
|
201
210
|
|
202
211
|
lambda {
|
203
212
|
@branch.facelart( 'sbc' )
|
204
|
-
}.should
|
213
|
+
}.should raise_exception( NoMethodError, /undefined method.*facelart/i )
|
205
214
|
end
|
206
215
|
|
216
|
+
it "don't create sub-branches for multi-value RDNs with an invalid attribute" do
|
217
|
+
@schema.should_receive( :attribute_types ).
|
218
|
+
and_return({ :cn => :a_value, :ou => :a_value })
|
219
|
+
|
220
|
+
lambda {
|
221
|
+
@branch.cn( 'benchlicker', :facelart => 'sbc' )
|
222
|
+
}.should raise_exception( NoMethodError, /invalid secondary attribute.*facelart/i )
|
223
|
+
end
|
207
224
|
|
208
225
|
it "can return all of its immediate children as Branches" do
|
209
|
-
@directory.should_receive( :search ).
|
210
|
-
with( @branch, :one, '(objectClass=*)' ).
|
226
|
+
@directory.should_receive( :search ).with( @branch, :one, '(objectClass=*)', {} ).
|
211
227
|
and_return([ :the_children ])
|
212
228
|
@branch.children.should == [ :the_children ]
|
213
229
|
end
|
@@ -350,13 +366,14 @@ describe Treequel::Branch do
|
|
350
366
|
end
|
351
367
|
|
352
368
|
it "knows if a attribute is valid given its objectClasses" do
|
353
|
-
|
369
|
+
attrtype = mock( "attribute type object" )
|
354
370
|
|
355
371
|
@branch.should_receive( :valid_attribute_types ).
|
356
372
|
twice.
|
357
|
-
and_return([
|
373
|
+
and_return([ attrtype ])
|
358
374
|
|
359
|
-
|
375
|
+
attrtype.should_receive( :valid_name? ).with( :uid ).and_return( true )
|
376
|
+
attrtype.should_receive( :valid_name? ).with( :rubberChicken ).and_return( false )
|
360
377
|
|
361
378
|
@branch.valid_attribute?( :uid ).should be_true()
|
362
379
|
@branch.valid_attribute?( :rubberChicken ).should be_false()
|
@@ -364,7 +381,7 @@ describe Treequel::Branch do
|
|
364
381
|
|
365
382
|
it "can be moved to a new location within the directory" do
|
366
383
|
newdn = "ou=hosts,dc=admin,#{TEST_BASE_DN}"
|
367
|
-
@directory.should_receive( :move ).with( @branch, newdn
|
384
|
+
@directory.should_receive( :move ).with( @branch, newdn )
|
368
385
|
@branch.move( newdn )
|
369
386
|
end
|
370
387
|
|
@@ -379,12 +396,6 @@ describe Treequel::Branch do
|
|
379
396
|
end
|
380
397
|
|
381
398
|
|
382
|
-
it "can be deleted from the directory" do
|
383
|
-
@directory.should_receive( :delete ).with( @branch )
|
384
|
-
@branch.delete
|
385
|
-
end
|
386
|
-
|
387
|
-
|
388
399
|
it "can create children under itself" do
|
389
400
|
newattrs = {
|
390
401
|
:ipHostNumber => '127.0.0.1',
|
@@ -436,6 +447,46 @@ describe Treequel::Branch do
|
|
436
447
|
end
|
437
448
|
|
438
449
|
|
450
|
+
it "can delete all values of one of its entry's individual attributes" do
|
451
|
+
LDAP::Mod.should_receive( :new ).with( LDAP::LDAP_MOD_DELETE, 'displayName', [] ).
|
452
|
+
and_return( :mod_delete )
|
453
|
+
@directory.should_receive( :modify ).with( @branch, [:mod_delete] )
|
454
|
+
|
455
|
+
@branch.delete( :displayName )
|
456
|
+
end
|
457
|
+
|
458
|
+
it "can delete all values of more than one of its entry's individual attributes" do
|
459
|
+
LDAP::Mod.should_receive( :new ).with( LDAP::LDAP_MOD_DELETE, 'displayName', [] ).
|
460
|
+
and_return( :first_mod_delete )
|
461
|
+
LDAP::Mod.should_receive( :new ).with( LDAP::LDAP_MOD_DELETE, 'gecos', [] ).
|
462
|
+
and_return( :second_mod_delete )
|
463
|
+
@directory.should_receive( :modify ).
|
464
|
+
with( @branch, [:first_mod_delete, :second_mod_delete] )
|
465
|
+
|
466
|
+
@branch.delete( :displayName, :gecos )
|
467
|
+
end
|
468
|
+
|
469
|
+
it "can delete one particular value of its entry's individual attributes" do
|
470
|
+
LDAP::Mod.should_receive( :new ).
|
471
|
+
with( LDAP::LDAP_MOD_DELETE, 'objectClass', ['apple-user'] ).
|
472
|
+
and_return( :mod_delete )
|
473
|
+
@directory.should_receive( :modify ).with( @branch, [:mod_delete] )
|
474
|
+
|
475
|
+
@branch.delete( :objectClass => 'apple-user' )
|
476
|
+
end
|
477
|
+
|
478
|
+
it "can delete particular values of more than one of its entry's individual attributes" do
|
479
|
+
LDAP::Mod.should_receive( :new ).
|
480
|
+
with( LDAP::LDAP_MOD_DELETE, 'objectClass', ['apple-user', 'inetOrgPerson'] ).
|
481
|
+
and_return( :first_mod_delete )
|
482
|
+
LDAP::Mod.should_receive( :new ).
|
483
|
+
with( LDAP::LDAP_MOD_DELETE, 'cn', [] ).and_return( :second_mod_delete )
|
484
|
+
@directory.should_receive( :modify ).
|
485
|
+
with( @branch, array_including(:first_mod_delete, :second_mod_delete) )
|
486
|
+
|
487
|
+
@branch.delete( :objectClass => ['apple-user',:inetOrgPerson], :cn => [] )
|
488
|
+
end
|
489
|
+
|
439
490
|
it "knows how to represent its DN as an RFC1781-style UFN" do
|
440
491
|
@branch.to_ufn.should =~ /Hosts, acme\.com/i
|
441
492
|
end
|
@@ -561,6 +612,14 @@ describe Treequel::Branch do
|
|
561
612
|
end
|
562
613
|
end
|
563
614
|
|
615
|
+
it "can fetch multiple values via #values_at" do
|
616
|
+
@branch.should_receive( :[] ).with( :cn ).and_return( :cn_value )
|
617
|
+
@branch.should_receive( :[] ).with( :desc ).and_return( :desc_value )
|
618
|
+
@branch.should_receive( :[] ).with( :l ).and_return( :l_value )
|
619
|
+
|
620
|
+
@branch.values_at( :cn, :desc, :l ).should == [ :cn_value, :desc_value, :l_value ]
|
621
|
+
end
|
622
|
+
|
564
623
|
end
|
565
624
|
|
566
625
|
end
|