2

I'm using bats to test some bash scripts. In one of the test, I need to mount a generated iso disk image and make assertions on its content.

When I try to unmount the disk image right after the test, I get a Device or resource busy error unless I insert a sleep-time before the unmount operation.

The script looks like this:

setup() {
  load 'test_helper/bats-support/load'
  load 'test_helper/bats-assert/load'
}

teardown() {
  if [ -f "$BATS_TEST_TMPDIR"/mnt/my_file.txt ]; then
    sleep 1
    fusermount -u "$BATS_TEST_TMPDIR"/mnt
  fi
}

@test 'check iso content' {
  generate_iso "$BATS_TEST_TMPDIR"/my_iso.iso
  mkdir "$BATS_TEST_TMPDIR"/mnt
  fuseiso "$BATS_TEST_TMPDIR"/my_iso.iso "$BATS_TEST_TMPDIR"/mnt
  assert grep 'A required string' < "$BATS_TEST_TMPDIR"/mnt/my_file.txt
}

This somehow works but I'm not 100% happy with the arbitrary sleep-time that may or may not be sufficient for the unmount to be successful depending on how soon the file is closed.

I tried to kill the process accessing the mounted filesystem by using fuser -mk "$BATS_TEST_TMPDIR"/mnt instead of sleeping but this would eventually kill the process running the tests.

Is there any way I can avoid the arbitrary sleep-time? Can I ask the OS to wait for the file to be closed before proceeding? Any help would be greatly appreciated.

Jacques Gaudin
  • 15,779
  • 10
  • 54
  • 75
  • So _who_ is using the disc? See `lsof` `fuser` `I tried to kill` so what is that process doing? What process is it? Why now wait for it to finish? – KamilCuk Jan 14 '22 at 11:06
  • It's the script itself I reckon. When I kill the process with `fuser -vmk` I get `"$BATS_LIBEXEC"/bats-core/bats-exec-file: line 274: 65140 Killed "$BATS_LIBEXEC/bats-exec-test" "${flags[@]}" "$filename" "$test_name" "$test_number_in_suite" "$test_number_in_file"` – Jacques Gaudin Jan 14 '22 at 11:12
  • If it's a subprocess which is running. Couldn't you `wait` for it to finish? Maybe look into this [post](https://stackoverflow.com/a/356154/7558856). – eDonkey Jan 14 '22 at 11:13
  • @eDonkey Interesting idea, although I want to unmount before the script finishes. If I understand correctly, the script can't wait for itself to finish. Isn't it a problem? – Jacques Gaudin Jan 14 '22 at 11:23
  • @eDonkey I just checked and `assert` doesn't run the command in a sub-shell. – Jacques Gaudin Jan 14 '22 at 11:31
  • Just a thought - i don't have any experience with "bats" - but wouldn't instead of `assert`, `@test` create a *child-/subprocess*? Because that's the case with a lot of testing tools. Then you could `wait` for the test to finish and unmount the disk. – eDonkey Jan 14 '22 at 12:25
  • 1
    @eDonkey I think `@test` creates a subprocess indeed although I'm not sure how to get access to its PID. I can't figure out how/when the subprocess is created within bats source either. – Jacques Gaudin Jan 14 '22 at 16:37

1 Answers1

1

That was actually really easy, I just needed to close the file in the last grep (note the <&-):

assert grep 'A required string' <&- "$BATS_TEST_TMPDIR"/mnt/my_file.txt

teardown() {
  if [ -f "$BATS_TEST_TMPDIR"/mnt/my_file.txt ]; then
    fusermount -u "$BATS_TEST_TMPDIR"/mnt
  fi
}

@test 'check iso content' {
  generate_iso "$BATS_TEST_TMPDIR"/my_iso.iso
  mkdir "$BATS_TEST_TMPDIR"/mnt
  fuseiso "$BATS_TEST_TMPDIR"/my_iso.iso "$BATS_TEST_TMPDIR"/mnt
  assert grep 'A required string' <&- "$BATS_TEST_TMPDIR"/mnt/my_file.txt
}
Jacques Gaudin
  • 15,779
  • 10
  • 54
  • 75