]> git.corax.cc Git - toolbox/commitdiff
test: Add test cases for sem module
authorMatthias Kruk <m@m10k.eu>
Sat, 8 Oct 2022 13:51:07 +0000 (22:51 +0900)
committerMatthias Kruk <m@m10k.eu>
Sat, 8 Oct 2022 13:51:07 +0000 (22:51 +0900)
There are currently no shellspec test cases for the sem module,
making it impossible to check if the module is working correctly.

This commit adds shellspec test cases for the public functions of
the sem module. The test cases are equivalent to the old BATS test
cases.

test/sem_spec.sh [new file with mode: 0644]

diff --git a/test/sem_spec.sh b/test/sem_spec.sh
new file mode 100644 (file)
index 0000000..f4e0a22
--- /dev/null
@@ -0,0 +1,472 @@
+#!/bin/bash
+
+. toolbox.sh
+include "sem"
+
+Describe "sem_init()"
+  It "creates a private semaphore"
+    _test_sem_init_create_private() {
+           local name
+           local path
+
+           name="$FUNCNAME.$RANDOM"
+           path=$(_sem_get_path "$name")
+
+           if [ -d "$path" ]; then
+                   return 1
+           elif ! sem_init "$name" 0; then
+                   return 2
+           elif ! [ -d "$path" ]; then
+                   return 3
+           fi
+
+           rm -rf "$path"
+           return 0
+    }
+
+    When call _test_sem_init_create_private
+    The status should equal 0
+  End
+
+  It "creates a public semaphore"
+    _test_sem_init_create_public() {
+           local name
+
+           if ! name=$(mktemp --dry-run); then
+                   return 1
+           fi
+
+           if ! sem_init "$name" 0; then
+                   return 1
+           elif ! [ -d "$name" ]; then
+                   return 2
+           fi
+
+           rm -rf "$name"
+           return 0
+    }
+
+    When call _test_sem_init_create_public
+    The status should equal 0
+  End
+
+  It "locks the waitlock if the counter is 0"
+    _test_sem_init_lock_waitlock() {
+           local name
+           local lock
+           local -i err
+
+           if ! name=$(mktemp --dry-run); then
+                   return 1
+           fi
+           lock=$(_sem_get_waitlock "$name")
+           err=0
+
+           if ! sem_init "$name" 0; then
+                   return 1
+           elif ! [ -L "$lock" ]; then
+                   err=2
+           fi
+
+           rm -rf "$name"
+           return "$err"
+    }
+
+    When call _test_sem_init_lock_waitlock
+    The status should equal 0
+  End
+
+  It "does not lock the waitlock if the counter is larger than 0"
+    _test_sem_init_unlock_waitlock() {
+           local name
+           local lock
+           local -i err
+
+           if ! name=$(mktemp --dry-run); then
+                   return 1
+           fi
+           lock=$(_sem_get_waitlock "$name")
+           err=0
+
+           if ! sem_init "$name" 1; then
+                   return 1
+           elif [ -L "$lock" ]; then
+                   err=2
+           fi
+
+           rm -rf "$name"
+           return "$err"
+    }
+
+    When call _test_sem_init_unlock_waitlock
+    The status should equal 0
+  End
+
+  It "sets the semaphore's counter"
+    _test_sem_init_set_counter() {
+           local path
+           local -i i
+           local -i err
+
+           if ! path=$(mktemp --directory); then
+                   return 1
+           fi
+           err=0
+
+           for (( i = 0; i < 8; i++ )); do
+                   local name
+                   local counter
+                   local value
+
+                   name="$path/sem$i"
+                   counter=$(_sem_get_counter "$name")
+
+                   if ! sem_init "$name" "$i"; then
+                           (( err++ ))
+                           continue
+                   fi
+
+                   value=$(< "$counter")
+                   if (( value != i )); then
+                           (( err++ ))
+                   fi
+           done
+
+           rm -rf "$path"
+           return "$err"
+    }
+
+    When call _test_sem_init_set_counter
+    The status should equal 0
+  End
+
+  It "sets the ownerlock"
+    _test_sem_init_set_ownerlock() {
+           local sem
+           local lock
+
+           local -i err
+
+           if ! sem=$(mktemp --dry-run); then
+                   return 1
+           elif ! sem_init "$sem" 0; then
+                   return 2
+           fi
+
+           err=0
+           lock=$(_sem_get_owner "$sem")
+
+           if ! [ -L "$lock" ]; then
+                   err=1
+           fi
+
+           rm -rf "$sem"
+           return "$err"
+    }
+
+    When call _test_sem_init_set_ownerlock
+    The status should equal 0
+  End
+
+  It "makes the current process the owner of the semaphore"
+    _test_sem_init_owner_curproc() {
+           local sem
+           local lock
+           local -i owner
+           local -i err
+
+           if ! sem=$(mktemp --dry-run); then
+                   return 1
+           elif ! sem_init "$sem" 0; then
+                   return 2
+           fi
+
+           err=0
+           lock=$(_sem_get_owner "$sem")
+
+           if ! owner=$(readlink "$lock"); then
+                   err=3
+           elif (( owner != $$ )); then
+                   err=4
+           fi
+
+           rm -rf "$sem"
+           return "$err"
+    }
+
+    When call _test_sem_init_owner_curproc
+    The status should equal 0
+  End
+
+  It "fails if the counter value was not passed"
+    When call sem_init "/tmp/dontcare.$RANDOM"
+    The status should not equal 0
+  End
+
+  It "fails if the counter value is negative"
+    When call sem_init "/tmp/dontcare.$RANDOM" -1
+    The status should not equal 0
+  End
+
+  It "fails if the counter value is not numeric"
+    When call sem_init "/tmp/dontcare.$RANDOM" "test"
+    The status should not equal 0
+  End
+
+  It "does not allocate a semaphore if the function failed"
+    When call sem_init "/tmp/dontcare"
+    The status should not equal 0
+    The path "/tmp/dontcare" should not exist
+  End
+End
+
+Describe "sem_destroy()"
+  It "removes a semaphore from the file system"
+    _test_sem_destroy_removes_semaphore() {
+           local sem
+           local -i err
+
+           err=0
+
+           if ! sem=$(mktemp --dry-run); then
+                   return 1
+           elif ! sem_init "$sem" 0; then
+                   return 2
+           elif ! sem_destroy "$sem"; then
+                   err=3
+           elif [ -e "$sem" ]; then
+                   err=4
+                   rm -rf "$sem"
+           fi
+
+           return "$err"
+    }
+    When call _test_sem_destroy_removes_semaphore
+    The status should equal 0
+  End
+
+  It "does not destroy another process's semaphore"
+    _test_sem_destroy_foreign_semaphore() {
+           local sem
+           local -i err
+
+           err=0
+
+           if ! sem=$(mktemp --dry-run); then
+                   return 1
+           elif ! bash -c ". toolbox.sh; include sem; sem_init \"$sem\" 0"; then
+                   return 2
+           fi
+
+           if sem_destroy "$sem"; then
+                   err=3
+           fi
+
+           rm -rf "$sem"
+           return "$err"
+    }
+    When call _test_sem_destroy_foreign_semaphore
+    The status should equal 0
+  End
+End
+
+Describe "sem_post()"
+  It "increases the counter by one"
+    _test_sem_post_increase() {
+           local sem
+           local counter
+           local -i value
+           local -i err
+
+           if ! sem=$(mktemp --dry-run); then
+                   return 1
+           elif ! sem_init "$sem" 0; then
+                   return 2
+           fi
+
+           err=0
+           counter=$(_sem_get_counter "$sem")
+
+           if ! sem_post "$sem"; then
+                   err=3
+           elif ! value=$(< "$counter"); then
+                   err=4
+           elif (( value != 1 )); then
+                   err=5
+           fi
+
+           rm -rf "$sem"
+           return "$err"
+    }
+
+    When call _test_sem_post_increase
+    The status should equal 0
+  End
+
+  It "wakes up a blocked call to sem_wait()"
+    _test_sem_post_wake_up_sem_wait() {
+           local sem
+           local -i timeout
+           local -i child_pid
+           local -i err
+
+           err=0
+           timeout=10
+
+           if ! sem=$(mktemp --dry-run); then
+                   return 1
+           elif ! sem_init "$sem" 0; then
+                   return 2
+           fi
+
+           ( sem_wait "$sem" ) &
+           child_pid="$!"
+
+           sem_post "$sem"
+
+           while (( timeout > 0 )) &&
+                 kill -0 "$child_pid" &> /dev/null; do
+                   sleep 1
+                   (( timeout-- ))
+           done
+
+           if (( timeout == 0 )); then
+                   err=3
+                   kill "$child_pid"
+           fi
+
+           rm -rf "$sem"
+           return "$err"
+    }
+
+    When call _test_sem_post_wake_up_sem_wait
+    The status should equal 0
+  End
+End
+
+Describe "sem_wait()"
+  It "decreases the counter by one"
+    _test_sem_wait_decrease() {
+           local sem
+           local counter
+           local -i value
+           local -i err
+
+           if ! sem=$(mktemp --dry-run); then
+                   return 1
+           elif ! sem_init "$sem" 1; then
+                   return 2
+           fi
+
+           err=0
+           counter=$(_sem_get_counter "$sem")
+
+           if ! sem_wait "$sem"; then
+                   err=3
+           elif ! value=$(< "$counter"); then
+                   err=4
+           elif (( value != 0 )); then
+                   err=5
+           fi
+
+           rm -rf "$sem"
+           return "$err"
+    }
+
+    When call _test_sem_wait_decrease
+    The status should equal 0
+  End
+
+  It "locks the waitlock if the counter is 1"
+    _test_sem_wait_lock_waitlock() {
+           local sem
+           local lock
+           local -i err
+
+           if ! sem=$(mktemp --dry-run); then
+                   return 1
+           elif ! sem_init "$sem" 1; then
+                   return 2
+           fi
+
+           err=0
+           lock=$(_sem_get_waitlock "$sem")
+
+           if ! sem_wait "$sem"; then
+                   err=3
+           elif ! [ -L "$lock" ]; then
+                   err=4
+           fi
+
+           rm -rf "$sem"
+           return "$err"
+    }
+
+    When call _test_sem_wait_lock_waitlock
+    The status should equal 0
+  End
+
+  It "releases the waitlock if the counter is greater than 1"
+    _test_sem_wait_unlock_waitlock() {
+           local sem
+           local lock
+           local -i err
+
+           if ! sem=$(mktemp --dry-run); then
+                   return 1
+           elif ! sem_init "$sem" 2; then
+                   return 2
+           fi
+
+           err=0
+           lock=$(_sem_get_waitlock "$sem")
+
+           if ! sem_wait "$sem"; then
+                   err=3
+           elif [ -L "$lock" ]; then
+                   err=4
+           fi
+
+           rm -rf "$sem"
+           return "$err"
+    }
+
+    When call _test_sem_wait_unlock_waitlock
+    The status should equal 0
+  End
+End
+
+Describe "sem_peek()"
+  It "returns the counter of a semaphore"
+    _test_sem_peek_returns_counter() {
+           local sem
+           local -i i
+           local -i err
+
+           err=0
+
+           if ! sem=$(mktemp --dry-run); then
+                   return 1
+           elif ! sem_init "$sem" 0; then
+                   return 2
+           fi
+
+           for (( i = 0; i < 16; i++ )); do
+                   local -i counter
+
+                   counter=$(sem_peek "$sem")
+                   if (( counter != i )); then
+                           err=3
+                   fi
+
+                   sem_post "$sem"
+           done
+
+           rm -rf "$sem"
+           return "$err"
+    }
+
+    When call _test_sem_peek_returns_counter
+    The status should equal 0
+  End
+End