-2

I'm trying to test the following method in a file (heavily edited to make a small sample):

app.go

var fruit = ""

func check(input string) bool {
    if input == "1" {
        go func() {
            fruit = "BANANA"
            time.Sleep(1 * time.Second)
        }()
        return true
    } else if fruit == "BANANA" {
        return true
    } 
    return false
}

app_test.go

func TestInputs(t *testing.T) {
    res := check("1")
    res = check("2")
    if res != true {
        t.Errorf("got: %t, want: %t", res, true)
    }
}

Essentially, I'd like res = check("2") to return true, since fruit was set to BANANA in the previous call. Is this possible? The Go Routine shouldn't matter too much here - however it is part of my program's functionality and I'm not sure if it affects testing.

1 Answers1

1

You're using time.Sleep() before changing fruit, yet you don't use anything in your test to wait that.

In general time.Sleep() is not a synchronization tool. Even if you'd insert a 2-second sleep in your test before calling check() again, that's still a data race: one goroutine modifies fruit, and another reads it without synchronization. This is undefined behavior.

Use proper synchronization primitives: that is: locks, channels, waitgroups etc.

icza
  • 389,944
  • 63
  • 907
  • 827
  • I'd like there to be a data race, as strange as it sounds. – seriouslyg0e Jul 13 '21 at 08:42
  • 2
    _"I'd like there to be a data race"_ No, you don't. Data races are undefined behavior. You can't assume anything when there's a data race in your app. There are only guarantees when there isn't. You can't reason about a racy app. If you just want to show there's race, run it with the `-race` option. – icza Jul 13 '21 at 08:43
  • "Undefined behavior" does not exclude the case where you get what you would expect if there would be no race. There is no guarantee you will always get what you expect, that's what undefined means. – icza Jul 13 '21 at 08:55
  • The problem is (as icza has already said) that you literally *can't* test for a data race without adding additional requirements beyond what the language itself imposes. This means you cannot write your test in pure Go. Consider writing the test portion in assembler, where you can make use of particular CPU properties. – torek Jul 13 '21 at 08:57
  • Also: when there's data race in your app, you're not exploiting any vulnerability. That's simply a faulty app. There is no guaranteed security in a racy app, there is no guaranteed _anything_ in a racy app. – icza Jul 13 '21 at 09:01
  • @icza I beg to differ. Race conditions _can_ be exploited to undermine the security of a Go app: https://github.com/netanel01/ctf-writeups/blob/master/googlectf/2019/pwn_gomium/README.md – jub0bs Jul 13 '21 at 09:15
  • 1
    @jub0bs Maybe my wording wasn't correct. What I mean is you can't expect any security from a racy app. – icza Jul 13 '21 at 09:18