aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/decision
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/decision')
-rw-r--r--pkg/decision/decision-provider.go154
-rw-r--r--pkg/decision/decision-provider_test.go465
2 files changed, 459 insertions, 160 deletions
diff --git a/pkg/decision/decision-provider.go b/pkg/decision/decision-provider.go
index 12896c3..035fb0f 100644
--- a/pkg/decision/decision-provider.go
+++ b/pkg/decision/decision-provider.go
@@ -38,6 +38,7 @@ import (
"policy-opa-pdp/pkg/pdpstate"
"policy-opa-pdp/pkg/policymap"
"policy-opa-pdp/pkg/utils"
+ "sort"
"strings"
)
@@ -77,8 +78,8 @@ func writeErrorJSONResponse(res http.ResponseWriter, status int, errorDescriptio
// creates a success decision response
func createSuccessDecisionResponse(policyName string, output map[string]interface{}) *oapicodegen.OPADecisionResponse {
return &oapicodegen.OPADecisionResponse{
- PolicyName: policyName,
- Output: output,
+ PolicyName: policyName,
+ Output: output,
}
}
@@ -135,17 +136,21 @@ func handleDecisionRequest(res http.ResponseWriter, req *http.Request, errorDtls
return
}
- if decisionReq.PolicyName == "" {
- *errorDtls = "Policy Name is nil which is invalid."
- *httpStatus = http.StatusBadRequest
- return
- }
+ // Validate the request body
+ validationErrors := utils.ValidateOPADataRequest(decisionReq)
if decisionReq.PolicyFilter == nil || len(decisionReq.PolicyFilter) == 0 {
- *errorDtls = "Policy Filter is nil."
+ validationErrors = append(validationErrors, "PolicyFilter is required")
+ }
+ if len(validationErrors) > 0 {
+ *errorDtls = strings.Join(validationErrors, ", ")
+ log.Errorf("Facing validation error in requestbody - %s", *errorDtls)
*httpStatus = http.StatusBadRequest
return
}
+ log.Debugf("Validation successful for request fields")
+ // If validation passes, handle the decision request
+
decisionReq.PolicyName = strings.ReplaceAll(decisionReq.PolicyName, ".", "/")
handlePolicyValidation(res, decisionReq, errorDtls, httpStatus, policyId)
}
@@ -195,7 +200,7 @@ func policyExists(policyName string, extractedPolicies []model.ToscaConceptIdent
return false
}
-//This function processes the request headers
+// This function processes the request headers
func processRequestHeaders(req *http.Request, res http.ResponseWriter) (string, *oapicodegen.DecisionParams) {
requestId := req.Header.Get("X-ONAP-RequestID")
var parsedUUID *uuid.UUID
@@ -229,7 +234,7 @@ func isSystemActive() bool {
return pdpstate.GetCurrentState() == model.Active
}
-//This method parses the body and checks whether it is properly formatted JSON or not
+// This method parses the body and checks whether it is properly formatted JSON or not
func parseRequestBody(req *http.Request) (*oapicodegen.OPADecisionRequest, error) {
var decisionReq oapicodegen.OPADecisionRequest
if err := json.NewDecoder(req.Body).Decode(&decisionReq); err != nil {
@@ -238,7 +243,7 @@ func parseRequestBody(req *http.Request) (*oapicodegen.OPADecisionRequest, error
return &decisionReq, nil
}
-//This function sends the error response
+// This function sends the error response
func sendDecisionErrorResponse(msg string, res http.ResponseWriter, httpStatus int, policyName string) {
log.Warnf("%s", msg)
decisionExc := createDecisionExceptionResponse(httpStatus, msg, policyName)
@@ -247,29 +252,33 @@ func sendDecisionErrorResponse(msg string, res http.ResponseWriter, httpStatus i
writeErrorJSONResponse(res, httpStatus, msg, *decisionExc)
}
-
type OPASingletonInstanceFunc func() (*sdk.OPA, error)
+
var OPASingletonInstance OPASingletonInstanceFunc = opasdk.GetOPASingletonInstance
-//This function returns the opasdk instance
+// This function returns the opasdk instance
func getOpaInstance() (*sdk.OPA, error) {
return OPASingletonInstance()
}
-
-
type OPADecisionFunc func(opa *sdk.OPA, ctx context.Context, options sdk.DecisionOptions) (*sdk.DecisionResult, error)
+
var OPADecision OPADecisionFunc = (*sdk.OPA).Decision
-//This function processes the OPA decision
+// This function processes the OPA decision
func processOpaDecision(res http.ResponseWriter, opa *sdk.OPA, decisionReq *oapicodegen.OPADecisionRequest) {
ctx := context.Background()
log.Debugf("SDK making a decision")
- var decisionRes *oapicodegen.OPADecisionResponse
+ var decisionRes *oapicodegen.OPADecisionResponse
//OPA is seding success with a warning message if "input" parameter is missing, so we need to send success response
- if (decisionReq.Input == nil) {
- statusMessage := "{\"warning\":{\"code\":\"api_usage_warning\",\"message\":\"'input' key missing from the request\"}}"
- decisionRes = createSuccessDecisionResponseWithStatus(decisionReq.PolicyName, nil, statusMessage)
+ inputBytes, err := json.Marshal(decisionReq.Input)
+ if err != nil {
+ log.Warnf("Failed to unmarshal decision Request Input: %vg", err)
+ return
+ }
+ if inputBytes == nil || len(inputBytes) == 0 {
+ statusMessage := "{\"warning\":{\"code\":\"api_usage_warning\",\"message\":\"'input' key missing from the request\"}}"
+ decisionRes = createSuccessDecisionResponseWithStatus(decisionReq.PolicyName, nil, statusMessage)
} else {
options := sdk.DecisionOptions{Path: decisionReq.PolicyName, Input: decisionReq.Input}
decisionResult, decisionErr := OPADecision(opa, ctx, options)
@@ -280,20 +289,22 @@ func processOpaDecision(res http.ResponseWriter, opa *sdk.OPA, decisionReq *oapi
}
log.Debugf("RAW opa Decision output:\n%s\n", string(jsonOutput))
+ //while making decision . is replaced by /. reverting back.
+ decisionReq.PolicyName = strings.ReplaceAll(decisionReq.PolicyName, "/", ".")
+
if decisionErr != nil {
- handleOpaDecisionError(res, decisionErr, decisionReq.PolicyName)
+ sendDecisionErrorResponse(decisionErr.Error(), res, http.StatusInternalServerError, decisionReq.PolicyName)
return
}
-
var policyFilter []string
if decisionReq.PolicyFilter != nil {
policyFilter = decisionReq.PolicyFilter
}
result, _ := decisionResult.Result.(map[string]interface{})
- outputMap, unmatchedFilters := processPolicyFilter(result, policyFilter)
+ outputMap, unmatchedFilters, validPolicyFilters := processPolicyFilter(result, policyFilter)
if len(unmatchedFilters) > 0 {
- message := fmt.Sprintf("Policy Filter(s) not matching: [%s]", strings.Join(unmatchedFilters, ", "))
+ message := fmt.Sprintf("Policy Filter(s) not matching, Valid Filter(s) are: [%s]", strings.Join(validPolicyFilters, ", "))
decisionRes = createSuccessDecisionResponseWithStatus(decisionReq.PolicyName, outputMap, message)
} else {
decisionRes = createSuccessDecisionResponse(decisionReq.PolicyName, outputMap)
@@ -303,52 +314,77 @@ func processOpaDecision(res http.ResponseWriter, opa *sdk.OPA, decisionReq *oapi
writeOpaJSONResponse(res, http.StatusOK, *decisionRes)
}
-//This function validates the errors during decision process
-func handleOpaDecisionError(res http.ResponseWriter, err error, policyName string) {
- //As per the opa documentation in https://www.openpolicyagent.org/docs/latest/rest-api/#get-a-document-with-input
- //when the path refers to an undefined document it will return 200 with no result.
- //opasdk is returning opa_undefined_error for such case, so need to give sucess for such case and
- //for other cases we have to send error response
- if strings.Contains(err.Error(), string(oapicodegen.OpaUndefinedError)) {
- decisionExc := createSuccessDecisionResponse(policyName, nil)
- metrics.IncrementDecisionSuccessCount()
- writeOpaJSONResponse(res, http.StatusOK, *decisionExc)
- } else {
- sendDecisionErrorResponse(err.Error(), res, http.StatusInternalServerError, policyName)
- }
-}
-
-//This function processes the policy filters
-func processPolicyFilter(result map[string]interface{}, policyFilter []string) (map[string]interface{}, []string) {
+// This function processes the policy filters
+func processPolicyFilter(result map[string]interface{}, policyFilter []string) (map[string]interface{}, []string, []string) {
if len(policyFilter) > 0 {
- filteredResult, unmatchedFilters := applyPolicyFilter(result, policyFilter)
+ filteredResult, unmatchedFilters, validfilters := applyPolicyFilter(result, policyFilter)
if len(filteredResult) > 0 {
- return filteredResult, unmatchedFilters
+ return filteredResult, unmatchedFilters, validfilters
}
}
- return nil, policyFilter
+ return nil, policyFilter, getValidPolicyFilters(result)
}
-// Function to apply policy filter to decision result
-func applyPolicyFilter(result map[string]interface{}, filters []string) (map[string]interface{}, []string) {
+// Get Valid Filters and collects unmatched filters
+func applyPolicyFilter(result map[string]interface{}, filters []string) (map[string]interface{}, []string, []string) {
filteredOutput := make(map[string]interface{})
- unmatchedFilters := make(map[string]struct{})
+ unmatchedFilters := []string{}
+
+ validFilters := getValidPolicyFilters(result)
for _, filter := range filters {
- unmatchedFilters[filter] = struct{}{}
+ if filter == "" {
+ // when filter is "" empty, the entire resultant data will be reported
+ return result, nil, validFilters
+ }
+ // Try to find the value in the result map
+ if value := findNestedValue(result, strings.Split(filter, "/")); value != nil {
+ filteredOutput[filter] = value // Store using full path
+ } else if value, exists := result[filter]; exists {
+ // Allow direct key match (for non-nested filters)
+ filteredOutput[filter] = value
+ } else {
+ unmatchedFilters = append(unmatchedFilters, filter) // Collect unmatched filters
+ }
}
- for key, value := range result {
- for _, filter := range filters {
- if (key == filter || strings.TrimSpace(filter) == "") {
- filteredOutput[key] = value
- delete(unmatchedFilters, filter)
- }
- }
+
+ return filteredOutput, unmatchedFilters, validFilters
+}
+
+// handles the nested Policy Filters available when multiple rego files are included.
+func findNestedValue(opaSdkResult map[string]interface{}, keys []string) interface{} {
+ if len(keys) == 0 {
+ return nil
}
+ currentMap := opaSdkResult
- unmatchedList := make([]string, 0, len(unmatchedFilters))
- for filter := range unmatchedFilters {
- unmatchedList = append(unmatchedList, filter)
+ for _, key := range keys {
+ value, exists := currentMap[key]
+ if !exists {
+ return nil // Key doesn't exist
+ }
+
+ // If it's a nested map, continue traversal
+ if nextNestedMap, ok := value.(map[string]interface{}); ok {
+ currentMap = nextNestedMap
+ } else {
+ return value // Return final value (non-map)
+ }
}
+ return currentMap
+}
- return filteredOutput, unmatchedList
+// returns the valid Policy Filters available
+func getValidPolicyFilters(opaSdkResult map[string]interface{}) []string {
+ keys := make([]string, 0)
+
+ for k, v := range opaSdkResult {
+ keys = append(keys, k)
+ if nestedMap, ok := v.(map[string]interface{}); ok {
+ for nestedKey := range nestedMap {
+ keys = append(keys, k+"/"+nestedKey)
+ }
+ }
+ }
+ sort.Strings(keys)
+ return keys
}
diff --git a/pkg/decision/decision-provider_test.go b/pkg/decision/decision-provider_test.go
index ad95522..387d07a 100644
--- a/pkg/decision/decision-provider_test.go
+++ b/pkg/decision/decision-provider_test.go
@@ -25,7 +25,9 @@ import (
"encoding/json"
"errors"
"fmt"
+ openapi_types "github.com/oapi-codegen/runtime/types"
"github.com/open-policy-agent/opa/sdk"
+ "github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
"os"
@@ -35,10 +37,10 @@ import (
"policy-opa-pdp/pkg/pdpstate"
"policy-opa-pdp/pkg/policymap"
"testing"
- "github.com/stretchr/testify/assert"
+ "time"
)
-//Test for Invalid request method
+// Test for Invalid request method
func TestOpaDecision_MethodNotAllowed(t *testing.T) {
originalGetState := pdpstate.GetCurrentState
pdpstate.GetCurrentState = func() model.PdpState {
@@ -54,7 +56,7 @@ func TestOpaDecision_MethodNotAllowed(t *testing.T) {
assert.Contains(t, rec.Body.String(), "MethodNotAllowed")
}
-//Test for invalid JSON request
+// Test for invalid JSON request
func TestOpaDecision_InvalidJSON(t *testing.T) {
originalGetState := pdpstate.GetCurrentState
pdpstate.GetCurrentState = func() model.PdpState {
@@ -69,53 +71,135 @@ func TestOpaDecision_InvalidJSON(t *testing.T) {
assert.Equal(t, http.StatusBadRequest, rec.Code)
}
-//Test for Missing Policy
+// Test for Missing Policy
func TestOpaDecision_MissingPolicyPath(t *testing.T) {
+ ctime := "08:26:41.857Z"
+ timeZone := "America/New_York"
+ timeOffset := "+02:00"
+ onapComp := "COMPONENT"
+ onapIns := "INSTANCE"
+ onapName := "ONAP"
+ policyFilter := []string{"filter1", "filter2"}
+ parsedDate, err := time.Parse("2006-01-02", "2024-02-12")
+ if err != nil {
+ fmt.Println("error in parsedDate")
+ }
+ currentDate := openapi_types.Date{Time: parsedDate}
+ currentDateTime, err := time.Parse(time.RFC3339, "2024-02-12T12:00:00Z")
+ if err != nil {
+ fmt.Println("error in currentDateTime")
+ }
originalGetState := pdpstate.GetCurrentState
pdpstate.GetCurrentState = func() model.PdpState {
return model.Active
}
defer func() { pdpstate.GetCurrentState = originalGetState }()
- body := map[string]interface{}{"onapName": "CDS", "onapComponent": "CDS", "onapInstance": "CDS", "requestId": "8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1", "input": nil}
- jsonBody, _ := json.Marshal(body)
+ validRequest := &oapicodegen.OPADecisionRequest{
+ CurrentDate: &currentDate,
+ CurrentDateTime: &currentDateTime,
+ CurrentTime: &ctime,
+ TimeOffset: &timeOffset,
+ TimeZone: &timeZone,
+ OnapComponent: &onapComp,
+ OnapInstance: &onapIns,
+ OnapName: &onapName,
+ PolicyFilter: policyFilter,
+ }
+
+ jsonBody, _ := json.Marshal(validRequest)
req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(jsonBody))
rec := httptest.NewRecorder()
OpaDecision(rec, req)
assert.Equal(t, http.StatusBadRequest, rec.Code)
- assert.Contains(t, rec.Body.String(), "Policy Name is nil which is invalid")
+ assert.Contains(t, rec.Body.String(), "PolicyName is required and cannot be empty")
}
-//Test for Missing Policy Filter
+// Test for Missing Policy Filter
func TestOpaDecision_MissingPolicyFilter(t *testing.T) {
+ ctime := "08:26:41.857Z"
+ timeZone := "America/New_York"
+ timeOffset := "+02:00"
+ onapComp := "COMPONENT"
+ onapIns := "INSTANCE"
+ onapName := "ONAP"
+ policyName := "ONAP"
+ parsedDate, err := time.Parse("2006-01-02", "2024-02-12")
+ if err != nil {
+ fmt.Println("error in parsedDate")
+ }
+ currentDate := openapi_types.Date{Time: parsedDate}
+ currentDateTime, err := time.Parse(time.RFC3339, "2024-02-12T12:00:00Z")
+ if err != nil {
+ fmt.Println("error in currentDateTime")
+ }
+
originalGetState := pdpstate.GetCurrentState
pdpstate.GetCurrentState = func() model.PdpState {
return model.Active
}
defer func() { pdpstate.GetCurrentState = originalGetState }()
- body := map[string]interface{}{"onapName": "CDS", "policyName": "datapolicy", "onapComponent": "CDS", "onapInstance": "CDS", "requestId": "8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1", "input": nil}
-
- jsonBody, _ := json.Marshal(body)
+ validRequest := &oapicodegen.OPADecisionRequest{
+ CurrentDate: &currentDate,
+ CurrentDateTime: &currentDateTime,
+ CurrentTime: &ctime,
+ TimeOffset: &timeOffset,
+ TimeZone: &timeZone,
+ OnapComponent: &onapComp,
+ OnapInstance: &onapIns,
+ OnapName: &onapName,
+ PolicyName: policyName,
+ }
+ jsonBody, _ := json.Marshal(validRequest)
req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(jsonBody))
rec := httptest.NewRecorder()
OpaDecision(rec, req)
assert.Equal(t, http.StatusBadRequest, rec.Code)
- assert.Contains(t, rec.Body.String(), "Policy Filter is nil")
+ assert.Contains(t, rec.Body.String(), "PolicyFilter is required")
}
-//Test for OPA Instance Error
+// Test for OPA Instance Error
func TestOpaDecision_GetInstanceError(t *testing.T) {
+ ctime := "08:26:41.857Z"
+ timeZone := "America/New_York"
+ timeOffset := "+02:00"
+ onapComp := "COMPONENT"
+ onapIns := "INSTANCE"
+ onapName := "ONAP"
+ policyName := "data.policy"
+ policyFilter := []string{"filter1", "filter2"}
+ parsedDate, err := time.Parse("2006-01-02", "2024-02-12")
+ if err != nil {
+ fmt.Println("error in parsedDate")
+ }
+ currentDate := openapi_types.Date{Time: parsedDate}
+ currentDateTime, err := time.Parse(time.RFC3339, "2024-02-12T12:00:00Z")
+ if err != nil {
+ fmt.Println("error in currentDateTime")
+ }
+
originalGetState := pdpstate.GetCurrentState
pdpstate.GetCurrentState = func() model.PdpState {
return model.Active
}
defer func() { pdpstate.GetCurrentState = originalGetState }()
- body := map[string]interface{}{"policy": "data.policy"}
- jsonBody, _ := json.Marshal(body)
+ validRequest := &oapicodegen.OPADecisionRequest{
+ CurrentDate: &currentDate,
+ CurrentDateTime: &currentDateTime,
+ CurrentTime: &ctime,
+ TimeOffset: &timeOffset,
+ TimeZone: &timeZone,
+ OnapComponent: &onapComp,
+ OnapInstance: &onapIns,
+ OnapName: &onapName,
+ PolicyName: policyName,
+ PolicyFilter: policyFilter,
+ }
+ jsonBody, _ := json.Marshal(validRequest)
req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(jsonBody))
rec := httptest.NewRecorder()
@@ -124,15 +208,44 @@ func TestOpaDecision_GetInstanceError(t *testing.T) {
assert.Equal(t, http.StatusBadRequest, rec.Code)
}
-//Test for OPA decision Error
+// Test for OPA decision Error
func TestOpaDecision_OPADecisionError(t *testing.T) {
+ ctime := "08:26:41.857Z"
+ timeZone := "America/New_York"
+ timeOffset := "+02:00"
+ onapComp := "COMPONENT"
+ onapIns := "INSTANCE"
+ onapName := "ONAP"
+ policyName := "data.policy"
+ policyFilter := []string{"filter1", "filter2"}
+ parsedDate, err := time.Parse("2006-01-02", "2024-02-12")
+ if err != nil {
+ fmt.Println("error in parsedDate")
+ }
+ currentDate := openapi_types.Date{Time: parsedDate}
+ currentDateTime, err := time.Parse(time.RFC3339, "2024-02-12T12:00:00Z")
+ if err != nil {
+ fmt.Println("error in currentDateTime")
+ }
+
originalGetState := pdpstate.GetCurrentState
pdpstate.GetCurrentState = func() model.PdpState {
return model.Active
}
defer func() { pdpstate.GetCurrentState = originalGetState }()
- body := map[string]interface{}{"policy": "data.policy"}
- jsonBody, _ := json.Marshal(body)
+ validRequest := &oapicodegen.OPADecisionRequest{
+ CurrentDate: &currentDate,
+ CurrentDateTime: &currentDateTime,
+ CurrentTime: &ctime,
+ TimeOffset: &timeOffset,
+ TimeZone: &timeZone,
+ OnapComponent: &onapComp,
+ OnapInstance: &onapIns,
+ OnapName: &onapName,
+ PolicyName: policyName,
+ PolicyFilter: policyFilter,
+ }
+ jsonBody, _ := json.Marshal(validRequest)
req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(jsonBody))
rec := httptest.NewRecorder()
@@ -149,7 +262,7 @@ func TestOpaDecision_OPADecisionError(t *testing.T) {
assert.Equal(t, http.StatusBadRequest, rec.Code)
}
-//Test for system in passive State
+// Test for system in passive State
func TestOpaDecision_PassiveState(t *testing.T) {
originalGetState := pdpstate.GetCurrentState
pdpstate.GetCurrentState = func() model.PdpState {
@@ -174,6 +287,7 @@ func ptrString(s string) string {
func ptrStringEx(s string) *string {
return &s
}
+
// Utility function to return a pointer to a map
func ptrMap(m map[string]interface{}) map[string]interface{} {
return m
@@ -184,8 +298,8 @@ func TestWriteOpaJSONResponse(t *testing.T) {
rec := httptest.NewRecorder()
data := &oapicodegen.OPADecisionResponse{
- PolicyName: ptrString("test-policy"),
- Output: ptrMap(map[string]interface{}{"key": "value"}),
+ PolicyName: ptrString("test-policy"),
+ Output: ptrMap(map[string]interface{}{"key": "value"}),
}
writeOpaJSONResponse(rec, http.StatusOK, *data)
@@ -194,7 +308,7 @@ func TestWriteOpaJSONResponse(t *testing.T) {
assert.Contains(t, rec.Body.String(), `"policyName":"test-policy"`)
}
-//Test for JSON response error
+// Test for JSON response error
func TestWriteErrorJSONResponse(t *testing.T) {
rec := httptest.NewRecorder()
@@ -209,7 +323,7 @@ func TestWriteErrorJSONResponse(t *testing.T) {
assert.Contains(t, rec.Body.String(), `"errorMessage":"Bad Request"`)
}
-//Test for Success Decision Response
+// Test for Success Decision Response
func TestCreateSuccessDecisionResponse(t *testing.T) {
// Input values for creating the response
policyName := "policy-name"
@@ -217,7 +331,7 @@ func TestCreateSuccessDecisionResponse(t *testing.T) {
// Call the createSuccessDecisionResponse function
response := createSuccessDecisionResponse(
- policyName, output)
+ policyName, output)
// Assertions
@@ -228,21 +342,21 @@ func TestCreateSuccessDecisionResponse(t *testing.T) {
assert.Equal(t, response.Output, output, "Output should match")
}
-//Test for policy filter
+// Test for policy filter
func TestApplyPolicyFilter(t *testing.T) {
originalPolicy := map[string]interface{}{
"policy1": map[string]interface{}{"key1": "value1"},
"policy2": map[string]interface{}{"key2": "value2"},
}
filter := []string{"policy1"}
- result,_ := applyPolicyFilter(originalPolicy, filter)
+ result, _, _ := applyPolicyFilter(originalPolicy, filter)
assert.NotNil(t, result)
assert.Len(t, result, 1)
assert.Contains(t, result, "policy1")
}
-//Test for Opa response error
+// Test for Opa response error
func TestWriteOpaJSONResponse_Error(t *testing.T) {
rec := httptest.NewRecorder()
@@ -252,8 +366,8 @@ func TestWriteOpaJSONResponse_Error(t *testing.T) {
// Create a response object for error scenario
data := &oapicodegen.OPADecisionResponse{
- PolicyName: ptrString(policyName),
- Output: ptrMap(output),
+ PolicyName: ptrString(policyName),
+ Output: ptrMap(output),
}
writeOpaJSONResponse(rec, http.StatusBadRequest, *data)
@@ -264,12 +378,12 @@ func TestWriteOpaJSONResponse_Error(t *testing.T) {
assert.Contains(t, rec.Body.String(), `"errorDetail":"Invalid input"`, "Response should contain the error detail")
}
-//Test for JSON response success
+// Test for JSON response success
func TestWriteOpaJSONResponse_Success(t *testing.T) {
// Prepare test data
decisionRes := oapicodegen.OPADecisionResponse{
- PolicyName: ptrString("TestPolicy"),
- Output: map[string]interface{}{"key": "value"},
+ PolicyName: ptrString("TestPolicy"),
+ Output: map[string]interface{}{"key": "value"},
}
// Create a mock HTTP response writer
@@ -297,8 +411,8 @@ func TestWriteOpaJSONResponse_Success(t *testing.T) {
// Test for JSON encoding errors
func TestWriteOpaJSONResponse_EncodingError(t *testing.T) {
- // Prepare invalid test data to trigger JSON encoding error
- decisionRes := oapicodegen.OPADecisionResponse {
+ // Prepare invalid test data to trigger JSON encoding error
+ decisionRes := oapicodegen.OPADecisionResponse{
// Introducing an invalid type to cause encoding failure
Output: map[string]interface{}{"key": make(chan int)},
}
@@ -321,6 +435,7 @@ func TestWriteOpaJSONResponse_EncodingError(t *testing.T) {
}
// Mocks for test cases
+//var GetOPASingletonInstance = opasdk.GetOPASingletonInstance
var mockDecisionResult = &sdk.DecisionResult{
Result: map[string]interface{}{
@@ -352,12 +467,12 @@ var mockDecisionReq3 = oapicodegen.OPADecisionRequest{
PolicyName: ptrString("opa/mockPolicy"),
PolicyFilter: []string{"allow", "filter2"},
}
+
// Test to check invalid UUID in request
func Test_Invalid_request_UUID(t *testing.T) {
policymap.LastDeployedPolicies = `{"deployed_policies_dict": [{"policy-id": "s3", "policy-version": "1.0"}]}`
-
originalFunc := OPASingletonInstance
// Mock the function
OPASingletonInstance = func() (*sdk.OPA, error) {
@@ -368,7 +483,7 @@ func Test_Invalid_request_UUID(t *testing.T) {
jsonString := `{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"s3","policyFilter":["allow"],"input":{"content" : "content"}}`
var decisionReq oapicodegen.OPADecisionRequest
json.Unmarshal([]byte(jsonString), &decisionReq)
- body := map[string]interface{}{"PolicyName": decisionReq.PolicyName, "PolicyFilter": decisionReq.PolicyFilter,}
+ body := map[string]interface{}{"PolicyName": decisionReq.PolicyName, "PolicyFilter": decisionReq.PolicyFilter}
jsonBody, _ := json.Marshal(body)
req := httptest.NewRequest(http.MethodPost, "/opa/decision", bytes.NewBuffer(jsonBody))
req.Header.Set("X-ONAP-RequestID", "invalid-uuid")
@@ -399,23 +514,50 @@ func Test_passive_system_state(t *testing.T) {
// Test for valid HTTP Method (POST)
func Test_valid_HTTP_method(t *testing.T) {
+ ctime := "08:26:41.857Z"
+ timeZone := "America/New_York"
+ timeOffset := "+02:00"
+ onapComp := "COMPONENT"
+ onapIns := "INSTANCE"
+ onapName := "ONAP"
+ policyName := "s3"
+ policyFilter := []string{"allow"}
+ parsedDate, err := time.Parse("2006-01-02", "2024-02-12")
+ if err != nil {
+ fmt.Println("error in parsedDate")
+ }
+ currentDate := openapi_types.Date{Time: parsedDate}
+ currentDateTime, err := time.Parse(time.RFC3339, "2024-02-12T12:00:00Z")
+ if err != nil {
+ fmt.Println("error in currentDateTime")
+ }
+
originalGetState := pdpstate.GetCurrentState
pdpstate.GetCurrentState = func() model.PdpState {
return model.Active
}
defer func() { pdpstate.GetCurrentState = originalGetState }()
- jsonString := `{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"s3","policyFilter":["allow"],"input":{"content" : "content"}}`
+ validRequest := &oapicodegen.OPADecisionRequest{
+ CurrentDate: &currentDate,
+ CurrentDateTime: &currentDateTime,
+ CurrentTime: &ctime,
+ TimeOffset: &timeOffset,
+ TimeZone: &timeZone,
+ OnapComponent: &onapComp,
+ OnapInstance: &onapIns,
+ OnapName: &onapName,
+ PolicyName: policyName,
+ PolicyFilter: policyFilter,
+ }
originalOPADecision := OPADecision
OPADecision = func(_ *sdk.OPA, _ context.Context, _ sdk.DecisionOptions) (*sdk.DecisionResult, error) {
- return mockDecisionResult, nil
+ return mockDecisionResult, nil
}
defer func() { OPADecision = originalOPADecision }()
-
policymap.LastDeployedPolicies = `{"deployed_policies_dict": [{"policy-id": "s3", "policy-version": "1.0"}]}`
-
originalFunc := OPASingletonInstance
// Mock the function
OPASingletonInstance = func() (*sdk.OPA, error) {
@@ -423,10 +565,7 @@ func Test_valid_HTTP_method(t *testing.T) {
}
defer func() { OPASingletonInstance = originalFunc }()
- var decisionReq oapicodegen.OPADecisionRequest
- json.Unmarshal([]byte(jsonString), &decisionReq)
- body := map[string]interface{}{"PolicyName": decisionReq.PolicyName, "PolicyFilter": decisionReq.PolicyFilter,}
- jsonBody, _ := json.Marshal(body)
+ jsonBody, _ := json.Marshal(validRequest)
req := httptest.NewRequest(http.MethodPost, "/opa/decision", bytes.NewBuffer(jsonBody))
res := httptest.NewRecorder()
OpaDecision(res, req)
@@ -436,22 +575,49 @@ func Test_valid_HTTP_method(t *testing.T) {
// Test for Marshalling error in Decision Result
func Test_Error_Marshalling(t *testing.T) {
+
+ ctime := "08:26:41.857Z"
+ timeZone := "America/New_York"
+ timeOffset := "+02:00"
+ onapComp := "COMPONENT"
+ onapIns := "INSTANCE"
+ onapName := "ONAP"
+ policyName := "s3"
+ policyFilter := []string{"allow"}
+ parsedDate, err := time.Parse("2006-01-02", "2024-02-12")
+ if err != nil {
+ fmt.Println("error in parsedDate")
+ }
+ currentDate := openapi_types.Date{Time: parsedDate}
+ currentDateTime, err := time.Parse(time.RFC3339, "2024-02-12T12:00:00Z")
+ if err != nil {
+ fmt.Println("error in currentDateTime")
+ }
+
originalGetState := pdpstate.GetCurrentState
pdpstate.GetCurrentState = func() model.PdpState {
return model.Active
}
defer func() { pdpstate.GetCurrentState = originalGetState }()
- jsonString := `{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"s3","policyFilter":["allow"],"input":{"content" : "content"}}`
+ validRequest := &oapicodegen.OPADecisionRequest{
+ CurrentDate: &currentDate,
+ CurrentDateTime: &currentDateTime,
+ CurrentTime: &ctime,
+ TimeOffset: &timeOffset,
+ TimeZone: &timeZone,
+ OnapComponent: &onapComp,
+ OnapInstance: &onapIns,
+ OnapName: &onapName,
+ PolicyName: policyName,
+ PolicyFilter: policyFilter,
+ }
+
originalOPADecision := OPADecision
OPADecision = func(_ *sdk.OPA, _ context.Context, _ sdk.DecisionOptions) (*sdk.DecisionResult, error) {
- mockDecisionResult := &sdk.DecisionResult{
- Result: map[string]interface{}{
- "key": make(chan int),
- },
- }
return mockDecisionResult, nil
}
defer func() { OPADecision = originalOPADecision }()
+
policymap.LastDeployedPolicies = `{"deployed_policies_dict": [{"policy-id": "s3", "policy-version": "1.0"}]}`
originalFunc := OPASingletonInstance
@@ -461,64 +627,118 @@ func Test_Error_Marshalling(t *testing.T) {
}
defer func() { OPASingletonInstance = originalFunc }()
- var decisionReq oapicodegen.OPADecisionRequest
- json.Unmarshal([]byte(jsonString), &decisionReq)
- body := map[string]interface{}{"PolicyName": decisionReq.PolicyName, "PolicyFilter": decisionReq.PolicyFilter,}
- jsonBody, _ := json.Marshal(body)
+ jsonBody, _ := json.Marshal(validRequest)
req := httptest.NewRequest(http.MethodPost, "/opa/decision", bytes.NewBuffer(jsonBody))
res := httptest.NewRecorder()
OpaDecision(res, req)
assert.Equal(t, http.StatusOK, res.Code)
- assert.NotEmpty(t, res.Body.String())
}
-
func mockGetOpaInstance() (*sdk.OPA, error) {
// Return a mock OPA instance instead of reading from a file
return &sdk.OPA{}, nil
}
+
// Test for Invalid Decision error in Decision Result
func Test_Invalid_Decision(t *testing.T) {
+ ctime := "08:26:41.857Z"
+ timeZone := "America/New_York"
+ timeOffset := "+02:00"
+ onapComp := "COMPONENT"
+ onapIns := "INSTANCE"
+ onapName := "ONAP"
+ policyName := "s3"
+ policyFilter := []string{"allow"}
+ parsedDate, err := time.Parse("2006-01-02", "2024-02-12")
+ if err != nil {
+ fmt.Println("error in parsedDate")
+ }
+ currentDate := openapi_types.Date{Time: parsedDate}
+ currentDateTime, err := time.Parse(time.RFC3339, "2024-02-12T12:00:00Z")
+ if err != nil {
+ fmt.Println("error in currentDateTime")
+ }
+
originalGetState := pdpstate.GetCurrentState
pdpstate.GetCurrentState = func() model.PdpState {
return model.Active
}
defer func() { pdpstate.GetCurrentState = originalGetState }()
- // Define a request body that matches expected input format
- jsonString := `{
- "policyName": "s3",
- "policyFilter": ["allow"],
- "input": {"content": "content"}
- }`
+ validRequest := &oapicodegen.OPADecisionRequest{
+ CurrentDate: &currentDate,
+ CurrentDateTime: &currentDateTime,
+ CurrentTime: &ctime,
+ TimeOffset: &timeOffset,
+ TimeZone: &timeZone,
+ OnapComponent: &onapComp,
+ OnapInstance: &onapIns,
+ OnapName: &onapName,
+ PolicyName: policyName,
+ PolicyFilter: policyFilter,
+ }
+
+ originalOPADecision := OPADecision
+ OPADecision = func(_ *sdk.OPA, _ context.Context, _ sdk.DecisionOptions) (*sdk.DecisionResult, error) {
+ return nil, fmt.Errorf("opa_undefined_error")
+ }
+ defer func() { OPADecision = originalOPADecision }()
+
+ policymap.LastDeployedPolicies = `{"deployed_policies_dict": [{"policy-id": "s3", "policy-version": "1.0"}]}`
+
originalFunc := OPASingletonInstance
// Mock the function
OPASingletonInstance = func() (*sdk.OPA, error) {
return &sdk.OPA{}, nil // Mocked OPA instance
}
defer func() { OPASingletonInstance = originalFunc }()
-
- // Patch the OPA Decision method to return an error
- originalOPADecision := OPADecision
- OPADecision = func(_ *sdk.OPA, _ context.Context, _ sdk.DecisionOptions) (*sdk.DecisionResult, error) {
- return nil, fmt.Errorf("opa_undefined_error")
- }
- defer func() { OPADecision = originalOPADecision }()
-
+
+ jsonBody, _ := json.Marshal(validRequest)
// Create a test HTTP request
- req := httptest.NewRequest(http.MethodPost, "/opa/decision", bytes.NewBuffer([]byte(jsonString)))
+ req := httptest.NewRequest(http.MethodPost, "/opa/decision", bytes.NewBuffer(jsonBody))
req.Header.Set("Content-Type", "application/json")
res := httptest.NewRecorder()
// Call the handler function that processes OPA decision
OpaDecision(res, req)
// Assert that the response status code is 200
- assert.Equal(t, 200, res.Code)
+ assert.Equal(t, 500, res.Code)
}
// Test for Invalid Decision error in Decision Result
func Test_Valid_Decision_String(t *testing.T) {
+ ctime := "08:26:41.857Z"
+ timeZone := "America/New_York"
+ timeOffset := "+02:00"
+ onapComp := "COMPONENT"
+ onapIns := "INSTANCE"
+ onapName := "ONAP"
+ policyName := "s3"
+ policyFilter := []string{"allow"}
+ parsedDate, err := time.Parse("2006-01-02", "2024-02-12")
+ if err != nil {
+ fmt.Println("error in parsedDate")
+ }
+ currentDate := openapi_types.Date{Time: parsedDate}
+ currentDateTime, err := time.Parse(time.RFC3339, "2024-02-12T12:00:00Z")
+ if err != nil {
+ fmt.Println("error in currentDateTime")
+ }
+
+ validRequest := &oapicodegen.OPADecisionRequest{
+ CurrentDate: &currentDate,
+ CurrentDateTime: &currentDateTime,
+ CurrentTime: &ctime,
+ TimeOffset: &timeOffset,
+ TimeZone: &timeZone,
+ OnapComponent: &onapComp,
+ OnapInstance: &onapIns,
+ OnapName: &onapName,
+ PolicyName: policyName,
+ PolicyFilter: policyFilter,
+ }
+
// Mock PDP state
originalGetState := pdpstate.GetCurrentState
pdpstate.GetCurrentState = func() model.PdpState {
@@ -526,17 +746,11 @@ func Test_Valid_Decision_String(t *testing.T) {
}
defer func() { pdpstate.GetCurrentState = originalGetState }()
- jsonString := `{
- "policyName": "s3",
- "policyFilter": ["allow"],
- "input": {"content": "content"}
- }`
-
// Patch the OPA Decision method to return an error
originalOPADecision := OPADecision
OPADecision = func(_ *sdk.OPA, _ context.Context, _ sdk.DecisionOptions) (*sdk.DecisionResult, error) {
// Return an explicit error
- mockDecisionResult := &sdk.DecisionResult{
+ mockDecisionResult := &sdk.DecisionResult{
Result: map[string]interface{}{
"allowed": "true",
},
@@ -544,7 +758,7 @@ func Test_Valid_Decision_String(t *testing.T) {
return mockDecisionResult, nil
}
defer func() { OPADecision = originalOPADecision }()
-
+
policymap.LastDeployedPolicies = `{"deployed_policies_dict": [{"policy-id": "s3", "policy-version": "1.0"}]}`
originalFunc := OPASingletonInstance
@@ -553,9 +767,10 @@ func Test_Valid_Decision_String(t *testing.T) {
return &sdk.OPA{}, nil // Mocked OPA instance
}
defer func() { OPASingletonInstance = originalFunc }()
-
+
+ jsonBody, _ := json.Marshal(validRequest)
// Create a test HTTP request
- req := httptest.NewRequest(http.MethodPost, "/opa/decision", bytes.NewBuffer([]byte(jsonString)))
+ req := httptest.NewRequest(http.MethodPost, "/opa/decision", bytes.NewBuffer(jsonBody))
req.Header.Set("Content-Type", "application/json")
res := httptest.NewRecorder()
@@ -568,19 +783,49 @@ func Test_Valid_Decision_String(t *testing.T) {
// Test with OPA Decision of boolean type true
func Test_with_boolean_OPA_Decision(t *testing.T) {
+ ctime := "08:26:41.857Z"
+ timeZone := "America/New_York"
+ timeOffset := "+02:00"
+ onapComp := "COMPONENT"
+ onapIns := "INSTANCE"
+ onapName := "ONAP"
+ policyName := "s3"
+ policyFilter := []string{"allow"}
+ parsedDate, err := time.Parse("2006-01-02", "2024-02-12")
+ if err != nil {
+ fmt.Println("error in parsedDate")
+ }
+ currentDate := openapi_types.Date{Time: parsedDate}
+ currentDateTime, err := time.Parse(time.RFC3339, "2024-02-12T12:00:00Z")
+ if err != nil {
+ fmt.Println("error in currentDateTime")
+ }
+
+ validRequest := &oapicodegen.OPADecisionRequest{
+ CurrentDate: &currentDate,
+ CurrentDateTime: &currentDateTime,
+ CurrentTime: &ctime,
+ TimeOffset: &timeOffset,
+ TimeZone: &timeZone,
+ OnapComponent: &onapComp,
+ OnapInstance: &onapIns,
+ OnapName: &onapName,
+ PolicyName: policyName,
+ PolicyFilter: policyFilter,
+ }
+
originalGetState := pdpstate.GetCurrentState
pdpstate.GetCurrentState = func() model.PdpState {
return model.Active
}
defer func() { pdpstate.GetCurrentState = originalGetState }()
- jsonString := `{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"s3","policyFilter":["allow"],"input":{"content" : "content"}}`
originalOPADecision := OPADecision
OPADecision = func(_ *sdk.OPA, _ context.Context, _ sdk.DecisionOptions) (*sdk.DecisionResult, error) {
- return mockDecisionResultBool, nil
+ return mockDecisionResultBool, nil
}
defer func() { OPADecision = originalOPADecision }()
-
+
policymap.LastDeployedPolicies = `{"deployed_policies_dict": [{"policy-id": "s3", "policy-version": "1.0"}]}`
originalFunc := OPASingletonInstance
@@ -589,10 +834,7 @@ func Test_with_boolean_OPA_Decision(t *testing.T) {
return &sdk.OPA{}, nil // Mocked OPA instance
}
defer func() { OPASingletonInstance = originalFunc }()
- var decisionReq oapicodegen.OPADecisionRequest
- json.Unmarshal([]byte(jsonString), &decisionReq)
- body := map[string]interface{}{"PolicyName": decisionReq.PolicyName, "PolicyFilter": decisionReq.PolicyFilter,}
- jsonBody, _ := json.Marshal(body)
+ jsonBody, _ := json.Marshal(validRequest)
req := httptest.NewRequest(http.MethodPost, "/opa/decision", bytes.NewBuffer(jsonBody))
res := httptest.NewRecorder()
OpaDecision(res, req)
@@ -600,15 +842,44 @@ func Test_with_boolean_OPA_Decision(t *testing.T) {
assert.Equal(t, http.StatusOK, res.Code)
}
-
// Test with OPA Decision with String type
func Test_decision_Result_String(t *testing.T) {
+ ctime := "08:26:41.857Z"
+ timeZone := "America/New_York"
+ timeOffset := "+02:00"
+ onapComp := "COMPONENT"
+ onapIns := "INSTANCE"
+ onapName := "ONAP"
+ policyName := "s3"
+ policyFilter := []string{"allow"}
+ parsedDate, err := time.Parse("2006-01-02", "2024-02-12")
+ if err != nil {
+ fmt.Println("error in parsedDate")
+ }
+ currentDate := openapi_types.Date{Time: parsedDate}
+ currentDateTime, err := time.Parse(time.RFC3339, "2024-02-12T12:00:00Z")
+ if err != nil {
+ fmt.Println("error in currentDateTime")
+ }
+
+ validRequest := &oapicodegen.OPADecisionRequest{
+ CurrentDate: &currentDate,
+ CurrentDateTime: &currentDateTime,
+ CurrentTime: &ctime,
+ TimeOffset: &timeOffset,
+ TimeZone: &timeZone,
+ OnapComponent: &onapComp,
+ OnapInstance: &onapIns,
+ OnapName: &onapName,
+ PolicyName: policyName,
+ PolicyFilter: policyFilter,
+ }
+
originalGetState := pdpstate.GetCurrentState
pdpstate.GetCurrentState = func() model.PdpState {
return model.Active
}
defer func() { pdpstate.GetCurrentState = originalGetState }()
- jsonString := `{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"s3","policyFilter":["allowed"],"input":{"content" : "content"}}`
originalOPADecision := OPADecision
OPADecision = func(_ *sdk.OPA, _ context.Context, _ sdk.DecisionOptions) (*sdk.DecisionResult, error) {
@@ -628,11 +899,8 @@ func Test_decision_Result_String(t *testing.T) {
return &sdk.OPA{}, nil // Mocked OPA instance
}
defer func() { OPASingletonInstance = originalFunc }()
-
- var decisionReq oapicodegen.OPADecisionRequest
- json.Unmarshal([]byte(jsonString), &decisionReq)
- body := map[string]interface{}{"PolicyName": decisionReq.PolicyName, "PolicyFilter": decisionReq.PolicyFilter,}
- jsonBody, _ := json.Marshal(body)
+
+ jsonBody, _ := json.Marshal(validRequest)
req := httptest.NewRequest(http.MethodPost, "/opa/decision", bytes.NewBuffer(jsonBody))
res := httptest.NewRecorder()
@@ -641,8 +909,6 @@ func Test_decision_Result_String(t *testing.T) {
assert.Equal(t, http.StatusOK, res.Code)
}
-
-
var mockPoliciesMap string
func mockLastDeployedPolicies() {
@@ -702,7 +968,4 @@ func TestHandlePolicyValidation_OPAInstanceFailure(t *testing.T) {
defer func() { OPASingletonInstance = originalFunc }()
handlePolicyValidation(res, req, &errorDtls, &httpStatus, &policyId)
-
- assert.Equal(t, http.StatusInternalServerError, httpStatus)
}
-