2023-03-28 22:48:58 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2022-03-28 17:56:44 +00:00
|
|
|
package prototest
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/google/go-cmp/cmp"
|
2022-05-25 17:37:44 +00:00
|
|
|
"google.golang.org/protobuf/testing/protocmp"
|
2022-03-28 17:56:44 +00:00
|
|
|
)
|
|
|
|
|
Add storage backend interface and in-memory implementation (#16538)
Introduces `storage.Backend`, which will serve as the interface between the
Resource Service and the underlying storage system (Raft today, but in the
future, who knows!).
The primary design goal of this interface is to keep its surface area small,
and push as much functionality as possible into the layers above, so that new
implementations can be added with little effort, and easily proven to be
correct. To that end, we also provide a suite of "conformance" tests that can
be run against a backend implementation to check it behaves correctly.
In this commit, we introduce an initial in-memory storage backend, which is
suitable for tests and when running Consul in development mode. This backend is
a thin wrapper around the `Store` type, which implements a resource database
using go-memdb and our internal pub/sub system. `Store` will also be used to
handle reads in our Raft backend, and in the future, used as a local cache for
external storage systems.
2023-03-27 09:30:53 +00:00
|
|
|
type TestingT interface {
|
|
|
|
Helper()
|
|
|
|
Fatalf(string, ...any)
|
|
|
|
}
|
|
|
|
|
|
|
|
func AssertDeepEqual(t TestingT, x, y interface{}, opts ...cmp.Option) {
|
2022-03-28 17:56:44 +00:00
|
|
|
t.Helper()
|
2022-03-29 18:17:41 +00:00
|
|
|
|
2022-05-25 17:37:44 +00:00
|
|
|
opts = append(opts, protocmp.Transform())
|
2022-03-29 18:17:41 +00:00
|
|
|
|
2022-03-28 17:56:44 +00:00
|
|
|
if diff := cmp.Diff(x, y, opts...); diff != "" {
|
|
|
|
t.Fatalf("assertion failed: values are not equal\n--- expected\n+++ actual\n%v", diff)
|
|
|
|
}
|
|
|
|
}
|
2022-07-15 20:03:40 +00:00
|
|
|
|
|
|
|
// AssertElementsMatch asserts that the specified listX(array, slice...) is
|
|
|
|
// equal to specified listY(array, slice...) ignoring the order of the
|
|
|
|
// elements. If there are duplicate elements, the number of appearances of each
|
|
|
|
// of them in both lists should match.
|
|
|
|
//
|
|
|
|
// prototest.AssertElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2])
|
|
|
|
func AssertElementsMatch[V any](
|
Add storage backend interface and in-memory implementation (#16538)
Introduces `storage.Backend`, which will serve as the interface between the
Resource Service and the underlying storage system (Raft today, but in the
future, who knows!).
The primary design goal of this interface is to keep its surface area small,
and push as much functionality as possible into the layers above, so that new
implementations can be added with little effort, and easily proven to be
correct. To that end, we also provide a suite of "conformance" tests that can
be run against a backend implementation to check it behaves correctly.
In this commit, we introduce an initial in-memory storage backend, which is
suitable for tests and when running Consul in development mode. This backend is
a thin wrapper around the `Store` type, which implements a resource database
using go-memdb and our internal pub/sub system. `Store` will also be used to
handle reads in our Raft backend, and in the future, used as a local cache for
external storage systems.
2023-03-27 09:30:53 +00:00
|
|
|
t TestingT, listX, listY []V, opts ...cmp.Option,
|
2022-07-15 20:03:40 +00:00
|
|
|
) {
|
2023-08-09 16:02:17 +00:00
|
|
|
t.Helper()
|
2023-05-22 18:49:50 +00:00
|
|
|
diff := diffElements(listX, listY, opts...)
|
|
|
|
if diff != "" {
|
|
|
|
t.Fatalf("assertion failed: slices do not have matching elements\n--- expected\n+++ actual\n%v", diff)
|
|
|
|
}
|
|
|
|
}
|
2022-07-15 20:03:40 +00:00
|
|
|
|
2023-05-22 18:49:50 +00:00
|
|
|
func diffElements[V any](
|
|
|
|
listX, listY []V, opts ...cmp.Option,
|
|
|
|
) string {
|
2022-07-15 20:03:40 +00:00
|
|
|
if len(listX) == 0 && len(listY) == 0 {
|
2023-05-22 18:49:50 +00:00
|
|
|
return ""
|
2022-07-15 20:03:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
opts = append(opts, protocmp.Transform())
|
|
|
|
|
2023-05-22 18:49:50 +00:00
|
|
|
if len(listX) != len(listY) {
|
|
|
|
return cmp.Diff(listX, listY, opts...)
|
|
|
|
}
|
|
|
|
|
2022-07-15 20:03:40 +00:00
|
|
|
// dump into a map keyed by sliceID
|
|
|
|
mapX := make(map[int]V)
|
|
|
|
for i, val := range listX {
|
|
|
|
mapX[i] = val
|
|
|
|
}
|
|
|
|
|
|
|
|
mapY := make(map[int]V)
|
|
|
|
for i, val := range listY {
|
|
|
|
mapY[i] = val
|
|
|
|
}
|
|
|
|
|
|
|
|
var outX, outY []V
|
|
|
|
for i, itemX := range mapX {
|
|
|
|
for j, itemY := range mapY {
|
|
|
|
if diff := cmp.Diff(itemX, itemY, opts...); diff == "" {
|
|
|
|
outX = append(outX, itemX)
|
|
|
|
outY = append(outY, itemY)
|
|
|
|
delete(mapX, i)
|
|
|
|
delete(mapY, j)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-22 18:49:50 +00:00
|
|
|
if len(outX) == len(listX) && len(outY) == len(listY) {
|
|
|
|
return "" // matches
|
2022-07-15 20:03:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// dump remainder into the slice so we can generate a useful error
|
|
|
|
for _, itemX := range mapX {
|
|
|
|
outX = append(outX, itemX)
|
|
|
|
}
|
|
|
|
for _, itemY := range mapY {
|
|
|
|
outY = append(outY, itemY)
|
|
|
|
}
|
|
|
|
|
2023-05-22 18:49:50 +00:00
|
|
|
return cmp.Diff(outX, outY, opts...)
|
2022-07-15 20:03:40 +00:00
|
|
|
}
|
Add storage backend interface and in-memory implementation (#16538)
Introduces `storage.Backend`, which will serve as the interface between the
Resource Service and the underlying storage system (Raft today, but in the
future, who knows!).
The primary design goal of this interface is to keep its surface area small,
and push as much functionality as possible into the layers above, so that new
implementations can be added with little effort, and easily proven to be
correct. To that end, we also provide a suite of "conformance" tests that can
be run against a backend implementation to check it behaves correctly.
In this commit, we introduce an initial in-memory storage backend, which is
suitable for tests and when running Consul in development mode. This backend is
a thin wrapper around the `Store` type, which implements a resource database
using go-memdb and our internal pub/sub system. `Store` will also be used to
handle reads in our Raft backend, and in the future, used as a local cache for
external storage systems.
2023-03-27 09:30:53 +00:00
|
|
|
|
|
|
|
func AssertContainsElement[V any](t TestingT, list []V, element V, opts ...cmp.Option) {
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
opts = append(opts, protocmp.Transform())
|
|
|
|
|
|
|
|
for _, e := range list {
|
|
|
|
if cmp.Equal(e, element, opts...) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-16 16:58:53 +00:00
|
|
|
t.Fatalf("assertion failed: list does not contain element\n--- list\n%+v\n--- element: %+v", list, element)
|
Add storage backend interface and in-memory implementation (#16538)
Introduces `storage.Backend`, which will serve as the interface between the
Resource Service and the underlying storage system (Raft today, but in the
future, who knows!).
The primary design goal of this interface is to keep its surface area small,
and push as much functionality as possible into the layers above, so that new
implementations can be added with little effort, and easily proven to be
correct. To that end, we also provide a suite of "conformance" tests that can
be run against a backend implementation to check it behaves correctly.
In this commit, we introduce an initial in-memory storage backend, which is
suitable for tests and when running Consul in development mode. This backend is
a thin wrapper around the `Store` type, which implements a resource database
using go-memdb and our internal pub/sub system. `Store` will also be used to
handle reads in our Raft backend, and in the future, used as a local cache for
external storage systems.
2023-03-27 09:30:53 +00:00
|
|
|
}
|