mirror of https://github.com/grafana/grafana
Settings: Fix data race when dynamically overriding settings with environment variables (#81667)
Chore: Fix data race when dynamically overriding settings with environment variablespull/81897/head
parent
c87e4eb724
commit
b02f0b926a
@ -0,0 +1,42 @@ |
||||
package osutil |
||||
|
||||
import ( |
||||
"os" |
||||
) |
||||
|
||||
// Env collects global functions from standard package "os" that are related to
|
||||
// environment variables. This allows abstracting code and provides a way to
|
||||
// concurrently test code that needs access to these shared resources.
|
||||
type Env interface { |
||||
Setenv(key, value string) error |
||||
Getenv(key string) string |
||||
} |
||||
|
||||
// RealEnv implements Env interface by calling the actual global functions in
|
||||
// package "os". This should be used by default anywhere that an Env is
|
||||
// expected, and use MapEnv instead in your unit tests.
|
||||
type RealEnv struct{} |
||||
|
||||
func (RealEnv) Setenv(key, value string) error { |
||||
return os.Setenv(key, value) |
||||
} |
||||
|
||||
func (RealEnv) Getenv(key string) string { |
||||
return os.Getenv(key) |
||||
} |
||||
|
||||
// MapEnv is a fake implementing Env interface. It is purposefully not
|
||||
// concurrency-safe, so if your tests using it panic due to concurrent map
|
||||
// access, then you need to fix a data race in your code. This is
|
||||
// because environment variables are globals to a process, so you should be
|
||||
// properly synchronizing access to them (e.g. with a mutex).
|
||||
type MapEnv map[string]string |
||||
|
||||
func (m MapEnv) Setenv(key, value string) error { |
||||
m[key] = value |
||||
return nil |
||||
} |
||||
|
||||
func (m MapEnv) Getenv(key string) string { |
||||
return m[key] |
||||
} |
@ -0,0 +1,35 @@ |
||||
package osutil |
||||
|
||||
import ( |
||||
"os" |
||||
"testing" |
||||
|
||||
"github.com/stretchr/testify/assert" |
||||
) |
||||
|
||||
func TestRealEnv(t *testing.T) { |
||||
// testing here is obviously not parallel since we do need to access real
|
||||
// environment variables from the os
|
||||
|
||||
const key = "MEREKETENGUE" |
||||
const value = "IS ALIVE" |
||||
|
||||
assert.Equal(t, os.Getenv(key), RealEnv{}.Getenv(key)) |
||||
assert.NoError(t, RealEnv{}.Setenv(key, value)) |
||||
assert.Equal(t, value, RealEnv{}.Getenv(key)) |
||||
assert.Equal(t, value, os.Getenv(key)) |
||||
} |
||||
|
||||
func TestMapEnv(t *testing.T) { |
||||
t.Parallel() |
||||
|
||||
const key = "THE_THING" |
||||
const value = "IS ALIVE" |
||||
|
||||
e := MapEnv{} |
||||
assert.Empty(t, e.Getenv(key)) |
||||
assert.Len(t, e, 0) |
||||
assert.NoError(t, e.Setenv(key, value)) |
||||
assert.Equal(t, value, e.Getenv(key)) |
||||
assert.Len(t, e, 1) |
||||
} |
Loading…
Reference in new issue