aboutsummaryrefslogtreecommitdiff
path: root/src/lib/kadm5/unit-test/api.1/lock.exp
blob: 02df75bf700abcc4db50a3737455bbd65bda9f77 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# This is in api.1 so that it happens after all the tests in api.0.
# If some API function does not unlock the database then the server
# (whichs runs through all api tests) will still have it locked, and
# these tests will fail.

load_lib lib.t

api_exit

if { $RPC } {
    return
}

send_user "UNTESTED: lock: DAL changes broke locking code (see MIT RT ticket 3201)\n"
untested "lock: DAL changes broke locking code (see MIT RT ticket 3201)"
return

set locktest $LOCKTEST
set lockfile $env(K5ROOT)/kdb5.kadm5.lock

# The lock tests use the program lock-test in the unit test
# directory.  The basic idea is that lock-test can be told to acquire
# various kinds of locks and then wait for input before proceeding;
# this is necessary because otherwise we'd have no way to test locking
# interactions without a race condition.
#
# lock_test_start and lock_test_continue work together to give a crude
# form of continuations.  lock_test_continue expects a list of
# commands for lock-test (passed on the command line) and responses
# (read from stdout).  When it gets to a command of "wait",
# lock_test_continue returns, and its return value is a list of the
# arguments that it should be passed to continue processing that
# particular list of commands for that particular lock-test after
# whatever that requried lock-test to wait has been completed.
#
# lock_test is simply a wrapper for tests that do not involve wait.

proc lock_test_setup {test cmds} {
    global locktest spawn_id

    verbose "test $test"

    set cmdline ""
    foreach cmdpair $cmds {
	if {[lindex $cmdpair 0] == "eof"} {
	    break
	}
	set cmdline "$cmdline [lindex $cmdpair 0]"
    }

    verbose "spawning $locktest $cmdline"
    eval "spawn $locktest $cmdline"
}

proc lock_test {test cmds} {
    global spawn_id

    lock_test_setup $test $cmds
    set lockany [lock_test_continue $test $spawn_id 0 "" 0 $cmds]
    while {$lockany != {}} {
	set lockany [eval lock_test_continue $lockany]
    }
}

proc lock_test_start {test cmds} {
    global spawn_id

    lock_test_setup $test $cmds
    return [lock_test_continue $test $spawn_id 0 "" 0 $cmds]
}

proc lock_test_continue {test my_spawn_id test_failed fail_output cont cmds} {
    global wait_error_index wait_errno_index wait_status_index
    global spawn_id

    set spawn_id $my_spawn_id

    if {$cont == 1} {
	send -i $spawn_id "\n"
    }

    while {[llength $cmds] > 0} {
	set cmdpair [lindex $cmds 0]
	set cmds [lrange $cmds 1 end]
	set cmd [lindex $cmdpair 0]
	set output [lindex $cmdpair 1]

	verbose "test $test: command: $cmd"

	if {$cmd == "wait"} {
	    # ah, for continuations...
	    return [list $test $spawn_id $test_failed $fail_output 1 $cmds]
	} 
	if {$cmd == "eof"} {
	    set status $output
	    set output "doesnotmatchanything"
	}

	expect {
	    -i $spawn_id
	    -re "$output" { verbose "test $test: read: $output" }
	    timeout {
		set test_failed 1
		set fail_output "timeout while waiting for $output"
	    }
	    eof {
		if {$cmd != "eof"} {
		    set test_failed 1
		    set fail_output "eof while waiting for $output"
		}
	    }
	}

	if {$test_failed == 1} { break }
    }

    # In timeout cases, the process may not be dead yet.
    catch { exec kill -9 [exp_pid -i $spawn_id] } x
    set ret [wait -i $spawn_id]
    verbose "% Exit $ret" 2

    if {$test_failed == 0} {
	if {[lindex $ret $wait_error_index] == -1} {
	    set test_failed 1
	    set fail_output "wait returned error [lindex $ret $wait_errno_index]"
	} else {
	    if { [lindex $ret $wait_status_index] == $status ||
	    (($status<0) && ([lindex $ret $wait_status_index] == ($status+256))) } {
		verbose "test $test: status $status"
	    } else {
		set test_failed 1
		set fail_output "unexpected return status [lindex $ret $wait_status_index], should be $status"
	    }
	}
    }
    
    if {$test_failed == 0} {
	pass $test 
    } else { 
	fail "$test: $fail_output"
    }

    return {}
}

set lock1 [lock_test_start 1 [list \
	[list shared	"shared"] \
	[list release	"released"] \
	[list wait	""] \
	[list eof	0]]]
eval lock_test_continue $lock1

set lock2 [lock_test_start 2 [list \
	[list exclusive	exclusive] \
	[list release	released] \
	[list wait	""] \
	[list eof	0]]]
eval lock_test_continue $lock2

set lock3 [lock_test_start 5 [list \
	[list permanent	permanent] \
	[list release	released] \
	[list wait	""] \
	[list eof	0]]]
eval lock_test_continue $lock3

set lock4 [lock_test_start 4 [list \
	[list release	"Database not locked"] \
	[list wait	""] \
	[list eof	0]]]
eval lock_test_continue $lock4

set lock5 [lock_test_start 5 [list \
	[list shared	shared] \
	[list wait	""] \
	[list eof	0]]]
set lock5_1 [lock_test_start 5.1 [list \
	[list shared	shared] \
	[list wait	""] \
	[list eof	0]]]
eval lock_test_continue $lock5_1
eval lock_test_continue $lock5

set lock6 [lock_test_start 6 [list \
	[list exclusive exclusive] \
	[list wait	""] \
	[list eof	0]]]
set lock6_1 [lock_test_start 6.1 [list \
	[list shared	"Cannot lock database"] \
	[list wait	""] \
	[list eof	0]]]
eval lock_test_continue $lock6_1
eval lock_test_continue $lock6

set lock7 [lock_test_start 7 [list \
	[list shared	shared] \
	[list wait	""] \
	[list eof	0]]]
set lock7_1 [lock_test_start 7.1 [list \
	[list exclusive	"Cannot lock database"] \
	[list wait	""] \
	[list eof	0]]]
eval lock_test_continue $lock7_1
eval lock_test_continue $lock7

set lock8 [lock_test_start 8 [list \
	[list permanent	permanent] \
	[list wait	""] \
	[list release	"released" ] \
	[list wait	""] \
	[list eof	0]]]
set lock8_1 [lock_test_start 8.1 [list \
	[list "" "administration database lock file missing while opening database" ] \
	[list wait	""] \
	[list eof	1]]]
eval lock_test_continue $lock8_1
eval set lock8 \[lock_test_continue $lock8\]
eval lock_test_continue $lock8

set lock9 [lock_test_start 9 [list \
	[list exclusive exclusive] \
	[list release released] \
	[list wait	""] \
	[list exclusive	"database lock file missing while getting exclusive"] \
	[list wait	""] \
	[list eof	0]]]
set lock9_1 [lock_test_start 9.1 [list \
	[list permanent	permanent] \
	[list wait	""] \
	[list release	released] \
	[list wait	""] \
	[list eof	0]]]
eval set lock9 \[lock_test_continue $lock9\]
eval lock_test_continue $lock9
eval set lock9_1 \[lock_test_continue $lock9_1\]
eval lock_test_continue $lock9_1

if {! [file exists $lockfile]} {
    perror "lock file missing before test 10"
}
set lock10 [lock_test_start 10 [list \
	[list permanent	permanent] \
	[list wait	""] \
	[list release	released] \
	[list wait	""] \
	[list eof	0]]]
if {[file exists $lockfile]} {
    fail "test 10: lock file exists"
}
eval set lock10 \[lock_test_continue $lock10\]
eval lock_test_continue $lock10
if {[file exists $lockfile]} {
    pass "test 11: lock file exists"
} else {
    fail "test 11: lock file does not exist"
}

set lock12 [lock_test_start 12 [list \
	[list shared	shared] \
	[list wait	""] \
	[list eof	0]]]
set lock12_1 [lock_test_start 12.1 [list \
	[list "get test-pol"	retrieved] \
	[list wait	""] \
	[list eof	0]]]
eval lock_test_continue $lock12_1
eval lock_test_continue $lock12

set lock13 [lock_test_start 13 [list \
	[list "get lock13"	"Principal or policy does not exist"] \
	[list wait	""] \
	[list "get lock13"	retrieved] \
	[list wait	""] \
	[list eof	0]]]
set test13_spawn_id $spawn_id
# create_policy could call api_exit immediately when it starts up.
# If it does, and the spawn ID in $spawn_id is ours rather than its,
# it'll close our spawn ID.  So, we call api_start to give it something
# to close.
api_start
create_policy lock13
set api_spawn_id $spawn_id
set spawn_id $test13_spawn_id
eval set lock13 \[lock_test_continue $lock13\]
eval lock_test_continue $lock13
set spawn_id $api_spawn_id
delete_policy lock13