Whole bunch of changes

Run sync within a SQL transaction, so that no partial sync happens

Don't abort on SQL errors, but print ERROR notice

Exit with code 1 when any ERRORs were logged

Silence the test suite, so that test runs are more clearly

Use PG queries instead of psql in test. This is more flexible
than parsing text outputs per Regexp.
This commit is contained in:
Lars Kanis
2018-03-13 16:21:20 +01:00
parent d9cb63ed98
commit 257b1a5e49
7 changed files with 164 additions and 46 deletions

2
test/fixtures/config-invalid.yaml vendored Normal file
View File

@ -0,0 +1,2 @@
---
ldap_connection:

View File

@ -5,7 +5,7 @@ ldap_connection:
ldap_users:
base: dc=example,dc=com
filter: (&(cn=*)(sAMAccountName=*))
filter: (sAMAccountName=*)
name_attribute: sAMAccountName
ldap_groups:
@ -23,7 +23,7 @@ pg_connection:
# password:
pg_users:
filter: rolcanlogin AND NOT rolsuper
filter: rolcanlogin AND NOT rolsuper AND rolname!='double_user'
create_options: LOGIN
pg_groups:

View File

@ -8,10 +8,23 @@ require_relative 'ldap_server'
class TestPgLdapSync < Minitest::Test
include Minitest::Hooks
@@logid = 0
def log_and_run( *cmd )
puts cmd.join(' ')
system( *cmd )
raise "Command failed: [%s]" % [cmd.join(' ')] unless $?.success?
if $DEBUG
puts cmd.join(' ')
system( *cmd )
raise "Command failed: [%s]" % [cmd.join(' ')] unless $?.success?
else
fname = "temp/run_#{@@logid+=1}.log"
pid = Process.spawn( *cmd, [:out, :err] => [fname, "w"] )
Process.wait(pid)
unless $?.success?
$stderr.puts "Command failed: [%s]\n%s" % [cmd.join(' '), File.read(fname)]
end
File.unlink fname
raise "Command failed: [%s]" % [cmd.join(' ')] unless $?.success?
end
end
def start_ldap_server
@ -46,9 +59,13 @@ class TestPgLdapSync < Minitest::Test
log_and_run 'initdb', '-D', 'temp/pg_data', '--no-locale'
end
log_and_run 'pg_ctl', '-w', '-o', "-k.", '-D', 'temp/pg_data', 'start'
@pgconn = PG.connect dbname: 'postgres'
@pgconn.exec "SET client_min_messages to warning"
end
def stop_pg_server
@pgconn.close if @pgconn
log_and_run 'pg_ctl', '-w', '-o', "-k.", '-D', 'temp/pg_data', 'stop'
end
@ -66,13 +83,29 @@ class TestPgLdapSync < Minitest::Test
end
def setup
log_and_run 'psql', '-e', '-c', "DROP ROLE IF EXISTS fred, wilma, \"Flintstones\", \"Wilmas\", \"All Users\"", 'postgres'
@pgconn.exec "DROP ROLE IF EXISTS fred, wilma, \"Flintstones\", \"Wilmas\", \"All Users\", double_user"
end
def psqlre(*args)
/^\s*#{args[0]}[ |]*#{args[1]}[ |\{"]*#{args[2..-1].join('[", ]+')}["\}\s]*$/
def assert_role(role_name, attrs, member_of=[])
res = @pgconn.exec("SELECT * FROM pg_roles WHERE rolname = '#{@pgconn.escape_string(role_name)}'")
assert_equal 1, res.ntuples, "Role #{role_name} not found"
res2 = @pgconn.exec "SELECT pr.rolname FROM pg_auth_members pam JOIN pg_roles pr ON pr.oid=pam.roleid WHERE pam.member=#{res.to_a[0]['oid']}"
rolnames = res2.map{|t| t['rolname'] }
assert_equal member_of.sort, rolnames.sort
exp_attrs = []
exp_attrs << 'Cannot login' if res[0]['rolcanlogin'] != 't'
exp_attrs << 'Superuser' if res[0]['rolsuper'] == 't'
assert_equal attrs, exp_attrs.join(", ")
end
def refute_role(role_name)
res = @pgconn.exec("SELECT oid FROM pg_roles WHERE rolname = '#{@pgconn.escape_string(role_name)}'")
assert_equal 0, res.ntuples, "Role #{role_name} not found"
end
def exec_psql_du
text = if RUBY_PLATFORM=~/mingw|mswin/
`psql -c \\du postgres`
@ -89,7 +122,7 @@ class TestPgLdapSync < Minitest::Test
end
def sync_with_config(config="config-ldapdb")
PgLdapSync::Application.run(["-c", "test/fixtures/#{config}.yaml", "-vv"])
PgLdapSync::Application.run(["-c", "test/fixtures/#{config}.yaml"] + ($DEBUG ? ["-vv"] : ["--no-verbose"]))
end
def sync_to_fixture(fixture: "ldapdb", config: "config-ldapdb")
@ -103,41 +136,59 @@ class TestPgLdapSync < Minitest::Test
yield(@directory)
sync_with_config
exec_psql_du
exec_psql_du if $DEBUG
end
def test_invalid_config
assert_output(/key 'ldap_users:' is required/) do
assert_raises(PgLdapSync::InvalidConfig) do
sync_with_config("config-invalid")
end
end
end
def test_base_users_groups_memberships
psql_du = sync_change{}
sync_change{}
assert_match(psqlre('All Users','Cannot login'), psql_du)
assert_match(psqlre('Flintstones','Cannot login'), psql_du)
assert_match(psqlre('Wilmas','Cannot login','All Users'), psql_du)
assert_match(psqlre('fred','','All Users','Flintstones'), psql_du)
assert_match(psqlre('wilma','','Flintstones','Wilmas'), psql_du)
assert_role('All Users', 'Cannot login')
assert_role('Flintstones', 'Cannot login')
assert_role('Wilmas', 'Cannot login', ['All Users'])
assert_role('fred', '', ['All Users', 'Flintstones'])
assert_role('wilma', '', ['Flintstones', 'Wilmas'])
end
def test_add_membership
psql_du = sync_change do |dir|
sync_change do |dir|
# add 'Fred' to 'Wilmas'
@directory[0]['cn=Wilmas,dc=example,dc=com']['member'] << 'cn=Fred Flintstone,dc=example,dc=com'
end
assert_match(psqlre('fred','','All Users','Flintstones', 'Wilmas'), psql_du)
assert_role('fred', '', ['All Users', 'Flintstones', 'Wilmas'])
end
def test_revoke_membership
psql_du = sync_change do |dir|
sync_change do |dir|
# revoke membership of 'wilma' to 'Flintstones'
dir[0]['cn=Flintstones,dc=example,dc=com']['member'].pop
end
assert_match(psqlre('wilma','','Wilmas'), psql_du)
assert_role('wilma', '', ['Wilmas'])
end
def test_rename_role
psql_du = sync_change do |dir|
sync_change do |dir|
# rename role 'wilma'
dir[0]['cn=Wilma Flintstone,dc=example,dc=com']['sAMAccountName'] = ['Wilma Flintstone']
end
refute_match(/wilma/, psql_du)
assert_match(psqlre('Wilma Flintstone','','Flintstones','Wilmas'), psql_du)
refute_role('wilma')
assert_role('Wilma Flintstone', '', ['Flintstones', 'Wilmas'])
end
def test_dont_stop_on_error
log_and_run 'psql', '-e', '-c', "CREATE ROLE double_user LOGIN", 'postgres'
assert_raises(PgLdapSync::ErrorExit) do
sync_change do |dir|
dir[0]['cn=double_user,dc=example,dc=com'] = {'sAMAccountName' => 'double_user'}
end
end
end
end