Home > Software engineering >  unit test bash script function which deletes files older than certain number of days
unit test bash script function which deletes files older than certain number of days

Time:05-22

I don't have much experience with bash/shell scripting and just recently started writing some bash scripts with unit tests using Bats framework or libraries. Currently writing a script which needs to delete the files older than certain number of days. Below is the function.

function deleteFilesOlderThan() {
 echo "Deleting files older than $1 days"
 eval "find ./test-files -mtime  $1 -exec rm {} \;"
}

Is it possible to unit test the above function as it has complex command? If it is not possible can we rewrite the above function some other way so that it is unit testable. Please advise.

CodePudding user response:

From my perspective, you are asking three separate questions:

  1. Is my code any good?
  2. How do I write test in general for BASH
  3. How do I test this specific code?

As that sounds more like a request for code review, it might be better suited to https://codereview.stackexchange.com/ but I'll answer here anyway...

The command isn't really that complex. But even if it were, you'd be testing the side-effect of the code, not the code itself. So complexity in the code doesn't even really matter...

Anyway, a test would look something like this:

@test "deleteFilesOlderThan deletes files" {
  # Arrange
  touch -t 123412312345 ./test-files/test.txt

  # Act
  deleteFilesOlderThan 1000

  # Assert
  [ ! -f ./test-files/test.txt ]
}

You could add more tests, for instance checking the output using assert_output, and checking that newer files do not get deleted.

The code can be tested without being rewritten but there are some potetial problems in the code:

  • As state in the comments, the eval is not really needed. The find command can run fine as-is, without being wrapped in an eval.

  • There are no checks. None. At all. You might want to at least check that $1 is actually provided. You could also check whether it is an integer or not.

  • You could check that test-files actually exists

  • The test-files directory is hard-coded. I would make that a parameter of the function. That way it can be provided with a different path for the test thanm that used for real.

These changes could look something like this:

function deleteFilesOlderThan() {
  local days="${1:?Two parameters required: <days> <path>}"
  local path="${2:?Two parameters required: <days> <path>}"
  
  if [[ -n ${days} && ${days} = *[!0123456789]* ]]; then
    echo "ERROR: Given days '${days}' is not an integer" >&2
  elif [[ ! -d "${path}" ]]; then
    echo "ERROR: Given path '${path}' is not a directory" >&2  
  else
    echo "Deleting files older than ${1} days in ${path}"

    find "${path}" -mtime " ${1}" -exec rm {} \;
  fi
}

Of course, now that there is more code, there should also be more tests. I'll leave that as an exercise for the reader.


If you are not already familiar with it, you might want to check out shellcheck. It will warn you if you write any code that might cause problems.

You might also want to look at shfmt (from the mvdan.cc/sh package) to formats shell script.

  • Related