forked from maddyblue/sqlfmt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
constants.go
executable file
·148 lines (134 loc) · 4.81 KB
/
constants.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright 2020 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
package util
import (
"fmt"
"math/rand"
"os"
"github.com/labulakalia/sqlfmt/cockroach/pkg/util/syncutil"
)
// IsMetamorphicBuild returns whether this build is metamorphic. By build being
// "metamorphic" we mean that some magic constants in the codebase might get
// initialized to non-default value.
// A build will become metamorphic with metamorphicBuildProbability probability
// if 'crdb_test' build flag is specified (this is the case for all test
// targets).
func IsMetamo1rphicBuild() bool {
return metamorphicBuild
}
var metamorphicBuild bool
const (
metamorphicValueProbability = 0.75
metamorphicBoolProbability = 0.5
)
// ConstantWithMetamorphicTestValue should be used to initialize "magic
// constants" that should be varied during test scenarios to check for bugs at
// boundary conditions. When metamorphicBuild is true, the test value will be
// used with metamorphicValueProbability probability. In all other cases, the
// production ("default") value will be used.
// The constant must be a "metamorphic variable": changing it cannot affect the
// output of any SQL DMLs. It can only affect the way in which the data is
// retrieved or processed, because otherwise the main test corpus would fail if
// this flag were enabled.
//
// An example of a "magic constant" that behaves this way is a batch size. Batch
// sizes tend to present testing problems, because often the logic that deals
// with what to do when a batch is finished is less likely to be exercised by
// simple unit tests that don't use enough data to fill up a batch.
//
// For example, instead of writing:
//
// const batchSize = 64
//
// you should write:
//
// var batchSize = util.ConstantWithMetamorphicTestValue("batch-size", 64, 1)
//
// This will often give your code a batch size of 1 in the crdb_test build
// configuration, increasing the amount of exercise the edge conditions get.
//
// The given name is used for logging.
func ConstantWithMetamorphicTestValue(name string, defaultValue, metamorphicValue int) int {
if metamorphicBuild {
rng.Lock()
defer rng.Unlock()
if rng.r.Float64() < metamorphicValueProbability {
logMetamorphicValue(name, metamorphicValue)
return metamorphicValue
}
}
return defaultValue
}
// rng is initialized to a rand.Rand if crdbTestBuild is enabled.
var rng struct {
r *rand.Rand
syncutil.Mutex
}
// DisableMetamorphicEnvVar can be used to disable metamorphic tests for
// sub-processes. If it exists and is set to something truthy as defined by
// strconv.ParseBool then metamorphic testing will not be enabled.
const DisableMetamorphicEnvVar = "COCKROACH_INTERNAL_DISABLE_METAMORPHIC_TESTING"
// ConstantWithMetamorphicTestRange is like ConstantWithMetamorphicTestValue
// except instead of returning a single metamorphic test value, it returns a
// random test value in the semi-open range [min, max).
//
// The given name is used for logging.
func ConstantWithMetamorphicTestRange(name string, defaultValue, min, max int) int {
if metamorphicBuild {
rng.Lock()
defer rng.Unlock()
if rng.r.Float64() < metamorphicValueProbability {
ret := min
if max > min {
ret = int(rng.r.Int31())%(max-min) + min
}
logMetamorphicValue(name, ret)
return ret
}
}
return defaultValue
}
// ConstantWithMetamorphicTestBool is like ConstantWithMetamorphicTestValue except
// it returns the non-default value half of the time (if running a metamorphic build).
//
// The given name is used for logging.
func ConstantWithMetamorphicTestBool(name string, defaultValue bool) bool {
if metamorphicBuild {
rng.Lock()
defer rng.Unlock()
if rng.r.Float64() < metamorphicBoolProbability {
ret := !defaultValue
logMetamorphicValue(name, ret)
return ret
}
}
return defaultValue
}
// ConstantWithMetamorphicTestChoice is like ConstantWithMetamorphicTestValue except
// it returns a random choice (equally weighted) of the given values. The default
// value is included in the random choice.
//
// The given name is used for logging.
func ConstantWithMetamorphicTestChoice(
name string, defaultValue interface{}, otherValues ...interface{},
) interface{} {
if metamorphicBuild {
values := append([]interface{}{defaultValue}, otherValues...)
rng.Lock()
defer rng.Unlock()
value := values[rng.r.Int63n(int64(len(values)))]
logMetamorphicValue(name, value)
return value
}
return defaultValue
}
func logMetamorphicValue(name string, value interface{}) {
fmt.Fprintf(os.Stderr, "initialized metamorphic constant %q with value %v\n", name, value)
}