Skip to content

Commit

Permalink
Update tests to remove race condition
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholasjackson committed Jan 11, 2024
1 parent 1400e3f commit 9def1b3
Showing 1 changed file with 43 additions and 8 deletions.
51 changes: 43 additions & 8 deletions context_lock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,28 @@ package hclconfig

import (
"fmt"
"sync"
"testing"
"time"

"github.com/hashicorp/hcl/v2"
"github.com/stretchr/testify/require"
"github.com/zclconf/go-cty/cty"
)

func TestContextLockDoesNotAllowConcurrentAccesstoContext(t *testing.T) {
a := &hcl.EvalContext{Variables: map[string]cty.Value{}}

w := sync.WaitGroup{}
w.Add(2)

go func() {
// get a lock but never unlock it
getContextLock(a)
for i := 0; i < 100; i++ {
a.Variables[fmt.Sprintf("%d", i)] = cty.StringVal("bar")
}

w.Done()
}()

go func() {
Expand All @@ -27,24 +32,41 @@ func TestContextLockDoesNotAllowConcurrentAccesstoContext(t *testing.T) {
for i := 0; i < 100; i++ {
a.Variables[fmt.Sprintf("%d", i)] = cty.StringVal("bar")
}

w.Done()
}()

done := make(chan struct{})

go func() {
w.Wait()
<-done
}()

// should never have 200 elements as the second go routine should be blocked
require.Neverf(t, func() bool {
return len(a.Variables) == 200
}, 100*time.Millisecond, 1*time.Millisecond, "a.Varibles should have 200 elements")
to := time.NewTimer(100 * time.Millisecond)
select {
case <-to.C:
t.Log("timed out waiting for wait group, test passed")
case <-done:
t.Fatal("should not have completed")
}
}

func TestContextLockAllowsConcurrentAccesstoDifferentContexts(t *testing.T) {
a := &hcl.EvalContext{Variables: map[string]cty.Value{}}
b := &hcl.EvalContext{Variables: map[string]cty.Value{}}

w := sync.WaitGroup{}
w.Add(2)

go func() {
unlock := getContextLock(a)
defer unlock()
for i := 0; i < 100; i++ {
a.Variables[fmt.Sprintf("%d", i)] = cty.StringVal("bar")
}

w.Done()
}()

go func() {
Expand All @@ -53,9 +75,22 @@ func TestContextLockAllowsConcurrentAccesstoDifferentContexts(t *testing.T) {
for i := 0; i < 100; i++ {
b.Variables[fmt.Sprintf("%d", i)] = cty.StringVal("bar")
}

w.Done()
}()

done := make(chan struct{})

go func() {
w.Wait()
done <- struct{}{}
}()

require.Eventuallyf(t, func() bool {
return len(a.Variables) == 100 && len(b.Variables) == 100
}, 100*time.Millisecond, 1*time.Millisecond, "a.Variables and b.Varibles should have 100 elements")
to := time.NewTimer(100 * time.Millisecond)
select {
case <-to.C:
t.Fatal("timed out waiting for wait group")
case <-done:
t.Log("wait group completed, test passed")
}
}

0 comments on commit 9def1b3

Please sign in to comment.