diff --git a/test/wasm/assets/007_complete.yaml b/test/wasm/assets/007_complete.yaml new file mode 100644 index 0000000000..479099e2a1 --- /dev/null +++ b/test/wasm/assets/007_complete.yaml @@ -0,0 +1,170 @@ +cases: + - note: constants + disable_partial: true + query: data.x.p = 1 + modules: + - | + package x + p = 1 + return_code: 1 + - note: constants (negative) + disable_partial: true + query: data.x.p = 1 + modules: + - | + package x + p = 2 + return_code: 0 + - note: variable + disable_partial: true + query: data.x.p = 1 + modules: + - | + package x + p = y { x = 1; y = x } + return_code: 1 + - note: variable (negative) + disable_partial: true + query: data.x.p = 1 + modules: + - | + package x + p = y { x = 2; y = x } + return_code: 0 + - note: conjunction + disable_partial: true + query: data.x.p = 1 + modules: + - | + package x + p = 1 { q; r } + q { true } + r { true } + return_code: 1 + - note: conjunction (negative) + disable_partial: true + query: data.x.p = 1 + modules: + - | + package x + p = 1 { q; r } + q { true } + r { false } + return_code: 0 + - note: disjunction + disable_partial: true + query: data.x.p = 2 + modules: + - | + package x + p = 1 { false } + p = 2 { true } + p = 3 { false } + return_code: 1 + - note: disjunction (negative) + disable_partial: true + query: data.x.p = 1 + modules: + - | + package x + p = 1 { false } + p = 2 { false } + p = 3 { true } + return_code: 0 + - note: negation + disable_partial: true + query: not data.x.p = 1 + modules: + - | + package x + p = 1 { false } # undefined + return_code: 1 + - note: negation (negative) + disable_partial: true + query: not data.x.p = 1 + modules: + - | + package x + p = 1 + return_code: 0 + - note: chain + disable_partial: true + query: data.x.p = 1 + modules: + - | + package x + p = q + q = r + r = 1 + return_code: 1 + - note: chain (negative) + disable_partial: true + query: data.x.p = 1 + modules: + - | + package x + p = q + q = r + r = 2 + return_code: 0 + - note: chain input + disable_partial: true + query: data.x.p = true + modules: + - | + package x + p = q + q = r + r { input.x = 1 } + input: {"x": 1} + return_code: 1 + - note: chain input (negative) + disable_partial: true + query: data.x.p = true + modules: + - | + package x + p = q + q = r + r { input.x = 2 } + input: {"x": 1} + return_code: 0 + - note: iteration + disable_partial: true + query: data.x.p = 1 + modules: + - | + package x + p = 1 { input[x] = 1 } + input: [3,2,1] + return_code: 1 + - note: iteration (negative) + disable_partial: true + query: data.x.p = 1 + modules: + - | + package x + p = 1 { input[x] = 4 } + input: [3,2,1] + return_code: 0 + - note: conflict error + disable_partial: true + query: data.x.p = 1 + modules: + - | + package x + p = 1 + p = 2 + want_error: "unreachable" # TODO(tsandall): replace with conflict error. + - note: packages + disable_partial: true + query: data.x.p = 1 + modules: + - | + package x + import data.y.p + p = p + - | + package y + p = 1 + return_code: 1 \ No newline at end of file diff --git a/test/wasm/assets/test.js b/test/wasm/assets/test.js index 34700fd116..2383ebc739 100644 --- a/test/wasm/assets/test.js +++ b/test/wasm/assets/test.js @@ -1,7 +1,7 @@ const { readFileSync, readdirSync } = require('fs'); function stringDecoder(mem) { - return function(addr) { + return function (addr) { const i8 = new Int8Array(mem.buffer); const start = addr; var s = ""; @@ -47,10 +47,10 @@ function now() { function formatMicros(us) { if (us <= 1000) { return us + 'µs' - } else if (us <= 1000*1000) { + } else if (us <= 1000 * 1000) { return (us / 1000).toFixed(4) + 'ms' } else { - return (us / (1000*1000)).toFixed(4) + 's' + return (us / (1000 * 1000)).toFixed(4) + 's' } } @@ -60,14 +60,14 @@ function evaluate(mem, policy, input) { const addr = policy.instance.exports.opa_malloc(str.length); const buf = new Uint8Array(mem.buffer); - for(let i = 0; i < str.length; i++) { - buf[addr+i] = str.charCodeAt(i); + for (let i = 0; i < str.length; i++) { + buf[addr + i] = str.charCodeAt(i); } const returnCode = policy.instance.exports.eval(addr, str.length); - return {returnCode: returnCode}; + return { returnCode: returnCode }; } function namespace(cache, key) { @@ -82,7 +82,7 @@ function namespace(cache, key) { async function test() { - const mem = new WebAssembly.Memory({initial: 5}); + const mem = new WebAssembly.Memory({ initial: 5 }); const addr2string = stringDecoder(mem); const t0 = now(); @@ -115,12 +115,12 @@ async function test() { let dirty = false; let cache = {}; - for(let i = 0; i < testCases.length; i++) { + for (let i = 0; i < testCases.length; i++) { const policy = await WebAssembly.instantiate(testCases[i].wasmBytes, { env: { memory: mem, - opa_abort: function(addr) { + opa_abort: function (addr) { throw addr2string(addr); }, }, @@ -132,9 +132,16 @@ async function test() { try { const result = evaluate(mem, policy, testCases[i].input); passed = result.returnCode === testCases[i].return_code; - } catch(e) { - passed = false; - error = e; + } catch (e) { + if (testCases[i].want_error === undefined) { + passed = false; + error = e; + } else if (e.message.includes(testCases[i].want_error)) { + passed = true; + } else { + passed = false; + error = e; + } } if (passed) { @@ -152,7 +159,7 @@ async function test() { const dt_end = t_end - t_load; if (dirty) { - console.log(); + console.log(); } console.log('SUMMARY:'); @@ -170,7 +177,7 @@ async function test() { console.log(); console.log('TOOK:', formatMicros(dt_end)); - if ((numFailed+numErrors) > 0) { + if ((numFailed + numErrors) > 0) { process.exit(1); } } diff --git a/test/wasm/cmd/testgen.go b/test/wasm/cmd/testgen.go index a75deb96c8..dd590d196e 100644 --- a/test/wasm/cmd/testgen.go +++ b/test/wasm/cmd/testgen.go @@ -9,6 +9,7 @@ import ( "compress/gzip" "context" "encoding/json" + "fmt" "io" "io/ioutil" "os" @@ -32,10 +33,13 @@ type testCaseSet struct { } type testCase struct { - Note string `json:"note"` - Query string `json:"query"` - Input *interface{} `json:"input"` - ReturnCode int `json:"return_code"` + Note string `json:"note"` + Query string `json:"query"` + Modules []string `json:"modules"` + DisablePartial bool `json:"disable_partial"` + Input *interface{} `json:"input"` + ReturnCode int `json:"return_code"` + WantError string `json:"want_error"` } type compiledTestCaseSet struct { @@ -50,7 +54,13 @@ type compiledTestCase struct { func compileTestCases(ctx context.Context, tests testCaseSet) (*compiledTestCaseSet, error) { var result []compiledTestCase for _, tc := range tests.Cases { - cr, err := rego.New(rego.Query(tc.Query)).Compile(ctx) + args := []func(*rego.Rego){ + rego.Query(tc.Query), + } + for idx, module := range tc.Modules { + args = append(args, rego.Module(fmt.Sprintf("module%d.rego", idx), module)) + } + cr, err := rego.New(args...).Compile(ctx, rego.CompilePartial(!tc.DisablePartial)) if err != nil { return nil, err }