@@ -61,20 +61,52 @@ func Eval(t testing.TestingT, options *EvalOptions, jsonFilePaths []string, resu
6161// opa eval -i $JSONFile -d $RulePath $ResultQuery
6262//
6363// This will asynchronously run OPA on each file concurrently using goroutines.
64- func EvalE (t testing.TestingT , options * EvalOptions , jsonFilePaths []string , resultQuery string ) error {
64+ // This will fail the test if any one of the files failed.
65+ // For each file, the output will be returned on the outputs slice.
66+ func EvalWithOutput (t testing.TestingT , options * EvalOptions , jsonFilePaths []string , resultQuery string ) (outputs []string ) {
67+ outputs , err := EvalWithOutputE (t , options , jsonFilePaths , resultQuery )
68+ require .NoError (t , err )
69+ return
70+ }
71+
72+ // EvalE runs `opa eval` on the given JSON files using the configured policy file and result query. Translates to:
73+ //
74+ // opa eval -i $JSONFile -d $RulePath $ResultQuery
75+ //
76+ // This will asynchronously run OPA on each file concurrently using goroutines.
77+ func EvalE (t testing.TestingT , options * EvalOptions , jsonFilePaths []string , resultQuery string ) (err error ) {
78+ _ , err = evalE (t , options , jsonFilePaths , resultQuery )
79+ return
80+ }
81+
82+ // EvalWithOutputE runs `opa eval` on the given JSON files using the configured policy file and result query. Translates to:
83+ //
84+ // opa eval -i $JSONFile -d $RulePath $ResultQuery
85+ //
86+ // This will asynchronously run OPA on each file concurrently using goroutines.
87+ // For each file, the output will be returned on the outputs slice.
88+ func EvalWithOutputE (t testing.TestingT , options * EvalOptions , jsonFilePaths []string , resultQuery string ) (outputs []string , err error ) {
89+ return evalE (t , options , jsonFilePaths , resultQuery )
90+ }
91+
92+ func evalE (t testing.TestingT , options * EvalOptions , jsonFilePaths []string , resultQuery string ) (outputs []string , err error ) {
6593 downloadedPolicyPath , err := DownloadPolicyE (t , options .RulePath )
6694 if err != nil {
67- return err
95+ return
6896 }
6997
98+ outputs = make ([]string , len (jsonFilePaths ))
7099 wg := new (sync.WaitGroup )
71100 wg .Add (len (jsonFilePaths ))
72101 errorsOccurred := new (multierror.Error )
73102 errChans := make ([]chan error , len (jsonFilePaths ))
74103 for i , jsonFilePath := range jsonFilePaths {
75104 errChan := make (chan error , 1 )
76105 errChans [i ] = errChan
77- go asyncEval (t , wg , errChan , options , downloadedPolicyPath , jsonFilePath , resultQuery )
106+
107+ go func (i int , jsonFilePath string ) {
108+ outputs [i ] = asyncEval (t , wg , errChan , options , downloadedPolicyPath , jsonFilePath , resultQuery )
109+ }(i , jsonFilePath )
78110 }
79111 wg .Wait ()
80112 for _ , errChan := range errChans {
@@ -83,7 +115,7 @@ func EvalE(t testing.TestingT, options *EvalOptions, jsonFilePaths []string, res
83115 errorsOccurred = multierror .Append (errorsOccurred , err )
84116 }
85117 }
86- return errorsOccurred .ErrorOrNil ()
118+ return outputs , errorsOccurred .ErrorOrNil ()
87119}
88120
89121// asyncEval is a function designed to be run in a goroutine to asynchronously call `opa eval` on a single input file.
@@ -95,7 +127,7 @@ func asyncEval(
95127 downloadedPolicyPath string ,
96128 jsonFilePath string ,
97129 resultQuery string ,
98- ) {
130+ ) ( output string ) {
99131 defer wg .Done ()
100132 cmd := shell.Command {
101133 Command : "opa" ,
@@ -105,7 +137,7 @@ func asyncEval(
105137 // opa eval is typically very quick.
106138 Logger : logger .Discard ,
107139 }
108- err := runCommandWithFullLoggingE (t , options .Logger , cmd )
140+ output , err := runCommandWithFullLoggingE (t , options .Logger , cmd )
109141 ruleBasePath := filepath .Base (downloadedPolicyPath )
110142 if err == nil {
111143 options .Logger .Logf (t , "opa eval passed on file %s (policy %s; query %s)" , jsonFilePath , ruleBasePath , resultQuery )
@@ -115,10 +147,12 @@ func asyncEval(
115147 options .Logger .Logf (t , "DEBUG: rerunning opa eval to query for full data." )
116148 cmd .Args = formatOPAEvalArgs (options , downloadedPolicyPath , jsonFilePath , "data" )
117149 // We deliberately ignore the error here as we want to only return the original error.
118- runCommandWithFullLoggingE (t , options .Logger , cmd )
150+ output , _ = runCommandWithFullLoggingE (t , options .Logger , cmd )
119151 }
120152 }
121153 errChan <- err
154+
155+ return
122156}
123157
124158// formatOPAEvalArgs formats the arguments for the `opa eval` command.
@@ -146,8 +180,8 @@ func formatOPAEvalArgs(options *EvalOptions, rulePath, jsonFilePath, resultQuery
146180// runCommandWithFullLogging will log the command output in its entirety with buffering. This avoids breaking up the
147181// logs when commands are run concurrently. This is a private function used in the context of opa only because opa runs
148182// very quickly, and the output of opa is hard to parse if it is broken up by interleaved logs.
149- func runCommandWithFullLoggingE (t testing.TestingT , logger * logger.Logger , cmd shell.Command ) error {
150- output , err : = shell .RunCommandAndGetOutputE (t , cmd )
183+ func runCommandWithFullLoggingE (t testing.TestingT , logger * logger.Logger , cmd shell.Command ) ( output string , err error ) {
184+ output , err = shell .RunCommandAndGetOutputE (t , cmd )
151185 logger .Logf (t , "Output of command `%s %s`:\n %s" , cmd .Command , strings .Join (cmd .Args , " " ), output )
152- return err
186+ return
153187}
0 commit comments