-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
topdown: fix re-wrapping of ndb_cache errors #5543
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
cases: | ||
- modules: | ||
- | | ||
package rules | ||
|
||
p { | ||
time.now_ns(now) | ||
} | ||
|
||
q { p with data.x as 7 } | ||
note: "with: ndb_cache-issue" | ||
query: data.rules = x | ||
want_result: | ||
- x: | ||
p: true | ||
q: true | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1696,7 +1696,7 @@ func (e evalBuiltin) eval(iter unifyIterator) error { | |
|
||
operands := make([]*ast.Term, len(e.terms)) | ||
|
||
for i := 0; i < len(e.terms); i++ { | ||
for i := range e.terms { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style update, immaterial |
||
operands[i] = e.e.bindings.Plug(e.terms[i]) | ||
} | ||
|
||
|
@@ -1723,25 +1723,19 @@ func (e evalBuiltin) eval(iter unifyIterator) error { | |
if v, ok := e.bctx.NDBuiltinCache.Get(e.bi.Name, ast.NewArray(operands[:endIndex]...)); ok { | ||
switch { | ||
case e.bi.Decl.Result() == nil: | ||
err = iter() | ||
return iter() | ||
case len(operands) == numDeclArgs: | ||
if v.Compare(ast.Boolean(false)) != 0 { | ||
err = iter() | ||
} // else: nothing to do, don't iter() | ||
if v.Compare(ast.Boolean(false)) == 0 { | ||
return nil // nothing to do | ||
} | ||
return iter() | ||
default: | ||
err = e.e.unify(e.terms[endIndex], ast.NewTerm(v), iter) | ||
} | ||
|
||
if err != nil { | ||
return Halt{Err: err} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Halt-wrapping is what we'd like to get rid of. The rest of this section is just a small restructuring, going with straightaway return iter() calls instead of err = iter() followed by a plain return err below. Since the Halt-wrapping is gone, this became applicable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like a solid refactoring to me! |
||
return e.e.unify(e.terms[endIndex], ast.NewTerm(v), iter) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
e.e.instr.startTimer(evalOpBuiltinCall) | ||
|
||
// Otherwise, we'll need to go through the normal unify flow. | ||
e.e.instr.startTimer(evalOpBuiltinCall) | ||
} | ||
|
||
// Normal unification flow for builtins: | ||
|
@@ -1770,6 +1764,9 @@ func (e evalBuiltin) eval(iter unifyIterator) error { | |
} | ||
|
||
if err != nil { | ||
// NOTE(sr): We wrap the errors here into Halt{} because we don't want to | ||
// record them into builtinErrors below. The errors set here are coming from | ||
// the call to iter(), not from the builtin implementation. | ||
err = Halt{Err: err} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -16,6 +16,7 @@ import ( | |||||||||||||||||||||||||||||||||||||
"github.com/open-policy-agent/opa/storage" | ||||||||||||||||||||||||||||||||||||||
inmem "github.com/open-policy-agent/opa/storage/inmem/test" | ||||||||||||||||||||||||||||||||||||||
"github.com/open-policy-agent/opa/test/cases" | ||||||||||||||||||||||||||||||||||||||
"github.com/open-policy-agent/opa/topdown/builtins" | ||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
func TestRego(t *testing.T) { | ||||||||||||||||||||||||||||||||||||||
|
@@ -34,7 +35,19 @@ func TestOPARego(t *testing.T) { | |||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
func testRun(t *testing.T, tc cases.TestCase) { | ||||||||||||||||||||||||||||||||||||||
func TestRegoWithNDBCache(t *testing.T) { | ||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was one (!!) test case in our ~1700 cases that would have broken if we did this before. But still worthwhile, we'll now run all yaml tests with NDBCache enabled. Since those tests are our safety net for anything more complex going on in topdown, it's worth it, I think. This is the case -- but it depends on your machine's IP setup, I think: opa/test/cases/testdata/netlookupipaddr/test-netlookupipaddr.yaml Lines 28 to 45 in 43be06e
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm surprised that it's just one testcase that blows up. 🤔 It's better than none though! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess that's because by their very nature, non-deterministic builtins are difficult to test? 😅 |
||||||||||||||||||||||||||||||||||||||
for _, tc := range cases.MustLoad("../test/cases/testdata").Sorted().Cases { | ||||||||||||||||||||||||||||||||||||||
t.Run(tc.Note, func(t *testing.T) { | ||||||||||||||||||||||||||||||||||||||
testRun(t, tc, func(q *Query) *Query { | ||||||||||||||||||||||||||||||||||||||
return q.WithNDBuiltinCache(builtins.NDBCache{}) | ||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
type opt func(*Query) *Query | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
func testRun(t *testing.T, tc cases.TestCase, opts ...opt) { | ||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice refactoring to allow parameterizing the test runner. 👍 |
||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
ctx := context.Background() | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
|
@@ -69,14 +82,19 @@ func testRun(t *testing.T, tc cases.TestCase) { | |||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
buf := NewBufferTracer() | ||||||||||||||||||||||||||||||||||||||
rs, err := NewQuery(query). | ||||||||||||||||||||||||||||||||||||||
q := NewQuery(query). | ||||||||||||||||||||||||||||||||||||||
WithCompiler(compiler). | ||||||||||||||||||||||||||||||||||||||
WithStore(store). | ||||||||||||||||||||||||||||||||||||||
WithTransaction(txn). | ||||||||||||||||||||||||||||||||||||||
WithInput(input). | ||||||||||||||||||||||||||||||||||||||
WithStrictBuiltinErrors(tc.StrictError). | ||||||||||||||||||||||||||||||||||||||
WithTracer(buf). | ||||||||||||||||||||||||||||||||||||||
Run(ctx) | ||||||||||||||||||||||||||||||||||||||
WithTracer(buf) | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
for _, o := range opts { | ||||||||||||||||||||||||||||||||||||||
q = o(q) | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
rs, err := q.Run(ctx) | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
if tc.WantError != nil { | ||||||||||||||||||||||||||||||||||||||
testAssertErrorText(t, *tc.WantError, err) | ||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the test case that @istalker2 came up with to reproduce this with NDBCache enabled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting that this one is what breaks everything. 🤔