I want to tell you a little story about what happened to me a few days ago. I went to the office and a colleague of mine was not very happy. This is strange because I work for a very nice company.. What happened? I asked him what was wrong. It turned out that he updated a lot of dependencies and some code for a certain service. And now the SonarQube reporting was not working anymore with a very strange message: HTTP Error 502 Bad gateway..

I decided to help him, because we don’t work alone and especially when you’re stuck (and frustrated) at something it’s best to include other human beings.

Since there we’re already several commits done I’ve decided to use git bisect to find the bug-introducing commit.

I’ve noticed that it was new to my colleague so let’s write a blog post about it.

Prerequisites

In order to follow the instructions, you need the following things:

Rust example

The rust-example is very simple. It’s a rust library with four functions namely: add, substract, multiply and division. By no means this should ever be used in real systems, this repo only exists as example for this blog post. It has 9 commits.

$ git log --pretty=format:"%h - %an, %ad : %s"
4d7f719 - Jeroen Knoops, Sun Aug 12 17:10:07 2018 +0200 : Adds link to blog post on git bisect
380d12e - Jeroen Knoops, Sun Aug 12 17:09:04 2018 +0200 : Refactors tests in seperate directory
1ae37e1 - Jeroen Knoops, Sun Aug 12 17:07:32 2018 +0200 : Adds edge cases for division
0580aec - Jeroen Knoops, Sun Aug 12 17:06:41 2018 +0200 : Adds information on how to run tests and create the documentation
d619b4d - Jeroen Knoops, Sun Aug 12 17:04:50 2018 +0200 : Adds function 'division'
abc4c40 - Jeroen Knoops, Sun Aug 12 17:03:29 2018 +0200 : Adds function 'multiply' with a runnable example in the documentation
2a5a057 - Jeroen Knoops, Sun Aug 12 17:01:27 2018 +0200 : Adds readme.md
3d75d3d - Jeroen Knoops, Sun Aug 12 16:59:58 2018 +0200 : Adds travis-ci pipeline
030b725 - Jeroen Knoops, Sun Aug 12 16:58:49 2018 +0200 : Adds functions 'add' and 'substract'

It starts with adding two functions, adding travis-ci, add some documentation, more functions, some refactoring… everything you expect from a ‘real’ project.

Of course it has some tests and I’ve tested everything manually before I commit… But for some reason at the end, the substract function is not working anymore.. Whoops.. I’ve tested it manually, but for some reason I’ve forgot to add a test for it..

Let’s create a test

We’re creating a test in /tests/bug.rs to show the bug. We will use this test to check in which commit the bug was introduced.

extern crate example;
use example::*;

#[test]
fn test_substract() {
      assert_eq!(substract(8, 2), 6);
}

Now try to run this test in isolation with the following command:

cargo test --test bug

Test on master should fail:

Test on first commit (030b725) should not fail:

Somewhere in between it start not working anymore.. Let’s use git bisect to find that.

Git bisect

We go back to the master with the added test.

We start the bisect procedure:

git bisect start

We tell bisect that the current version is bad:

git bisect bad

Now we tell bisect the commit of a known working version:

git bisect good 030b72500f08774b685c59c3e5ddd64afce432f1

We tell bisect to look when the bug appears:

git bisect run cargo test --test bug

After the test, reset the HEAD to the first place.

git bisect reset

Let’s see this in action:

What did just happen?

 git bisect run cargo test --test bug
running cargo test --test bug
   Compiling example v0.1.0 (file:///Users/software-concepts/workspace/jeroen.knoops/rust-example)
    Finished dev [unoptimized + debuginfo] target(s) in 0.58 secs
     Running target/debug/deps/bug-6262d8198d8b39aa

running 1 test
test test_substract ... FAILED

failures:

---- test_substract stdout ----
	thread 'test_substract' panicked at 'assertion failed: `(left == right)`
  left: `16`,
 right: `6`', tests/bug.rs:6:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.


failures:
    test_substract

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out

error: test failed, to rerun pass '--test bug'
Bisecting: 1 revision left to test after this (roughly 1 step)
[2a5a0578f44883d360287fc771c9d1dd7cff4cd6] Adds readme.md
running cargo test --test bug
   Compiling example v0.1.0 (file:///Users/software-concepts/workspace/jeroen.knoops/rust-example)
    Finished dev [unoptimized + debuginfo] target(s) in 0.59 secs
     Running target/debug/deps/bug-6262d8198d8b39aa

running 1 test
test test_substract ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

Bisecting: 0 revisions left to test after this (roughly 0 steps)
[abc4c40d4a06711bab5039a2896db3f67d8ddd0e] Adds function 'multiply' with a runnable example in the documentation
running cargo test --test bug
   Compiling example v0.1.0 (file:///Users/software-concepts/workspace/jeroen.knoops/rust-example)
    Finished dev [unoptimized + debuginfo] target(s) in 0.58 secs
     Running target/debug/deps/bug-6262d8198d8b39aa

running 1 test
test test_substract ... FAILED

failures:

---- test_substract stdout ----
	thread 'test_substract' panicked at 'assertion failed: `(left == right)`
  left: `16`,
 right: `6`', tests/bug.rs:6:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.


failures:
    test_substract

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out

error: test failed, to rerun pass '--test bug'
abc4c40d4a06711bab5039a2896db3f67d8ddd0e is the first bad commit
commit abc4c40d4a06711bab5039a2896db3f67d8ddd0e
Author: Jeroen Knoops <jeroen.knoops@gmail.com>
Date:   Sun Aug 12 17:03:29 2018 +0200

    Adds function 'multiply' with a runnable example in the documentation

:040000 040000 27cde4ec60027b8faffb1e97f3cb42022e80187b 34e8c57493a1b137f34fe45bf5ec555888ad8c3b M	src
bisect run success
[I]  ~  workspace  jeroen.knoops  rust-example  ⚓ abc4c40  ❓  $  git log
commit abc4c40d4a06711bab5039a2896db3f67d8ddd0e (HEAD, refs/bisect/bad)
Author: Jeroen Knoops <jeroen.knoops@gmail.com>
Date:   Sun Aug 12 17:03:29 2018 +0200

    Adds function 'multiply' with a runnable example in the documentation

commit 2a5a0578f44883d360287fc771c9d1dd7cff4cd6 (refs/bisect/good-2a5a0578f44883d360287fc771c9d1dd7cff4cd6)
Author: Jeroen Knoops <jeroen.knoops@gmail.com>
Date:   Sun Aug 12 17:01:27 2018 +0200

    Adds readme.md

commit 3d75d3da596b4fced7c4e91b17c20b2b61d2c8c5
Author: Jeroen Knoops <jeroen.knoops@gmail.com>
Date:   Sun Aug 12 16:59:58 2018 +0200

    Adds travis-ci pipeline

commit 030b72500f08774b685c59c3e5ddd64afce432f1 (refs/bisect/good-030b72500f08774b685c59c3e5ddd64afce432f1)
Author: Jeroen Knoops <jeroen.knoops@gmail.com>
Date:   Sun Aug 12 16:58:49 2018 +0200

    Adds functions 'add' and 'substract'

Commit which introduced the bug:

https://github.com/JeroenKnoops/rust-example/commit/abc4c40d4a06711bab5039a2896db3f67d8ddd0e

Created Refs: gitx

Results

When implementing multiply, I’ve accidentally broken the substract function. Git bisect will also add refs so you can which commits have been tested.

The correct implementation would be:

pub fn substract(a: i32, b: i32) -> i32 {
    a - b
}

The test we’ve written to find the bug can be renamed and also added to prevent this from happening again.

Conclusion

This was a very simple test / bug to find. By doing a git blame on the line, we would found the same error, but this is not always the case. Imagine a website which overtime became very slow. Try to create a test which measures the performance of a certain page. This test should fail when the performance is below a certain threshold. This can be a complete end-to-end test. Now you will find the exact place where the introduction of a small stupid javascript library caused a big performance problem.