platform_build_blueprint/proptools/hash_provider_test.go
Cole Faust 7add62142d Enforce that providers are not changed
When setProvider() is called, hash the provider and store the hash in
the module. Then after the build is done, hash all the providers again
and compare the hashes. It's an error if they don't match.

Also add a flag to control it in case this check gets slow as we convert
more things to providers. However right now it's fast (unnoticable
in terms of whole seconds) so just have the flag always enabled.

Bug: 322069292
Test: m nothing
Change-Id: Ie4e806a6a9f20542ffcc7439eef376d3fb6a98ca
2024-01-30 15:18:24 -08:00

112 lines
2.2 KiB
Go

package proptools
import (
"strings"
"testing"
)
func mustHash(t *testing.T, provider interface{}) uint64 {
t.Helper()
result, err := HashProvider(provider)
if err != nil {
t.Fatal(err)
}
return result
}
func TestHashingMapGetsSameResults(t *testing.T) {
provider := map[string]string{"foo": "bar", "baz": "qux"}
first := mustHash(t, provider)
second := mustHash(t, provider)
third := mustHash(t, provider)
fourth := mustHash(t, provider)
if first != second || second != third || third != fourth {
t.Fatal("Did not get the same result every time for a map")
}
}
func TestHashingNonSerializableTypesFails(t *testing.T) {
testCases := []struct {
name string
provider interface{}
}{
{
name: "function pointer",
provider: []func(){nil},
},
{
name: "channel",
provider: []chan int{make(chan int)},
},
{
name: "list with non-serializable type",
provider: []interface{}{"foo", make(chan int)},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
_, err := HashProvider(testCase)
if err == nil {
t.Fatal("Expected hashing error but didn't get one")
}
expected := "providers may only contain primitives, strings, arrays, slices, structs, maps, and pointers"
if !strings.Contains(err.Error(), expected) {
t.Fatalf("Expected %q, got %q", expected, err.Error())
}
})
}
}
func TestHashSuccessful(t *testing.T) {
testCases := []struct {
name string
provider interface{}
}{
{
name: "int",
provider: 5,
},
{
name: "string",
provider: "foo",
},
{
name: "*string",
provider: StringPtr("foo"),
},
{
name: "array",
provider: [3]string{"foo", "bar", "baz"},
},
{
name: "slice",
provider: []string{"foo", "bar", "baz"},
},
{
name: "struct",
provider: struct {
foo string
bar int
}{
foo: "foo",
bar: 3,
},
},
{
name: "map",
provider: map[string]int{
"foo": 3,
"bar": 4,
},
},
{
name: "list of interfaces with different types",
provider: []interface{}{"foo", 3, []string{"bar", "baz"}},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
mustHash(t, testCase.provider)
})
}
}