Skip to content
This repository has been archived by the owner on Apr 29, 2021. It is now read-only.

Output not captured (or returned) when using function exported from parent process #225

Closed
pawamoy opened this issue Jul 20, 2017 · 11 comments

Comments

@pawamoy
Copy link

pawamoy commented Jul 20, 2017

I was completely lost for a bit but I'm a persevering bug hunter so here is the simplified issue: if at some point in your test, you're using a function that has been exported from a parent process (in your interactive shell for example), and your test(s) fail, the output is not restored (not displayed). Screenshot below.

Here is some code to reproduce:

# tests/test_using_exported_function_in_sourced_file.bats

if exported_function; then
  # declare some variable or whatever
  a_variable="random contents"
fi

@test "should print captured output when failure" {
  echo "PRINT THIS"
  false  # always fail for demonstration purpose
}

bats tests/test_using_exported_function_in_sourced_file.bats

Running bats on this file works, even though exported_function is not defined: we end up with nice warnings before bats output. Now lets create our function in the shell and export it:

exported_function() { true; }
export -f exported_function

bats tests/test_using_exported_function_in_sourced_file.bats

Running bats again will fail (okay), but no output is printed!

screenshot - 07202017 - 06 13 06 pm

The same bug will occur no matter where the exported function is called (from a file loaded with bats' load or bash's . or source).

To prove it is really the exported function causing problem, let's define it in the test file:

# tests/test_using_exported_function_in_sourced_file.bats

exported_function() { true; }
# export -f exported_function  # same effect with or without

if exported_function; then
  # declare some variable or whatever
  a_variable="random contents"
fi

@test "should print captured output when failure" {
  echo "PRINT THIS"
  false  # always fail for demonstration purpose
}

Run bats: bats tests/test_using_exported_function_in_sourced_file.bats
Working again!

Is it a bug or am I missing something? Is it related really to bats?

@xmik
Copy link

xmik commented Jul 20, 2017

Does this help? #191 (comment)

@pawamoy
Copy link
Author

pawamoy commented Jul 20, 2017

Nope, I understand that bats is capturing output inside tests, the problem here is that it does not print it when the test fails!

@mfdj
Copy link

mfdj commented Jul 20, 2017

I tried re-producing your issue but wasn't able to.

I tweaked the script to be a little more concise:

if type -p exported_function; then
  a_variable="random contents"
fi

@test "should print captured output when failure" {
  echo "a_variable '$a_variable'"
  false  # always fail for demonstration purpose
}

I was able to get output in both cases?

screen shot 2017-07-20 at 10 16 04 am

@pawamoy
Copy link
Author

pawamoy commented Jul 20, 2017

Well you do not execute the function here. Try to remove type -p:

#!/usr/bin/env bats

if exported_function; then
  a_variable="random contents"
fi

@test "should print captured output when failure" {
  echo "a_variable '$a_variable'"
  false  # always fail for demonstration purpose
}

Just had the same problem on another machine:
capture du 2017-07-21 00-15-55

@pawamoy
Copy link
Author

pawamoy commented Jul 20, 2017

I installed bats with bpkg by the way, version 0.4.0 (sudo bpkg install -g sstephenson/bats)

@mfdj
Copy link

mfdj commented Jul 20, 2017

Good point — well I tried your variation to be double certain that the execution is the problem but was still not able to reproduce.

screen shot 2017-07-20 at 3 21 52 pm

I tested with Homebrew installed BATS and from source.
I also test with bash 3 + 4 as my login shell (I primarily use bash 4):

@pawamoy
Copy link
Author

pawamoy commented Jul 21, 2017

Hmmm... it must come from my shell environment then...

Thank you for the follow up 👍 ! I'm gonna continue the investigation and post updates here :)

@pawamoy
Copy link
Author

pawamoy commented Jul 21, 2017

Seems it happens with some (or all?) versions of Bash 4.3. I just upgraded to Bash 4.4.0 and everything works as expected (output is correctly printed). I won't investigate further to see what change from Bash 4.3 to 4.4 is responsible for the fix so I will close this issue if there are no updates the next few days! Thanks again @mfdj and @xmik

From http://sourcedigit.com/20892-bash-4-4-released-install-bash-shell-ubuntu/

sudo apt-get install build-essential
wget http://ftp.gnu.org/gnu/bash/bash-4.4.tar.gz
tar xf bash-4.4.tar.gz
cd bash-4.4
./configure
make
sudo make install

@pawamoy
Copy link
Author

pawamoy commented Jul 21, 2017

I wrote a test for this particular problem, should I send a PR?

In test/bats.bats:

@test "executing exported function does not break failing test output" {
  exported_function() { :; }
  export -f exported_function
  run bats "$FIXTURE_ROOT/exported_function.bats"
  [ $status -eq 1 ]
  [ "${lines[0]}" = "1..1" ]
  [ "${lines[1]}" = "not ok 1 failing test" ]
  [ "${lines[2]}" = "# (in test file test/fixtures/bats/exported_function.bats, line 9)" ]
  [ "${lines[3]}" = "#   \`false' failed" ]
  [ "${lines[4]}" = "# a='a is set'" ]
}

New file test/fixtures/bats/exported_function.bats:

# see issue #225

if exported_function; then
  a='a is set'
fi

@test "failing test" {
  echo "a='$a'"
  false
}

As expected, it's passing with Bash 4.4 and failing with Bash 4.3 (4.3.11(1)-release).

@pawamoy
Copy link
Author

pawamoy commented Jul 21, 2017

I ran tests with different Bash versions thanks to @aclemons' fork. Conclusion is exported_function test fails everywhere except in Bash 4.4. 🤣

Without patches: https://pastebin.com/kMUqQ3HD
With latest patches: https://pastebin.com/8J3uNkMC

  • 3.1
  • 3.2
  • 4.0
  • 4.1
  • 4.2
  • 4.3
  • 4.4

mbland added a commit to bats-core/bats-core that referenced this issue May 30, 2018
Closes #34. Incorporates the test code from that PR.

This fixes a problem whereby invoking an exported function within a test
script would result in an incorrect stack trace. It does this by using
`BATS_TEST_SOURCE` to capture a function's frame when its corresponding
`BASH_SOURCE` entry is empty.

Note: I believe the earlier problem described in sstephenson/bats#225
whereby no output was generated at all was fixed by commit
0f6dde5.

My investigation revealed that in Bash versions all the way up through
4.3.48, before this code change, the test failed as @pawamoy reported,
with the underlying test fixture producing the following output:

   not ok 1 failing test
     (in file , line 7,
      from function `bats_perform_test' in file libexec/bats-exec-test, line 339,
      from function `main' in test file , line 391)

Starting with Bash 4.4, the test passed.

The apparent reason for the failure is that the `BASH_SOURCE` entry
corresponding to the test file was getting wiped out when the exported
function was called. (Once I converged on this as a potential culprit, I
verified it by printing the contents of `BASH_SOURCE` before and after
the exported function call.) Since `bats_capture_stack_trace` depends on
matching a `BASH_SOURCE` value against `BATS_TEST_SOURCE`, when the
`BASH_SOURCE` corresponding to the test function was empty, it would
keep collecting stack frames, resulting in the output above.

As best I can currently tell,  the change accounting for the fix in Bash
4.4 is (from the Bash 4.4 ChangeLog):

  1/2/2014
  --------
  ...snip...

  2/26
  ----
  [bash-4.3 released]
  ...snip...

  11/28
  -----
  execute_cmd.c
    - struct func_array_state: new state to save state of BASH_LINENO,
      BASH_SOURCE, and FUNCNAME during function execution so it can be
      restored on a jump to top level
    - restore_funcarray_state: new function to restore func_array_state
    - execute_function: fill in func_array_state variable, add unwind-
      protect to restore it on jump to top level, call explicitly at
      end of function if subshell != 0 (may not be necessary, but safe
      for now).  Fixes bug with local assignments to FUNCNAME reported
      by Arfrever Frehtes Taifersar Arahesis <[email protected]>

  1/1/2015
  --------
  ...snip...

  7/7
  ---
  ...snip...
  [bash-4.4-alpha frozen]
@pawamoy
Copy link
Author

pawamoy commented Sep 18, 2018

This was resolved in bats-core/bats-core#87

@pawamoy pawamoy closed this as completed Sep 18, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants