134 lines
2.9 KiB
Go
134 lines
2.9 KiB
Go
package invocation_test
|
|
|
|
import (
|
|
_ "embed"
|
|
"fmt"
|
|
"os"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/ipfs/go-cid"
|
|
"github.com/ipld/go-ipld-prime"
|
|
"github.com/ipld/go-ipld-prime/codec/dagcbor"
|
|
"github.com/ipld/go-ipld-prime/codec/dagjson"
|
|
"github.com/ipld/go-ipld-prime/schema"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/ucan-wg/go-ucan/token/delegation"
|
|
"github.com/ucan-wg/go-ucan/token/internal/envelope"
|
|
"github.com/ucan-wg/go-ucan/token/invocation"
|
|
)
|
|
|
|
//go:embed fixtures.ipldsch
|
|
var schemaBytes []byte
|
|
|
|
var (
|
|
once sync.Once
|
|
ts *schema.TypeSystem
|
|
errSchema error
|
|
)
|
|
|
|
func mustLoadSchema() *schema.TypeSystem {
|
|
once.Do(func() {
|
|
ts, errSchema = ipld.LoadSchemaBytes(schemaBytes)
|
|
})
|
|
if errSchema != nil {
|
|
panic(fmt.Errorf("failed to load IPLD schema: %s", errSchema))
|
|
}
|
|
return ts
|
|
}
|
|
|
|
func fixturesType() schema.Type {
|
|
return mustLoadSchema().TypeByName("Fixtures")
|
|
}
|
|
|
|
type ErrorModel struct {
|
|
Name string
|
|
}
|
|
|
|
type VectorModel struct {
|
|
Name string
|
|
Description string
|
|
Invocation []byte
|
|
Proofs [][]byte
|
|
Error *ErrorModel
|
|
}
|
|
|
|
type FixturesModel struct {
|
|
Version string
|
|
Comments string
|
|
Valid []VectorModel
|
|
Invalid []VectorModel
|
|
}
|
|
|
|
type NamedError interface {
|
|
error
|
|
Name() string
|
|
}
|
|
|
|
func TestFixtures(t *testing.T) {
|
|
fixturesFile, err := os.Open("./testdata/executables.json")
|
|
require.NoError(t, err)
|
|
|
|
var fixtures FixturesModel
|
|
_, err = ipld.UnmarshalStreaming(fixturesFile, dagjson.Decode, &fixtures, fixturesType())
|
|
require.NoError(t, err)
|
|
|
|
for _, vector := range fixtures.Valid {
|
|
t.Run("valid "+vector.Name, func(t *testing.T) {
|
|
err := decodeAndValidate(vector)
|
|
require.NoError(t, err, "execution should have been allowed for invocation with %s", vector.Description)
|
|
})
|
|
}
|
|
|
|
for _, vector := range fixtures.Invalid {
|
|
t.Run("invalid "+vector.Name, func(t *testing.T) {
|
|
err := decodeAndValidate(vector)
|
|
require.Error(t, err, "execution should not have been allowed for invocation because %s", vector.Description)
|
|
})
|
|
}
|
|
}
|
|
|
|
type mapDelegationLoader struct {
|
|
data map[cid.Cid]*delegation.Token
|
|
}
|
|
|
|
func (ml *mapDelegationLoader) GetDelegation(cid cid.Cid) (*delegation.Token, error) {
|
|
d, ok := ml.data[cid]
|
|
if !ok {
|
|
return nil, fmt.Errorf("delegation not found: %s", cid)
|
|
}
|
|
return d, nil
|
|
}
|
|
|
|
func decodeAndValidate(vector VectorModel) error {
|
|
inv, err := invocation.Decode(vector.Invocation, dagcbor.Decode)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
proofs, err := decodeProofs(vector.Proofs)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = inv.ExecutionAllowed(&mapDelegationLoader{proofs})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func decodeProofs(vectorProofs [][]byte) (map[cid.Cid]*delegation.Token, error) {
|
|
proofs := map[cid.Cid]*delegation.Token{}
|
|
for _, p := range vectorProofs {
|
|
dlg, err := delegation.Decode(p, dagcbor.Decode)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
c, err := envelope.CIDFromBytes(p)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
proofs[c] = dlg
|
|
}
|
|
return proofs, nil
|
|
}
|