summaryrefslogtreecommitdiff
path: root/tests/daemon.at
blob: d7981f9d23a60dcccd97ca1b53aa482908f4f0ef (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
AT_BANNER([daemon unit tests - C])

OVS_START_SHELL_HELPERS
# check_process_name PID NAME
#
# On Linux, make sure that the name of process PID is NAME.
# (On other systems, don't bother.)
if test -e /proc/$$/comm; then
    check_process_name() {
        # In case we're building with shared libraries enabled, strip
        # off libtool's lt- prefix.
        AT_CHECK_UNQUOTED([sed 's/lt-//' /proc/$1/comm], [0], [$2
])
    }
else
    check_process_name() {
        :
    }
fi

# check_ancestors PID PARENT [GRANDPARENT...]
check_ancestors() {
    echo "checking ancestry: $*"
    local child=$1; shift
    AT_CHECK([kill -0 $child])
    while test $# != 0; do
        local parent=$1; shift
        AT_CHECK([parent_pid $child], [0], [stdout])
        actual_parent=$(cat stdout)
        if test $parent = 1; then
            # Traditionally, if a parent's process exits, the process's new
            # parent is pid 1 (init) but this is not always the case these
            # days.  Instead, if the parent process should be pid 1, be
            # satisfied if the parent process is different from our own pid.
            if test $actual_parent = $$; then
                echo "parent of pid $child is this shell ($$) but should not be"
                AT_FAIL_IF([:])
            fi
        elif test $parent != $actual_parent; then
            echo "parent of pid $child is $actual_parent but should be $parent"
            AT_FAIL_IF([:])
        fi
        child=$parent
    done
}
OVS_END_SHELL_HELPERS

AT_SETUP([daemon])
AT_SKIP_IF([test "$IS_WIN32" = "yes"])

dnl OVS_SKIP_NON_ADMIN_WIN()
dnl
dnl Checks if we have enough rights to create a service
m4_define([OVS_SKIP_NON_ADMIN_WIN],
  [
   AT_SKIP_IF([net session; test $? -ne 0])
   ])

# Start the daemon and wait for the pidfile to get created
# and that its contents are the correct pid.
on_exit 'kill $(cat *.pid)'
AT_CHECK([ovsdb-server --pidfile --no-db 2>/dev/null & echo $!], [0], [stdout])
expected_pid=$(cat stdout)

OVS_WAIT_UNTIL([test -s ovsdb-server.pid])
pid=$(cat ovsdb-server.pid)

AT_CHECK([test $pid = $expected_pid])
AT_CHECK([kill -0 $pid])

# Kill the daemon and make sure that the pidfile gets deleted.
AT_CHECK([kill $pid])
OVS_WAIT_WHILE([kill -0 $pid])

AT_CHECK([test ! -e ovsdb-server.pid])
AT_CLEANUP

AT_SETUP([daemon --monitor])
AT_SKIP_IF([test "$IS_WIN32" = "yes"])

# This test intentionally causes SIGSEGV, so make Address Sanitizer ignore it.
ASAN_OPTIONS=$ASAN_OPTIONS:handle_segv=0; export ASAN_OPTIONS

# Skip it if UB Sanitizer is being used.  There's no way to disable the
# SEGV check at runtime.
AT_SKIP_IF([test $TESTS_WITH_UBSAN = yes])

# Start the daemon and wait for the pidfile to get created.
on_exit 'kill $(cat *.pid)'
AT_CHECK([ovsdb-server --monitor --pidfile --no-db 2>/dev/null & echo $!],
  [0], [stdout])
parent=$(cat stdout)
OVS_WAIT_UNTIL([test -s ovsdb-server.pid])

# Check that the pidfile names a running process,
# and that the parent process of that process is our child process,
# and that (with a Linux kernel) the child's process name is correct.
child=$(cat ovsdb-server.pid)
check_ancestors $child $parent
check_process_name $child ovsdb-server

# Avoid a race between pidfile creation and notifying the parent,
# which can easily trigger if ovsdb-server is slow (e.g. due to valgrind).
OVS_WAIT_UNTIL([ovs-appctl -t ovsdb-server version])

# Kill the daemon process, making it look like a segfault,
# and wait for a new child process to get spawned.
AT_CHECK([kill -SEGV $child], [0], [], [ignore])
OVS_WAIT_WHILE([kill -0 $child])
OVS_WAIT_UNTIL([test -s ovsdb-server.pid && test $(cat ovsdb-server.pid) != $child])

# Check that the pidfile names a running process,
# and that the parent process of that process is our child process.
child2=$(cat ovsdb-server.pid)
check_ancestors $child2 $parent
check_process_name $child2 ovsdb-server

# Kill the daemon process with SIGTERM, and wait for the daemon
# and the monitor processes to go away and the pidfile to get deleted.
AT_CHECK([kill $child2])
OVS_WAIT_WHILE([kill -0 $parent || kill -0 $child2 || test -e ovsdb-server.pid])
AT_CLEANUP


AT_SETUP([daemon --detach])

# Start the daemon and make sure that the pidfile exists immediately.
# We don't wait for the pidfile to get created because the daemon is
# supposed to do so before the parent exits.
AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --no-db], [0])
AT_CHECK([test -s ovsdb-server.pid])
child=$(cat ovsdb-server.pid)
AT_CHECK([kill -0 $child])

# Kill the daemon and make sure that the pidfile gets deleted.
if test "$IS_WIN32" = "yes"; then
  # When a 'kill pid' is done on windows (through 'taskkill //F'),
  # pidfiles are not deleted (because it is force kill), so use
  # 'ovs-appctl exit' instead
  OVS_APP_EXIT_AND_WAIT([ovsdb-server])
else
  kill $child
fi
OVS_WAIT_WHILE([kill -0 $child])
AT_CHECK([test ! -e ovsdb-server.pid])

AT_CLEANUP


AT_SETUP([daemon --detach --monitor])
AT_SKIP_IF([test "$IS_WIN32" = "yes"])

# This test intentionally causes SIGSEGV, so make Address Sanitizer ignore it.
ASAN_OPTIONS=$ASAN_OPTIONS:handle_segv=0; export ASAN_OPTIONS

# Skip it if UB Sanitizer is being used.  There's no way to disable the
# SEGV check at runtime.
AT_SKIP_IF([test $TESTS_WITH_UBSAN = yes])

on_exit 'kill $(cat *.pid)'

# Start the daemon and make sure that the pidfile exists immediately.
# We don't wait for the pidfile to get created because the daemon is
# supposed to do so before the parent exits.
AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --monitor --no-db])
AT_CHECK([test -s ovsdb-server.pid])
child=$(cat ovsdb-server.pid)

# Check process naming and ancestry.
monitor=$(parent_pid $child)
check_process_name $child ovsdb-server
check_ancestors $child $monitor 1

# Kill the daemon process, making it look like a segfault,
# and wait for a new daemon process to get spawned.
AT_CHECK([kill -SEGV $child], [0])
OVS_WAIT_WHILE([kill -0 $child])
OVS_WAIT_UNTIL([test -s ovsdb-server.pid && test `cat ovsdb-server.pid` != $child])
child2=$(cat ovsdb-server.pid)

# Check process naming and ancestry.
check_process_name $child2 ovsdb-server
check_ancestors $child2 $monitor 1

# Kill the daemon process with SIGTERM, and wait for the daemon
# and the monitor processes to go away and the pidfile to get deleted.
AT_CHECK([kill $child2])
OVS_WAIT_WHILE(
  [kill -0 $monitor || kill -0 $child2 || test -e ovsdb-server.pid])
AT_CLEANUP


AT_SETUP([daemon --detach startup errors])
AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --unixctl=nonexistent/unixctl --no-db], [1], [], [stderr])
AT_CHECK([grep 'could not initialize control socket' stderr],
  [0], [ignore])
AT_CHECK([test ! -e ovsdb-server.pid])
AT_CLEANUP


AT_SETUP([daemon --detach --monitor startup errors])
AT_SKIP_IF([test "$IS_WIN32" = "yes"])
AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --monitor --unixctl=nonexistent/unixctl --no-db], [1], [], [stderr])
AT_CHECK([grep 'could not initialize control socket' stderr],
  [0], [ignore])
AT_CHECK([test ! -e ovsdb-server.pid])
AT_CLEANUP


AT_SETUP([daemon --service])
AT_KEYWORDS([windows-service])
AT_SKIP_IF([test "$IS_WIN32" != "yes"])
OVS_SKIP_NON_ADMIN_WIN
AT_SKIP_IF([sc qc ovsdb-server])

AT_CAPTURE_FILE([pid])
# To create a Windows service, we need the absolute path for the executable.
abs_path="$(cd $(dirname `which ovsdb-server`); pwd -W; cd $OLDPWD)"

AT_CHECK([sc create ovsdb-server binpath="$abs_path/ovsdb-server --no-db --log-file=`pwd`/ovsdb-server.log --pidfile=`pwd`/ovsdb-server.pid --unixctl=`pwd`/ovsdb-server.ctl --remote=punix:`pwd`/socket --service"],
[0], [[[SC]] CreateService SUCCESS
])

AT_CHECK([sc start ovsdb-server], [0], [ignore], [ignore], [sc delete ovsdb-server])
OVS_WAIT_UNTIL([test -s ovsdb-server.pid])
OVS_WAIT_UNTIL([sc query ovsdb-server | grep STATE | grep RUNNING > /dev/null 2>&1])
AT_CHECK([kill -0 `cat ovsdb-server.pid`], [0], [ignore])
AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/list-dbs], [0],
[_Server
])
AT_CHECK([sc stop ovsdb-server], [0], [ignore])
OVS_WAIT_UNTIL([test ! -s ovsdb-server.pid])
OVS_WAIT_UNTIL([sc query ovsdb-server | grep STATE | grep STOPPED > /dev/null 2>&1])
AT_CHECK([sc delete ovsdb-server], [0], [[[SC]] DeleteService SUCCESS
])
AT_CLEANUP