Esempio n. 1
0
func TestStorageIndexingBasicUpdate(t *testing.T) {

	refA := ast.MustParseRef("data.a[i]")
	refB := ast.MustParseRef("data.b[x]")
	store, ds := newStorageWithIndices(refA, refB)
	ds.Write(context.Background(), nil, AddOp, MustParsePath("/a/-"), nil)

	if store.IndexExists(refA) {
		t.Errorf("Expected index to be removed after patch")
	}
}
Esempio n. 2
0
func runIndexBuildTestCase(t *testing.T, i int, note string, refStr string, expectedStr string, value interface{}) {

	indices := newIndices()
	data := loadSmallTestData()
	store := NewDataStoreFromJSONObject(data)
	ref := ast.MustParseRef(refStr)

	if indices.Get(ref) != nil {
		t.Errorf("Test case %d (%v): Did not expect indices to contain %v yet", i, note, ref)
		return
	}

	// TODO(tsandall):
	err := indices.Build(context.Background(), store, invalidTXN, ref)
	if err != nil {
		t.Errorf("Test case %d (%v): Did not expect error from build: %v", i, note, err)
		return
	}

	index := indices.Get(ref)
	if index == nil {
		t.Errorf("Test case %d (%v): Did not expect nil index for %v", i, note, ref)
		return
	}

	assertBindingsEqual(t, fmt.Sprintf("Test case %d (%v)", i, note), index, value, expectedStr)
}
Esempio n. 3
0
func TestIndicesAdd(t *testing.T) {

	indices := newIndices()
	data := loadSmallTestData()
	store := NewDataStoreFromJSONObject(data)

	ref := ast.MustParseRef("data.d[x][y]")

	// TODO(tsandall):
	indices.Build(context.Background(), store, invalidTXN, ref)
	index := indices.Get(ref)

	// new value to add
	var val1 interface{}
	err := util.UnmarshalJSON([]byte(`{"x":[1,true]}`), &val1)
	if err != nil {
		panic(err)
	}
	bindings1 := loadExpectedBindings(`[{"x": "e", "y": 2}]`)[0]
	index.Add(val1, bindings1)
	assertBindingsEqual(t, "new value", index, val1, `[{"x": "e", "y": 2}]`)

	// existing value
	val2 := "baz"
	bindings2 := loadExpectedBindings(`[{"x": "e", "y": 3}]`)[0]
	index.Add(val2, bindings2)
	assertBindingsEqual(t, "existing value", index, val2, `[{"x": "e", "y": 1}, {"x": "e", "y": 3}]`)
	index.Add(val2, bindings2)
	assertBindingsEqual(t, "same value (no change)", index, val2, `[{"x": "e", "y": 1}, {"x": "e", "y": 3}]`)
}
Esempio n. 4
0
func setupBenchmark(nodes int, pods int) *topdown.QueryParams {

	// policy compilation
	c := ast.NewCompiler()
	modules := map[string]*ast.Module{
		"test": ast.MustParseModule(policy),
	}

	if c.Compile(modules); c.Failed() {
		panic(c.Errors)
	}

	// storage setup
	store := storage.New(storage.InMemoryConfig())

	// parameter setup
	ctx := context.Background()
	request := ast.ObjectTerm(ast.Item(ast.StringTerm("pod"), ast.MustParseTerm(requestedPod)))
	path := ast.MustParseRef("data.opa.test.scheduler.fit")
	txn := storage.NewTransactionOrDie(ctx, store)
	params := topdown.NewQueryParams(ctx, c, store, txn, request.Value, path)

	// data setup
	setupNodes(ctx, store, txn, nodes)
	setupRCs(ctx, store, txn, 1)
	setupPods(ctx, store, txn, pods, nodes)

	return params
}
Esempio n. 5
0
func setup(t *testing.T, filename string) *topdown.QueryParams {

	// policy compilation
	c := ast.NewCompiler()
	modules := map[string]*ast.Module{
		"test": ast.MustParseModule(policy),
	}

	if c.Compile(modules); c.Failed() {
		t.Fatal("unexpected error:", c.Errors)
	}

	// storage setup
	store := storage.New(storage.Config{
		Builtin: loadDataStore(filename),
	})

	// parameter setup
	ctx := context.Background()
	request := ast.ObjectTerm(ast.Item(ast.StringTerm("pod"), ast.MustParseTerm(requestedPod)))
	path := ast.MustParseRef("data.opa.test.scheduler.fit")
	txn := storage.NewTransactionOrDie(ctx, store)
	params := topdown.NewQueryParams(ctx, c, store, txn, request.Value, path)

	return params
}
Esempio n. 6
0
func ExampleQuery() {
	// Initialize context for the example. Normally the caller would obtain the
	// context from an input parameter or instantiate their own.
	ctx := context.Background()

	compiler := ast.NewCompiler()

	// Define a dummy module with rules that produce documents that we will query below.
	module, err := ast.ParseModule("my_module.rego", `

	    package opa.example

	    p[x] :- q[x], not r[x]
	    q[y] :- a = [1,2,3], y = a[_]
	    r[z] :- b = [2,4], z = b[_]

	`)

	mods := map[string]*ast.Module{
		"my_module": module,
	}

	if compiler.Compile(mods); compiler.Failed() {
		fmt.Println(compiler.Errors)
	}

	if err != nil {
		// Handle error.
	}

	// Instantiate the policy engine's storage layer.
	store := storage.New(storage.InMemoryConfig())

	// Create a new transaction. Transactions allow the policy engine to
	// evaluate the query over a consistent snapshot fo the storage layer.
	txn, err := store.NewTransaction(ctx)
	if err != nil {
		// Handle error.
	}

	defer store.Close(ctx, txn)

	// Prepare query parameters. In this case, there are no additional documents
	// required by the policy so the request is nil.
	var request ast.Value
	params := topdown.NewQueryParams(ctx, compiler, store, txn, request, ast.MustParseRef("data.opa.example.p"))

	// Execute the query against "p".
	v1, err1 := topdown.Query(params)

	// Inspect the result.
	fmt.Println("v1:", v1[0].Result)
	fmt.Println("err1:", err1)

	// Output:
	// v1: [1 3]
	// err1: <nil>

}
Esempio n. 7
0
File: repl.go Progetto: tsandall/opa
// loadRequest returns the request defined in the REPL. The REPL loads the
// request from the data.repl.request document.
func (r *REPL) loadRequest(ctx context.Context, compiler *ast.Compiler) (ast.Value, error) {

	params := topdown.NewQueryParams(ctx, compiler, r.store, r.txn, nil, ast.MustParseRef("data.repl.request"))

	result, err := topdown.Query(params)

	if err != nil {
		return nil, err
	}

	if result.Undefined() {
		return nil, nil
	}

	return ast.InterfaceToValue(result[0].Result)
}
Esempio n. 8
0
func TestPathRef(t *testing.T) {
	tests := []struct {
		path string
		head string
		ref  string
	}{
		{"/", "data", "data"},
		{"/foo/bar", "data", "data.foo.bar"},
		{"/foo/bar/3", "data", "data.foo.bar[3]"},
	}
	for _, tc := range tests {
		path := MustParsePath(tc.path)
		head := ast.VarTerm(tc.head)
		ref := ast.MustParseRef(tc.ref)
		result := path.Ref(head)
		if !result.Equal(ref) {
			t.Errorf("Expected %v but got %v", ref, result)
		}
	}
}
Esempio n. 9
0
func executeQuery(data string, compiler *ast.Compiler, tracer topdown.Tracer) {
	topdown.ResetQueryIDs()

	d := map[string]interface{}{}

	if len(data) > 0 {
		if err := util.UnmarshalJSON([]byte(data), &d); err != nil {
			panic(err)
		}
	}

	ctx := context.Background()
	store := storage.New(storage.InMemoryWithJSONConfig(d))
	txn := storage.NewTransactionOrDie(ctx, store)
	defer store.Close(ctx, txn)
	params := topdown.NewQueryParams(ctx, compiler, store, txn, nil, ast.MustParseRef("data.test.p"))
	params.Tracer = tracer

	_, err := topdown.Query(params)
	if err != nil {
		panic(err)
	}
}
Esempio n. 10
0
func TestNewPathForRef(t *testing.T) {
	tests := []struct {
		input  ast.Ref
		result Path
		err    error
	}{
		{ast.Ref{}, nil, fmt.Errorf("empty reference (indicates error in caller)")},
		{ast.MustParseRef("data.foo[x]"), nil, fmt.Errorf("unresolved reference (indicates error in caller): data.foo[x]")},
		{ast.MustParseRef("data.foo[true]"), nil, notFoundRefError(ast.MustParseRef("data.foo[true]"), doesNotExistMsg)},
		{ast.MustParseRef("data"), Path{}, nil},
		{ast.MustParseRef("data.foo"), Path{"foo"}, nil},
		{ast.MustParseRef("data.foo[1]"), Path{"foo", "1"}, nil},
		{ast.MustParseRef("data.foo.bar"), Path{"foo", "bar"}, nil},
	}

	for _, tc := range tests {
		result, err := NewPathForRef(tc.input)
		if tc.err != nil && !reflect.DeepEqual(tc.err, err) {
			t.Errorf("For %v expected %v but got %v", tc.input, tc.err, err)
		} else if !result.Equal(tc.result) {
			t.Errorf("For %v expected %v but got %v", tc.input, tc.result, result)
		}
	}
}
Esempio n. 11
0
func TestPrettyTrace(t *testing.T) {
	module := `
	package test
	p :- q[x], plus(x, 1, n)
	q[x] :- x = data.a[_]
	`

	ctx := context.Background()
	compiler := compileModules([]string{module})
	data := loadSmallTestData()
	store := storage.New(storage.InMemoryWithJSONConfig(data))
	txn := storage.NewTransactionOrDie(ctx, store)
	defer store.Close(ctx, txn)

	params := NewQueryParams(ctx, compiler, store, txn, nil, ast.MustParseRef("data.test.p"))
	tracer := NewBufferTracer()
	params.Tracer = tracer

	_, err := Query(params)
	if err != nil {
		panic(err)
	}

	expected := `Enter eq(data.test.p, _)
| Eval eq(data.test.p, _)
| Enter p = true :- data.test.q[x], plus(x, 1, n)
| | Eval data.test.q[x]
| | Enter q[x] :- eq(x, data.a[_])
| | | Eval eq(x, data.a[_])
| | | Exit q[x] :- eq(x, data.a[_])
| | Eval plus(x, 1, n)
| | Exit p = true :- data.test.q[x], plus(x, 1, n)
| Redo p = true :- data.test.q[x], plus(x, 1, n)
| | Redo data.test.q[x]
| | Redo q[x] :- eq(x, data.a[_])
| | | Redo eq(x, data.a[_])
| | | Exit q[x] :- eq(x, data.a[_])
| | Eval plus(x, 1, n)
| | Exit p = true :- data.test.q[x], plus(x, 1, n)
| Redo p = true :- data.test.q[x], plus(x, 1, n)
| | Redo data.test.q[x]
| | Redo q[x] :- eq(x, data.a[_])
| | | Redo eq(x, data.a[_])
| | | Exit q[x] :- eq(x, data.a[_])
| | Eval plus(x, 1, n)
| | Exit p = true :- data.test.q[x], plus(x, 1, n)
| Redo p = true :- data.test.q[x], plus(x, 1, n)
| | Redo data.test.q[x]
| | Redo q[x] :- eq(x, data.a[_])
| | | Redo eq(x, data.a[_])
| | | Exit q[x] :- eq(x, data.a[_])
| | Eval plus(x, 1, n)
| | Exit p = true :- data.test.q[x], plus(x, 1, n)
| Exit eq(data.test.p, _)
`

	a := strings.Split(expected, "\n")
	var buf bytes.Buffer
	PrettyTrace(&buf, *tracer)
	b := strings.Split(buf.String(), "\n")

	min := len(a)
	if min > len(b) {
		min = len(b)
	}

	for i := 0; i < min; i++ {
		if a[i] != b[i] {
			t.Errorf("Line %v in trace is incorrect. Expected %v but got: %v", i+1, a[i], b[i])
		}
	}

	if len(a) < len(b) {
		t.Fatalf("Extra lines in trace:\n%v", strings.Join(b[min:], "\n"))
	} else if len(b) < len(a) {
		t.Fatalf("Missing lines in trace:\n%v", strings.Join(a[min:], "\n"))
	}
}