mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-12 19:32:48 -06:00
e43ef0a979
Earlier this evening I tried to run the Go [modernize](https://pkg.go.dev/golang.org/x/tools/gopls/internal/analysis/modernize) analyzer on OPA. That didn't go as planned: - https://github.com/golang/go/issues/73661 - https://github.com/golang/go/issues/73663 While we wait for that to be fixed, I figured an old-fashioned search-and-replace across the repo may work for at least the `interface{}` to `any` conversion. That should help make it easier to see the other fixes as applied by the modernize tool once it has had those issues resolved. Signed-off-by: Anders Eknert <anders@styra.com>
261 lines
7.1 KiB
Go
261 lines
7.1 KiB
Go
// Copyright 2019 The OPA Authors. All rights reserved.
|
|
// Use of this source code is governed by an Apache2
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Package mock defines a fake storage implementation for use in testing.
|
|
package mock
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/open-policy-agent/opa/v1/storage"
|
|
"github.com/open-policy-agent/opa/v1/storage/inmem"
|
|
)
|
|
|
|
// Transaction is a mock storage.Transaction implementation for use in testing.
|
|
// It uses an internal storage.Transaction pointer with some added functionality.
|
|
type Transaction struct {
|
|
txn storage.Transaction
|
|
Committed int
|
|
Aborted int
|
|
}
|
|
|
|
// ID returns the underlying transaction ID
|
|
func (t *Transaction) ID() uint64 {
|
|
return t.txn.ID()
|
|
}
|
|
|
|
// Validate returns an error if the transaction is in an invalid state
|
|
func (t *Transaction) Validate() error {
|
|
if t.Committed > 1 {
|
|
return fmt.Errorf("transaction %d has too many commits (%d)", t.ID(), t.Committed)
|
|
}
|
|
if t.Aborted > 1 {
|
|
return fmt.Errorf("transaction %d has too many aborts (%d)", t.ID(), t.Committed)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (t *Transaction) safeToUse() bool {
|
|
return t.Committed == 0 && t.Aborted == 0
|
|
}
|
|
|
|
// Store is a mock storage.Store implementation for use in testing.
|
|
type Store struct {
|
|
inmem storage.Store
|
|
storeOpts []inmem.Opt
|
|
baseData map[string]any
|
|
Transactions []*Transaction
|
|
Reads []*ReadCall
|
|
Writes []*WriteCall
|
|
}
|
|
|
|
// ReadCall captures the parameters for a Read call
|
|
type ReadCall struct {
|
|
Transaction *Transaction
|
|
Path storage.Path
|
|
Error error
|
|
Safe bool
|
|
}
|
|
|
|
// WriteCall captures the parameters for a write call
|
|
type WriteCall struct {
|
|
Transaction *Transaction
|
|
Op storage.PatchOp
|
|
Path storage.Path
|
|
Error error
|
|
Safe bool
|
|
}
|
|
|
|
// New creates a new mock Store
|
|
func New(opt ...inmem.Opt) *Store {
|
|
s := &Store{
|
|
storeOpts: opt,
|
|
}
|
|
s.Reset()
|
|
return s
|
|
}
|
|
|
|
// NewWithData creates a store with some initial data
|
|
func NewWithData(data map[string]any, opt ...inmem.Opt) *Store {
|
|
s := &Store{
|
|
baseData: data,
|
|
storeOpts: opt,
|
|
}
|
|
s.Reset()
|
|
return s
|
|
}
|
|
|
|
// Reset the store
|
|
func (s *Store) Reset() {
|
|
s.Transactions = []*Transaction{}
|
|
s.Reads = []*ReadCall{}
|
|
s.Writes = []*WriteCall{}
|
|
if s.baseData != nil {
|
|
s.inmem = inmem.NewFromObjectWithOpts(s.baseData, s.storeOpts...)
|
|
} else {
|
|
s.inmem = inmem.NewWithOpts(s.storeOpts...)
|
|
}
|
|
}
|
|
|
|
// GetTransaction will a transaction with a specific ID
|
|
// that was associated with this Store.
|
|
func (s *Store) GetTransaction(id uint64) *Transaction {
|
|
for _, txn := range s.Transactions {
|
|
if txn.ID() == id {
|
|
return txn
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Errors returns a list of errors for each invalid state found.
|
|
// If any Transactions are invalid or reads/writes were
|
|
// unsafe an error will be returned for each problem.
|
|
func (s *Store) Errors() []error {
|
|
var errs []error
|
|
for _, txn := range s.Transactions {
|
|
err := txn.Validate()
|
|
if err != nil {
|
|
errs = append(errs, err)
|
|
}
|
|
}
|
|
|
|
for _, read := range s.Reads {
|
|
if !read.Safe {
|
|
errs = append(errs, fmt.Errorf("unsafe Read call %+v", *read))
|
|
}
|
|
}
|
|
|
|
for _, write := range s.Writes {
|
|
if !write.Safe {
|
|
errs = append(errs, fmt.Errorf("unsafe Write call %+v", *write))
|
|
}
|
|
}
|
|
|
|
return errs
|
|
}
|
|
|
|
// AssertValid will raise an error with the provided testing.T if
|
|
// there are any errors on the store.
|
|
func (s *Store) AssertValid(t *testing.T) {
|
|
t.Helper()
|
|
for _, err := range s.Errors() {
|
|
t.Errorf("Error detected on store: %s", err)
|
|
}
|
|
}
|
|
|
|
// storage.Store interface implementation
|
|
|
|
// Register just shims the call to the underlying inmem store
|
|
func (s *Store) Register(ctx context.Context, txn storage.Transaction, config storage.TriggerConfig) (storage.TriggerHandle, error) {
|
|
return s.inmem.Register(ctx, getRealTxn(txn), config)
|
|
}
|
|
|
|
// ListPolicies just shims the call to the underlying inmem store
|
|
func (s *Store) ListPolicies(ctx context.Context, txn storage.Transaction) ([]string, error) {
|
|
return s.inmem.ListPolicies(ctx, getRealTxn(txn))
|
|
}
|
|
|
|
// GetPolicy just shims the call to the underlying inmem store
|
|
func (s *Store) GetPolicy(ctx context.Context, txn storage.Transaction, name string) ([]byte, error) {
|
|
return s.inmem.GetPolicy(ctx, getRealTxn(txn), name)
|
|
}
|
|
|
|
// UpsertPolicy just shims the call to the underlying inmem store
|
|
func (s *Store) UpsertPolicy(ctx context.Context, txn storage.Transaction, name string, policy []byte) error {
|
|
return s.inmem.UpsertPolicy(ctx, getRealTxn(txn), name, policy)
|
|
}
|
|
|
|
// DeletePolicy just shims the call to the underlying inmem store
|
|
func (s *Store) DeletePolicy(ctx context.Context, txn storage.Transaction, name string) error {
|
|
return s.inmem.DeletePolicy(ctx, getRealTxn(txn), name)
|
|
}
|
|
|
|
// NewTransaction will create a new transaction on the underlying inmem store
|
|
// but wraps it with a mock Transaction. These are then tracked on the store.
|
|
func (s *Store) NewTransaction(ctx context.Context, params ...storage.TransactionParams) (storage.Transaction, error) {
|
|
realTxn, err := s.inmem.NewTransaction(ctx, params...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
txn := &Transaction{
|
|
txn: realTxn,
|
|
Committed: 0,
|
|
Aborted: 0,
|
|
}
|
|
s.Transactions = append(s.Transactions, txn)
|
|
return txn, nil
|
|
}
|
|
|
|
// Read will make a read from the underlying inmem store and
|
|
// add a new entry to the mock store Reads list. If there
|
|
// is an error are the read is unsafe it will be noted in
|
|
// the ReadCall.
|
|
func (s *Store) Read(ctx context.Context, txn storage.Transaction, path storage.Path) (any, error) {
|
|
mockTxn := txn.(*Transaction)
|
|
|
|
data, err := s.inmem.Read(ctx, mockTxn.txn, path)
|
|
|
|
s.Reads = append(s.Reads, &ReadCall{
|
|
Transaction: mockTxn,
|
|
Path: path,
|
|
Error: err,
|
|
Safe: mockTxn.safeToUse(),
|
|
})
|
|
|
|
return data, err
|
|
}
|
|
|
|
// Write will make a read from the underlying inmem store and
|
|
// add a new entry to the mock store Writes list. If there
|
|
// is an error are the write is unsafe it will be noted in
|
|
// the WriteCall.
|
|
func (s *Store) Write(ctx context.Context, txn storage.Transaction, op storage.PatchOp, path storage.Path, value any) error {
|
|
mockTxn := txn.(*Transaction)
|
|
|
|
err := s.inmem.Write(ctx, mockTxn.txn, op, path, value)
|
|
|
|
s.Writes = append(s.Writes, &WriteCall{
|
|
Transaction: mockTxn,
|
|
Op: op,
|
|
Path: path,
|
|
Error: err,
|
|
Safe: mockTxn.safeToUse(),
|
|
})
|
|
|
|
return nil
|
|
}
|
|
|
|
// Commit will commit the underlying transaction while
|
|
// also updating the mock Transaction
|
|
func (s *Store) Commit(ctx context.Context, txn storage.Transaction) error {
|
|
mockTxn := txn.(*Transaction)
|
|
|
|
err := s.inmem.Commit(ctx, mockTxn.txn)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
mockTxn.Committed++
|
|
return nil
|
|
}
|
|
|
|
// Abort will abort the underlying transaction while
|
|
// also updating the mock Transaction
|
|
func (s *Store) Abort(ctx context.Context, txn storage.Transaction) {
|
|
mockTxn := txn.(*Transaction)
|
|
s.inmem.Abort(ctx, mockTxn.txn)
|
|
mockTxn.Aborted++
|
|
}
|
|
|
|
func (s *Store) Truncate(ctx context.Context, txn storage.Transaction, params storage.TransactionParams, it storage.Iterator) error {
|
|
return s.inmem.Truncate(ctx, getRealTxn(txn), params, it)
|
|
}
|
|
|
|
func getRealTxn(txn storage.Transaction) storage.Transaction {
|
|
return txn.(*Transaction).txn
|
|
}
|