lang: Add per-test config with count maximums
Some of our special tests can only be run once per `go test` invocation. That is, using the test -count flag will cause a guaranteed failure since we depend on a global being initialized only once as part of that test. This adds a per-test config option so that a user can specify to never run a particular test more than once. This lets us continue to use the -count flag with the test suite, without it causing some tests to fail.
This commit is contained in:
@@ -22,6 +22,7 @@ package lang
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
@@ -62,6 +63,24 @@ const (
|
|||||||
runGraphviz = false // run graphviz in tests?
|
runGraphviz = false // run graphviz in tests?
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
testMutex *sync.Mutex // guards testCounter
|
||||||
|
testCounter map[string]uint // counts how many times each test ran
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
testMutex = &sync.Mutex{}
|
||||||
|
testCounter = make(map[string]uint)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigProperties are some values that are used to specify how each test runs.
|
||||||
|
type ConfigProperties struct {
|
||||||
|
|
||||||
|
// MaximumCount specifies how many times this test can run safely in a
|
||||||
|
// single iteration. If zero then this means infinite.
|
||||||
|
MaximumCount uint `json:"maximum-count"`
|
||||||
|
}
|
||||||
|
|
||||||
// TestAstFunc1 is a more advanced version which pulls code from physical dirs.
|
// TestAstFunc1 is a more advanced version which pulls code from physical dirs.
|
||||||
func TestAstFunc1(t *testing.T) {
|
func TestAstFunc1(t *testing.T) {
|
||||||
const magicError = "# err: "
|
const magicError = "# err: "
|
||||||
@@ -169,6 +188,7 @@ func TestAstFunc1(t *testing.T) {
|
|||||||
|
|
||||||
// copy files out into the test temp directory
|
// copy files out into the test temp directory
|
||||||
var testOutput []byte
|
var testOutput []byte
|
||||||
|
var testConfig []byte
|
||||||
found := false
|
found := false
|
||||||
for _, file := range archive.Files {
|
for _, file := range archive.Files {
|
||||||
if file.Name == "OUTPUT" {
|
if file.Name == "OUTPUT" {
|
||||||
@@ -176,6 +196,10 @@ func TestAstFunc1(t *testing.T) {
|
|||||||
found = true
|
found = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if file.Name == "CONFIG" {
|
||||||
|
testConfig = file.Data
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
name := filepath.Join(tmpdir, file.Name)
|
name := filepath.Join(tmpdir, file.Name)
|
||||||
dir := filepath.Dir(name)
|
dir := filepath.Dir(name)
|
||||||
@@ -189,6 +213,29 @@ func TestAstFunc1(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var c ConfigProperties // add pointer to get nil if empty
|
||||||
|
if len(testConfig) > 0 {
|
||||||
|
if err := json.Unmarshal(testConfig, &c); err != nil {
|
||||||
|
t.Errorf("err parsing txtar(%s) config: %+v", txtarFile, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if testing.Verbose() {
|
||||||
|
t.Logf("config: %+v", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
testMutex.Lock() // global
|
||||||
|
count := testCounter[t.Name()] // global
|
||||||
|
testCounter[t.Name()]++
|
||||||
|
testMutex.Unlock()
|
||||||
|
|
||||||
|
if c.MaximumCount != 0 && count >= c.MaximumCount {
|
||||||
|
if count == c.MaximumCount { // logf once
|
||||||
|
t.Logf("Skipping test after count: %d", count)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if !found { // skip missing tests
|
if !found { // skip missing tests
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -624,6 +671,7 @@ func TestAstFunc2(t *testing.T) {
|
|||||||
|
|
||||||
// copy files out into the test temp directory
|
// copy files out into the test temp directory
|
||||||
var testOutput []byte
|
var testOutput []byte
|
||||||
|
var testConfig []byte
|
||||||
found := false
|
found := false
|
||||||
for _, file := range archive.Files {
|
for _, file := range archive.Files {
|
||||||
if file.Name == "OUTPUT" {
|
if file.Name == "OUTPUT" {
|
||||||
@@ -631,6 +679,10 @@ func TestAstFunc2(t *testing.T) {
|
|||||||
found = true
|
found = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if file.Name == "CONFIG" {
|
||||||
|
testConfig = file.Data
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
name := filepath.Join(tmpdir, file.Name)
|
name := filepath.Join(tmpdir, file.Name)
|
||||||
dir := filepath.Dir(name)
|
dir := filepath.Dir(name)
|
||||||
@@ -644,6 +696,29 @@ func TestAstFunc2(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var c ConfigProperties // add pointer to get nil if empty
|
||||||
|
if len(testConfig) > 0 {
|
||||||
|
if err := json.Unmarshal(testConfig, &c); err != nil {
|
||||||
|
t.Errorf("err parsing txtar(%s) config: %+v", txtarFile, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if testing.Verbose() {
|
||||||
|
t.Logf("config: %+v", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
testMutex.Lock() // global
|
||||||
|
count := testCounter[t.Name()] // global
|
||||||
|
testCounter[t.Name()]++
|
||||||
|
testMutex.Unlock()
|
||||||
|
|
||||||
|
if c.MaximumCount != 0 && count >= c.MaximumCount {
|
||||||
|
if count == c.MaximumCount { // logf once
|
||||||
|
t.Logf("Skipping test after count: %d", count)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if !found { // skip missing tests
|
if !found { // skip missing tests
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1404,6 +1479,7 @@ func TestAstFunc3(t *testing.T) {
|
|||||||
|
|
||||||
// copy files out into the test temp directory
|
// copy files out into the test temp directory
|
||||||
var testOutput []byte
|
var testOutput []byte
|
||||||
|
var testConfig []byte
|
||||||
found := false
|
found := false
|
||||||
for _, file := range archive.Files {
|
for _, file := range archive.Files {
|
||||||
if file.Name == "OUTPUT" {
|
if file.Name == "OUTPUT" {
|
||||||
@@ -1411,6 +1487,10 @@ func TestAstFunc3(t *testing.T) {
|
|||||||
found = true
|
found = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if file.Name == "CONFIG" {
|
||||||
|
testConfig = file.Data
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
name := filepath.Join(tmpdir, file.Name)
|
name := filepath.Join(tmpdir, file.Name)
|
||||||
dir := filepath.Dir(name)
|
dir := filepath.Dir(name)
|
||||||
@@ -1424,6 +1504,29 @@ func TestAstFunc3(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var c ConfigProperties // add pointer to get nil if empty
|
||||||
|
if len(testConfig) > 0 {
|
||||||
|
if err := json.Unmarshal(testConfig, &c); err != nil {
|
||||||
|
t.Errorf("err parsing txtar(%s) config: %+v", txtarFile, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if testing.Verbose() {
|
||||||
|
t.Logf("config: %+v", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
testMutex.Lock() // global
|
||||||
|
count := testCounter[t.Name()] // global
|
||||||
|
testCounter[t.Name()]++
|
||||||
|
testMutex.Unlock()
|
||||||
|
|
||||||
|
if c.MaximumCount != 0 && count >= c.MaximumCount {
|
||||||
|
if count == c.MaximumCount { // logf once
|
||||||
|
t.Logf("Skipping test after count: %d", count)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if !found { // skip missing tests
|
if !found { // skip missing tests
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
-- CONFIG --
|
||||||
|
{
|
||||||
|
"maximum-count": 1
|
||||||
|
}
|
||||||
-- main.mcl --
|
-- main.mcl --
|
||||||
import "test"
|
import "test"
|
||||||
# one_instance_a should only produce one value, and will error if initialized twice
|
# one_instance_a should only produce one value, and will error if initialized twice
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
-- CONFIG --
|
||||||
|
{
|
||||||
|
"maximum-count": 1
|
||||||
|
}
|
||||||
-- main.mcl --
|
-- main.mcl --
|
||||||
import "test"
|
import "test"
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
-- CONFIG --
|
||||||
|
{
|
||||||
|
"maximum-count": 1
|
||||||
|
}
|
||||||
-- main.mcl --
|
-- main.mcl --
|
||||||
import "test"
|
import "test"
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
-- CONFIG --
|
||||||
|
{
|
||||||
|
"maximum-count": 1
|
||||||
|
}
|
||||||
-- main.mcl --
|
-- main.mcl --
|
||||||
import "test"
|
import "test"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user