waitForServerFunc = waitForServer
initializeOPAFunc = initializeOPA
startKafkaConsAndProdFunc = startKafkaConsAndProd
- registerPDPFunc = registerPDP
handleMessagesFunc = handleMessages
handleShutdownFunc = handleShutdown
)
}()
}
-// register pdp with PAP
-func registerPDP(sender publisher.PdpStatusSender) bool {
- if err := publisher.SendPdpPapRegistration(sender); err != nil {
- log.Warnf("Failed PDP PAP registration: %v", err)
- return false
- }
- log.Debugf("PDP PAP registration successful")
- return true
-}
-
// Register Handlers
func initializeHandlers() {
h.RegisterHandlers()
return nil // no error expected
}
- registerPDPFunc = func(sender publisher.PdpStatusSender) bool {
- // Simulate the registration logic here
- return false // Simulate successful registration
- }
-
handleMessagesFunc = func(ctx context.Context, kc *kafkacomm.KafkaConsumer, sender *publisher.RealPdpStatusSender) {
return
}
initializeHandlers()
}
-// Test to simulate the successful registration of a PDP
-func TestRegisterPDP_Success(t *testing.T) {
- mockSender := new(MockPdpStatusSender)
- mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
-
- result := registerPDP(mockSender)
-
- assert.True(t, result)
- mockSender.AssertExpectations(t)
-}
-
-// Test to simulate a failure scenario during the registration of a PDP.
-func TestRegisterPDP_Failure(t *testing.T) {
- mockSender := new(MockPdpStatusSender)
- mockSender.On("SendPdpStatus", mock.Anything).Return(assert.AnError)
-
- result := registerPDP(mockSender)
-
- assert.False(t, result)
- mockSender.AssertExpectations(t)
-}
-
// Test to verify that the HTTP Server starts successfully and can be shut down gracefully.
func TestStartAndShutDownHTTPServer(t *testing.T) {
testServer := startHTTPServer()
// Variables:
//
-// LogFilePath - The file path for the log file.
-// LogMaxSize - The maximum size of the log file in megabytes.
-// LogMaxBackups - The maximum number of backup log files to retain.
-// OpasdkConfigPath - The file path for the OPA SDK configuration.
-// Opa - The file path for the OPA binary.
-// BuildBundle - The command to build the bundle.
-// Policies - The directory path for policies.
-// Data - The directory path for policy data.
-// DataNode - The directory path for policy data with node.
-// Output - The output flag for bundle commands.
-// BundleTarGz - The name of the bundle tar.gz file.
-// BundleTarGzFile - The file path for the bundle tar.gz file.
-// PdpGroup - The default PDP group.
-// PdpType - The type of PDP.
-// ServerPort - The port on which the server listens.
-// SERVER_WAIT_UP_TIME - The time to wait for the server to be up, in seconds.
-// ShutdownWaitTime - The time to wait for the server to shut down, in seconds.
-// V1Compatible - The flag for v1 compatibility.
-// LatestVersion - The Version set in response for decision
-// MinorVersion - The Minor version set in response header for decision
-// PatchVersion - The Patch Version set in response header for decison
-// OpaPdpUrl - The Healthcheck url for response
-// HealtCheckStatus - The bool flag for Healthy field in HealtCheck response
-// OkCode - The Code for HealthCheck response
-// HealthCheckMessage - The Healtcheck Message
-// SingleHierarchy - The Counter indicates the length of datakey path
-// DefaultHeartbeatMS - The default interval for heartbeat signals in milliseconds.
+// LogFilePath - The file path for the log file.
+// LogMaxSize - The maximum size of the log file in megabytes.
+// LogMaxBackups - The maximum number of backup log files to retain.
+// OpasdkConfigPath - The file path for the OPA SDK configuration.
+// Opa - The file path for the OPA binary.
+// BuildBundle - The command to build the bundle.
+// Policies - The directory path for policies.
+// Data - The directory path for policy data.
+// DataNode - The directory path for policy data with node.
+// Output - The output flag for bundle commands.
+// BundleTarGz - The name of the bundle tar.gz file.
+// BundleTarGzFile - The file path for the bundle tar.gz file.
+// PdpGroup - The default PDP group.
+// PdpType - The type of PDP.
+// ServerPort - The port on which the server listens.
+// ServerWaitUpTime - The time to wait for the server to be up, in seconds.
+// ShutdownWaitTime - The time to wait for the server to shut down, in seconds.
+// V1Compatible - The flag for v1 compatibility.
+// LatestVersion - The Version set in response for decision
+// MinorVersion - The Minor version set in response header for decision
+// PatchVersion - The Patch Version set in response header for decison
+// OpaPdpUrl - The Healthcheck url for response
+// HealtCheckStatus - The bool flag for Healthy field in HealtCheck response
+// OkCode - The Code for HealthCheck response
+// HealthCheckMessage - The Healtcheck Message
+// DefaultHeartbeatMS - The default interval for heartbeat signals in milliseconds.
+// SingleHierarchy - The Counter indicates the length of datakey path
+// PolicyVersion - constant declared for policy-version
+// PolicyID - constant declared for policy-id
+// RequestId - constant declared for ONAP Request-ID
+// MaxOutputResponseLength - constant declared for maximum length of output in response message
var (
LogFilePath = "/var/logs/logs.log"
LogMaxSize = 10
BundleTarGz = "bundle.tar.gz"
BundleTarGzFile = "/app/bundles/bundle.tar.gz"
PdpGroup = "opaGroup"
- //This is a workaround as currently opa-pdp is not defined in the PapDB defaultGroup configuration and creating it manually overrides the existing configuration, so currently PdpGroup is opaGroup and it will be changed to defaultGroup once added in the configuration.
- PdpType = "opa"
- ServerPort = ":8282"
- ServerWaitUpTime = 5
- ShutdownWaitTime = 5
+ PdpType = "opa"
+ ServerPort = ":8282"
+ ServerWaitUpTime = 5
+ ShutdownWaitTime = 5
V1Compatible = "--v1-compatible"
- LatestVersion = "1.0.0"
- MinorVersion = "0"
- PatchVersion = "0"
- OpaPdpUrl = "self"
- HealtCheckStatus = true
- OkCode = int32(200)
- HealthCheckMessage = "alive"
- SingleHierarchy = 4
- DefaultHeartbeatMS = 60000
+ LatestVersion = "1.0.0"
+ MinorVersion = "0"
+ PatchVersion = "0"
+ OpaPdpUrl = "self"
+ HealtCheckStatus = true
+ OkCode = int32(200)
+ HealthCheckMessage = "alive"
+ DefaultHeartbeatMS = 60000
+ SingleHierarchy = 4
+ PolicyVersion = "policy-version"
+ PolicyId = "policy-id"
+ RequestId = "X-ONAP-RequestID"
+ MaxOutputResponseLength = 200
)
import (
"context"
"encoding/json"
+ "errors"
"fmt"
"github.com/google/uuid"
openapi_types "github.com/oapi-codegen/runtime/types"
"strings"
)
+type (
+ checkIfPolicyAlreadyExistsFunc func(policyId string) bool
+)
+
var (
- addOp storage.PatchOp = 0
- removeOp storage.PatchOp = 1
- replaceOp storage.PatchOp = 2
+ addOp storage.PatchOp = 0
+ removeOp storage.PatchOp = 1
+ replaceOp storage.PatchOp = 2
+ checkIfPolicyAlreadyExistsVar checkIfPolicyAlreadyExistsFunc = policymap.CheckIfPolicyAlreadyExists
+ getPolicyByIDVar = getPolicyByID
+ extractPatchInfoVar = extractPatchInfo
)
// creates a response code map to OPADataUpdateResponse
data := requestBody.Data
log.Infof("data : %s", data)
policyId := requestBody.PolicyName
+ if policyId == nil {
+ errMsg := "Policy Id is nil"
+ sendErrorResponse(res, errMsg, http.StatusBadRequest)
+ return
+ }
log.Infof("policy name : %s", *policyId)
isExists := policymap.CheckIfPolicyAlreadyExists(*policyId)
if !isExists {
return
}
- // Checking if the data operation is performed for a deployed policy with policymap.CheckIfPolicyAlreadyExists and getPolicyByID
- // if a match is found, we will join the url path with dots and check for the data key from the policiesMap whether utl path is a
- // prefix of data key. we will proceed for Patch Operation if this matches, else return error
- if len(dirParts) > 0 && dirParts[0] == "" {
- dirParts = dirParts[1:]
- }
- finalDirParts := strings.Join(dirParts, ".")
-
- policiesMap := policymap.LastDeployedPolicies
+ matchFound := validatePolicyDataPathMatched(dirParts, *policyId, res)
- matchedPolicy, err := getPolicyByID(policiesMap, *policyId)
- if err != nil {
- sendErrorResponse(res, err.Error(), http.StatusBadRequest)
- log.Errorf(err.Error())
- return
- }
-
- log.Infof("Matched policy: %+v", matchedPolicy)
-
- // Check if finalDirParts starts with any data key
- matchFound := false
- for _, dataKey := range matchedPolicy.Data {
- if strings.HasPrefix(finalDirParts, dataKey) {
- matchFound = true
- break
+ if matchFound {
+ if err := patchData(dataDir, data, res); err != nil {
+ // Handle the error, for example, log it or return an appropriate response
+ log.Errorf("Error encoding JSON response: %s", err)
}
}
-
- if !matchFound {
- errMsg := fmt.Sprintf("Dynamic Data add/replace/remove for policy '%s' expected under url path '%v'", *policyId, matchedPolicy.Data)
- sendErrorResponse(res, errMsg, http.StatusBadRequest)
- log.Errorf(errMsg)
- return
- }
-
- if err := patchData(dataDir, data, res); err != nil {
- // Handle the error, for example, log it or return an appropriate response
- log.Errorf("Error encoding JSON response: %s", err)
- }
}
}
}
}
-func extractPatchInfo(res http.ResponseWriter, ops *[]map[string]interface{}, root string) (result []opasdk.PatchImpl) {
+func extractPatchInfo(res http.ResponseWriter, ops *[]map[string]interface{}, root string) ([]opasdk.PatchImpl, error) {
+ var result []opasdk.PatchImpl
for _, op := range *ops {
- // Extract the operation, path, and value from the map
+
optypeString, opTypeErr := op["op"].(string)
if !opTypeErr {
opTypeErrMsg := "Error in getting op type. Op type is not given in request body"
sendErrorResponse(res, opTypeErrMsg, http.StatusInternalServerError)
log.Errorf(opTypeErrMsg)
- return nil
+ return nil, fmt.Errorf("Error in getting op type. Op type is not given in request body")
}
- opType := getOperationType(optypeString, res)
+ opType, err := getOperationType(optypeString, res)
+ if err != nil {
+ log.Warnf("Error in getting opType: %v", err)
+ return nil, fmt.Errorf("Error in getting operation type")
+ }
if opType == nil {
- return nil
+ return nil, fmt.Errorf("Error in getting operation Type as opType is Missing")
}
+
impl := opasdk.PatchImpl{
Op: *opType,
}
var value interface{}
- var valueErr bool
// PATCH request with add or replace opType, MUST contain a "value" member whose content specifies the value to be added / replaced. For remove opType, value does not required
if optypeString == "add" || optypeString == "replace" {
- value, valueErr = op["value"]
- if !valueErr || isEmpty(value) {
- valueErrMsg := "Error in getting data value. Value is not given in request body"
- sendErrorResponse(res, valueErrMsg, http.StatusInternalServerError)
- log.Errorf(valueErrMsg)
- return nil
+ value, err = getPatchValue(op, res)
+ if err != nil {
+ return nil, fmt.Errorf("Error in gatting Value, Value not found")
}
}
impl.Value = value
-
- opPath, opPathErr := op["path"].(string)
- if !opPathErr || len(opPath) == 0 {
- opPathErrMsg := "Error in getting data path. Path is not given in request body"
- sendErrorResponse(res, opPathErrMsg, http.StatusInternalServerError)
- log.Errorf(opPathErrMsg)
- return nil
- }
- storagePath := constructPath(opPath, optypeString, root, res)
+ storagePath := constructOpStoragePath(op, root, res)
if storagePath == nil {
- return nil
+ return nil, fmt.Errorf("Failed to construct op Storage Path")
}
impl.Path = storagePath
result = append(result, impl)
}
- //log.Debugf("result : %s", result)
- return result
+ return result, nil
+}
+
+func getPatchValue(op map[string]interface{}, res http.ResponseWriter) (interface{}, error) {
+ var value interface{}
+ var valueErr bool
+ value, valueErr = op["value"]
+ if !valueErr || isEmpty(value) {
+ valueErrMsg := "Error in getting data value. Value is not given in request body"
+ sendErrorResponse(res, valueErrMsg, http.StatusInternalServerError)
+ log.Errorf(valueErrMsg)
+ return nil, fmt.Errorf("Error in getting data value. Value is not given in request body")
+ }
+ return value, nil
}
func isEmpty(data interface{}) bool {
return storagePath
}
-func getOperationType(opType string, res http.ResponseWriter) *storage.PatchOp {
+func validatePolicyDataPathMatched(dirParts []string, policyId string, res http.ResponseWriter) bool {
+ matchFound := false
+ // Check if all dirParts exist in the matched policy's data key
+ log.Debugf("dirParts : %s", dirParts)
+ if len(dirParts) > 0 && dirParts[0] == "" {
+ dirParts = dirParts[1:]
+ }
+ finalDirParts := strings.Join(dirParts, ".")
+ policiesMap := policymap.LastDeployedPolicies
+ matchedPolicy, err := getPolicyByIDVar(policiesMap, policyId)
+ if err != nil {
+ sendErrorResponse(res, err.Error(), http.StatusBadRequest)
+ log.Errorf("Error getting Policy By Id: %v", err.Error())
+ return matchFound
+ }
+
+ log.Infof("Matched policy: %+v", matchedPolicy)
+
+ // Check if finalDirParts starts with any data key
+ for _, dataKey := range matchedPolicy.Data {
+ if strings.HasPrefix(finalDirParts, dataKey) {
+ matchFound = true
+ break
+ }
+ }
+ if !matchFound {
+ errMsg := fmt.Sprintf("Dynamic Data add/replace/remove for policy '%s' expected under url path '%v'", policyId, matchedPolicy.Data)
+ sendErrorResponse(res, errMsg, http.StatusBadRequest)
+ log.Errorf(errMsg)
+ return false
+ }
+
+ return matchFound
+}
+
+func constructOpStoragePath(op map[string]interface{}, root string, res http.ResponseWriter) storage.Path {
+ opPath, opPathErr := op["path"].(string)
+ if !opPathErr || len(opPath) == 0 {
+ opPathErrMsg := "Error in getting data path. Path is not given in request body"
+ sendErrorResponse(res, opPathErrMsg, http.StatusInternalServerError)
+ log.Errorf(opPathErrMsg)
+ return nil
+ }
+ optypeString := op["op"].(string)
+ storagePath := constructPath(opPath, optypeString, root, res)
+ return storagePath
+}
+
+func getOperationType(opType string, res http.ResponseWriter) (*storage.PatchOp, error) {
+
var op *storage.PatchOp
switch opType {
case "add":
errMsg := "Error in getting op type : Invalid operation type (" + opType + ") is used. Only add, remove and replace operation types are supported"
sendErrorResponse(res, errMsg, http.StatusBadRequest)
log.Errorf(errMsg)
- return nil
+ return nil, errors.New(errMsg)
}
}
- return op
+ return op, nil
}
type NewOpaSDKPatchFunc func(ctx context.Context, patches []opasdk.PatchImpl) error
func patchData(root string, ops *[]map[string]interface{}, res http.ResponseWriter) (err error) {
root = "/" + strings.Trim(root, "/")
- patchInfos := extractPatchInfo(res, ops, root)
+ patchInfos, err := extractPatchInfoVar(res, ops, root)
+ if err != nil {
+ log.Warnf("Failed to extarct Patch Info")
+ return err
+ }
if patchInfos != nil {
patchErr := NewOpaSDKPatch(context.Background(), patchInfos)
errMsg := "Error in updating data - " + patchErr.Error()
sendErrorResponse(res, errMsg, errCode)
log.Errorf(errMsg)
- return
+ return patchErr
}
log.Infof("Updated the data in the corresponding path successfully\n")
res.WriteHeader(http.StatusNoContent)
}
func constructResponseHeader(res http.ResponseWriter, req *http.Request) {
- requestId := req.Header.Get("X-ONAP-RequestID")
+ requestId := req.Header.Get(consts.RequestId)
var parsedUUID *uuid.UUID
var decisionParams *oapicodegen.DecisionParams
decisionParams = &oapicodegen.DecisionParams{
XONAPRequestID: (*openapi_types.UUID)(parsedUUID),
}
- res.Header().Set("X-ONAP-RequestID", decisionParams.XONAPRequestID.String())
+ res.Header().Set(consts.RequestId, decisionParams.XONAPRequestID.String())
}
} else {
requestId = "Unknown"
- res.Header().Set("X-ONAP-RequestID", requestId)
+ res.Header().Set(consts.RequestId, requestId)
}
res.Header().Set("X-LatestVersion", consts.LatestVersion)
"net/http/httptest"
"policy-opa-pdp/pkg/model/oapicodegen"
"policy-opa-pdp/pkg/opasdk"
+ "policy-opa-pdp/pkg/policymap"
"strings"
"testing"
"time"
res := httptest.NewRecorder()
result := patchData(root, &data, res)
assert.Equal(t, http.StatusNotFound, res.Code)
- assert.Nil(t, result)
+ assert.Error(t, result)
}
func Test_extractPatchInfo_OPTypefail(t *testing.T) {
opType string
expectsNil bool
}{
- {"Valid opType", "add", false},
- {"Valid opType", "remove", false},
- {"Valid opType", "replace", false},
+ {"Valid opType - add", "add", false},
+ {"Valid opType - remove", "remove", false},
+ {"Valid opType - replace", "replace", false},
{"Invalid opType", "try", true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
res := httptest.NewRecorder()
- result := getOperationType(tt.opType, res)
+ result, err := getOperationType(tt.opType, res)
+
if tt.expectsNil {
assert.Nil(t, result)
+ assert.Error(t, err)
} else {
assert.NotNil(t, result)
+ assert.NoError(t, err)
}
})
}
})
}
}
+
+// Sample JSON data for testing
+const samplePoliciesJSON = `
+{
+ "deployed_policies_dict": [
+ {
+ "data": ["data1", "data2"],
+ "policy": ["rule1", "rule2"],
+ "policy-id": "policy123",
+ "policy-version": "v1.0"
+ },
+ {
+ "data": ["data3"],
+ "policy": ["rule3"],
+ "policy-id": "policy456",
+ "policy-version": "v2.0"
+ }
+ ]
+}`
+
+// Test function for getPolicyByID
+func TestGetPolicyByID(t *testing.T) {
+ tests := []struct {
+ name string
+ policiesJSON string
+ policyID string
+ expectError bool
+ expectedData *Policy
+ }{
+ {
+ name: "Policy Exists",
+ policiesJSON: samplePoliciesJSON,
+ policyID: "policy123",
+ expectError: false,
+ expectedData: &Policy{
+ Data: []string{"data1", "data2"},
+ Policy: []string{"rule1", "rule2"},
+ PolicyID: "policy123",
+ PolicyVersion: "v1.0",
+ },
+ },
+ {
+ name: "Policy Not Found",
+ policiesJSON: samplePoliciesJSON,
+ policyID: "policy999",
+ expectError: true,
+ expectedData: nil,
+ },
+ {
+ name: "Invalid JSON Input",
+ policiesJSON: `{ invalid json }`, // Malformed JSON
+ policyID: "policy123",
+ expectError: true,
+ expectedData: nil,
+ },
+ {
+ name: "Empty JSON Input",
+ policiesJSON: `{ "deployed_policies_dict": [] }`, // No policies
+ policyID: "policy123",
+ expectError: true,
+ expectedData: nil,
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ policy, err := getPolicyByID(tc.policiesJSON, tc.policyID)
+
+ if tc.expectError {
+ if err == nil {
+ t.Errorf("Expected error, but got none")
+ }
+ } else {
+ if err != nil {
+ t.Errorf("Unexpected error: %v", err)
+ }
+ if policy == nil {
+ t.Fatalf("Expected policy, but got nil")
+ }
+ // Validate policy fields
+ if policy.PolicyID != tc.expectedData.PolicyID ||
+ policy.PolicyVersion != tc.expectedData.PolicyVersion ||
+ !equalSlices(policy.Data, tc.expectedData.Data) ||
+ !equalSlices(policy.Policy, tc.expectedData.Policy) {
+ t.Errorf("Policy mismatch: got %+v, expected %+v", policy, tc.expectedData)
+ }
+ }
+ })
+ }
+}
+
+// Helper function to compare string slices
+func equalSlices(a, b []string) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i := range a {
+ if a[i] != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+func TestIsEmpty(t *testing.T) {
+ tests := []struct {
+ name string
+ input interface{}
+ expected bool
+ }{
+ {"Nil Value", nil, true},
+ {"Empty String", "", true},
+ {"Non-Empty String", "hello", false},
+ {"Empty Slice", []interface{}{}, true},
+ {"Non-Empty Slice", []interface{}{1, 2, 3}, false},
+ {"Empty Map", map[string]interface{}{}, true},
+ {"Non-Empty Map", map[string]interface{}{"key": "value"}, false},
+ {"Empty Byte Slice", []byte{}, true},
+ {"Non-Empty Byte Slice", []byte("data"), false},
+ {"Zero Integer", 0, true},
+ {"Non-Zero Integer", 10, false},
+ {"Zero Float", 0.0, true},
+ {"Non-Zero Float", 3.14, false},
+ {"Non-Zero Unsigned Integer", uint(5), false},
+ {"Boolean False", false, true},
+ {"Boolean True", true, false},
+ {"Unsupported Type (Struct)", struct{}{}, false}, // Not considered empty
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ result := isEmpty(tc.input)
+ if result != tc.expected {
+ t.Errorf("isEmpty(%v) = %v; want %v", tc.input, result, tc.expected)
+ }
+ })
+ }
+}
+
+func TestPatchHandler_EmptyDataField(t *testing.T) {
+ ctime := "08:26:41"
+ timeZone := "America/New_York"
+ timeOffset := "+02:00"
+ onapComp := "COMPONENT"
+ onapIns := "INSTANCE"
+ onapName := "ONAP"
+ policyName := "TestPolicy"
+
+ 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")
+ }
+
+ var data []map[string]interface{} // Empty data field (to trigger validation)
+
+ invalidRequest := &oapicodegen.OPADataUpdateRequest{
+ CurrentDate: ¤tDate,
+ CurrentDateTime: ¤tDateTime,
+ CurrentTime: &ctime,
+ TimeOffset: &timeOffset,
+ TimeZone: &timeZone,
+ OnapComponent: &onapComp,
+ OnapInstance: &onapIns,
+ OnapName: &onapName,
+ PolicyName: &policyName,
+ Data: &data, // Empty data
+ }
+
+ // Marshal the request to JSON
+ requestBody, err := json.Marshal(invalidRequest)
+ if err != nil {
+ panic(err)
+ }
+
+ req := httptest.NewRequest("PATCH", "/policy/pdpo/v1/data/valid/path", bytes.NewReader(requestBody))
+ res := httptest.NewRecorder()
+
+ patchHandler(res, req)
+
+ assert.Equal(t, http.StatusBadRequest, res.Code)
+ assert.Contains(t, res.Body.String(), "Data is required and cannot be empty")
+}
+
+func Test_GetPolicyByIDFunc_Success(t *testing.T) {
+ // Mock policy data
+ policyID := "test-policy"
+ dirParts := []string{"", "some", "path"} // First part is empty, should be removed
+ expectedDirParts := "some.path" // Expected after cleaning
+
+ policiesMap := map[string]Policy{
+ policyID: {
+ PolicyID: policyID,
+ Data: []string{"some.path"},
+ },
+ }
+
+ // Mock function to return the policy
+ mockGetPolicyByIDFunc := func(policies map[string]Policy, id string) (Policy, error) {
+ policy, exists := policies[id]
+ if !exists {
+ return Policy{}, errors.New("policy not found")
+ }
+ return policy, nil
+ }
+
+ // Simulating HTTP request and response recorder
+ // req := httptest.NewRequest("GET", "/policy/test-policy", nil)
+ res := httptest.NewRecorder()
+
+ // Processing dirParts
+ fmt.Println("dirParts before:", dirParts)
+ if len(dirParts) > 0 && dirParts[0] == "" {
+ dirParts = dirParts[1:] // Remove first empty element
+ }
+ finalDirParts := strings.Join(dirParts, ".")
+
+ // Ensure `dirParts` are cleaned correctly
+ assert.Equal(t, expectedDirParts, finalDirParts)
+
+ // Fetch policy
+ matchedPolicy, err := mockGetPolicyByIDFunc(policiesMap, policyID)
+ if err != nil {
+ sendErrorResponse(res, err.Error(), http.StatusBadRequest)
+ return
+ }
+
+ // Ensure correct policy is returned
+ assert.Equal(t, policyID, matchedPolicy.PolicyID)
+ assert.Contains(t, matchedPolicy.Data, expectedDirParts)
+
+}
+
+// Mock function for checkIfPolicyAlreadyExists
+func mockCheckIfPolicyExists(policyID string) bool {
+ return policyID == "valid-policy"
+}
+
+// Mock function for getPolicyByID
+func mockGetPolicyByID(policiesMap map[string]Policy, policyID string) (Policy, error) {
+ if policyID == "valid-policy" {
+ return Policy{
+ Data: []string{"existing.path", "valid.path"},
+ }, nil
+ }
+ return Policy{}, errors.New("policy not found")
+}
+
+func TestPatchHandler_PolicyDoesNotExist(t *testing.T) {
+ originalCheckFunc := checkIfPolicyAlreadyExistsVar
+ checkIfPolicyAlreadyExistsVar = mockCheckIfPolicyExists
+ defer func() { checkIfPolicyAlreadyExistsVar = originalCheckFunc }()
+
+ ctime := "08:26:41.857Z"
+ timeZone := "America/New_York"
+ timeOffset := "+02:00"
+ onapComp := "COMPONENT"
+ onapIns := "INSTANCE"
+ onapName := "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")
+ }
+
+ requestBody := oapicodegen.OPADataUpdateRequest{
+ CurrentDate: ¤tDate,
+ CurrentDateTime: ¤tDateTime,
+ CurrentTime: &ctime,
+ TimeOffset: &timeOffset,
+ TimeZone: &timeZone,
+ OnapComponent: &onapComp,
+ OnapInstance: &onapIns,
+ OnapName: &onapName,
+
+ PolicyName: StringPointer("invalid-policy"),
+ Data: &[]map[string]interface{}{{"test": "value"}},
+ }
+ bodyBytes, _ := json.Marshal(requestBody)
+
+ req, err := http.NewRequest("PATCH", "/policy/pdpo/v1/data/existing.path", bytes.NewBuffer(bodyBytes))
+ assert.NoError(t, err)
+
+ rec := httptest.NewRecorder()
+
+ patchHandler(rec, req)
+
+ assert.Equal(t, http.StatusBadRequest, rec.Code)
+ assert.Contains(t, rec.Body.String(), "Policy associated with the patch request does not exist")
+}
+
+func TestPatchHandler_InvalidDataPath(t *testing.T) {
+
+ ctime := "08:26:41.857Z"
+ timeZone := "America/New_York"
+ timeOffset := "+02:00"
+ onapComp := "COMPONENT"
+ onapIns := "INSTANCE"
+ onapName := "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")
+ }
+
+ policymap.LastDeployedPolicies = `{"deployed_policies_dict": [{"policy-id": "valid-policy","policy-version": "v1"}]}`
+
+ requestBody := &oapicodegen.OPADataUpdateRequest{
+ CurrentDate: ¤tDate,
+ CurrentDateTime: ¤tDateTime,
+ CurrentTime: &ctime,
+ TimeOffset: &timeOffset,
+ TimeZone: &timeZone,
+ OnapComponent: &onapComp,
+ OnapInstance: &onapIns,
+ OnapName: &onapName,
+
+ PolicyName: StringPointer("valid-policy"),
+ Data: &[]map[string]interface{}{{"test": "value"}},
+ }
+ bodyBytes, _ := json.Marshal(requestBody)
+
+ req, err := http.NewRequest("PATCH", "/policy/pdpo/v1/data/nonexisting.path", bytes.NewBuffer(bodyBytes))
+ assert.NoError(t, err)
+
+ rec := httptest.NewRecorder()
+
+ patchHandler(rec, req)
+
+ assert.Equal(t, http.StatusBadRequest, rec.Code)
+ assert.Contains(t, rec.Body.String(), "Dynamic Data add/replace/remove for policy")
+}
+
+// Utility function to create a pointer to a string
+func StringPointer(s string) *string {
+ return &s
+}
+
+func TestValidatePolicyDataPathMatched_PolicyNotFound(t *testing.T) {
+ original := getPolicyByIDVar
+ defer func() { getPolicyByIDVar = original }()
+
+ getPolicyByIDVar = func(policiesMap string, policyId string) (*Policy, error) {
+ return nil, fmt.Errorf("policy not found")
+ }
+
+ dirParts := []string{"", "config", "a"}
+ res := httptest.NewRecorder()
+
+ result := validatePolicyDataPathMatched(dirParts, "non-existent-id", res)
+
+ assert.False(t, result)
+ assert.Equal(t, http.StatusBadRequest, res.Code)
+}
+
+func TestValidatePolicyDataPathMatched_Success(t *testing.T) {
+ original := getPolicyByIDVar
+ defer func() { getPolicyByIDVar = original }()
+
+ getPolicyByIDVar = func(policiesMap string, policyId string) (*Policy, error) {
+ return &Policy{
+ PolicyID: policyId,
+ Data: []string{"config.a", "data.b"},
+ }, nil
+ }
+
+ dirParts := []string{"", "config", "a"}
+ res := httptest.NewRecorder()
+
+ result := validatePolicyDataPathMatched(dirParts, "test-policy", res)
+
+ assert.True(t, result)
+ assert.Equal(t, 200, res.Code) // or 0 if not written to
+}
+
+func TestPatchInfos_ExtractPatchInfo_Error(t *testing.T) {
+ // Save original function and defer restore
+ originalExtractPatchInfo := extractPatchInfoVar
+ defer func() { extractPatchInfoVar = originalExtractPatchInfo }()
+
+ // Mock function to return error
+ extractPatchInfoVar = func(res http.ResponseWriter, ops *[]map[string]interface{}, root string) ([]opasdk.PatchImpl, error) {
+ return nil, fmt.Errorf("mocked extractPatchInfo failure")
+ }
+
+ // Dummy input
+ ops := &[]map[string]interface{}{
+ {"op": "add", "value": "dummy"},
+ }
+ root := "root.path"
+
+ res := httptest.NewRecorder()
+ // Call the actual logic that depends on extractPatchInfoVar
+ patchInfos, err := extractPatchInfoVar(res, ops, root)
+
+ // Assertions
+ if err == nil {
+ t.Fatal("expected error but got nil")
+ }
+ if patchInfos != nil {
+ t.Errorf("expected patchInfos to be nil, got: %v", patchInfos)
+ }
+}
// This function processes the request headers
func processRequestHeaders(req *http.Request, res http.ResponseWriter) (string, *oapicodegen.DecisionParams) {
- requestId := req.Header.Get("X-ONAP-RequestID")
+ requestId := req.Header.Get(consts.RequestId)
var parsedUUID *uuid.UUID
var decisionParams *oapicodegen.DecisionParams
decisionParams = &oapicodegen.DecisionParams{
XONAPRequestID: (*openapi_types.UUID)(parsedUUID),
}
- res.Header().Set("X-ONAP-RequestID", decisionParams.XONAPRequestID.String())
+ res.Header().Set(consts.RequestId, decisionParams.XONAPRequestID.String())
} else {
log.Warnf("Error Parsing the requestID: %v", err)
}
} else {
requestId = "Unknown"
- res.Header().Set("X-ONAP-RequestID", requestId)
+ res.Header().Set(consts.RequestId, requestId)
}
res.Header().Set("X-LatestVersion", consts.LatestVersion)
// handles HTTP requests for health checks and responds with the health status of the service.
func HealthCheckHandler(w http.ResponseWriter, r *http.Request) {
- requestId := r.Header.Get("X-ONAP-RequestID")
+ requestId := r.Header.Get(consts.RequestId)
var parsedUUID *uuid.UUID
var healthCheckParams *oapicodegen.HealthcheckParams
healthCheckParams = &oapicodegen.HealthcheckParams{
XONAPRequestID: (*openapi_types.UUID)(parsedUUID),
}
- w.Header().Set("X-ONAP-RequestID", healthCheckParams.XONAPRequestID.String())
+ w.Header().Set(consts.RequestId, healthCheckParams.XONAPRequestID.String())
}
} else {
log.Warnf("Invalid or Missing Request ID")
requestId = "000000000000"
- w.Header().Set("X-ONAP-RequestID", requestId)
+ w.Header().Set(consts.RequestId, requestId)
}
w.Header().Set("X-LatestVersion", consts.LatestVersion)
w.Header().Set("X-PatchVersion", consts.PatchVersion)
"sync"
)
+type (
+ pdpUpdateMessageHandlerFunc func(message []byte, p publisher.PdpStatusSender) error
+ pdpStateChangeMessageHandlerFunc func(message []byte, p publisher.PdpStatusSender) error
+)
+
var (
- shutdownFlag bool
- mu sync.Mutex
+ shutdownFlag bool
+ mu sync.Mutex
+ pdpUpdateMessageHandlerVar pdpUpdateMessageHandlerFunc = pdpUpdateMessageHandler
+ pdpStateChangeMessageHandlerVar pdpStateChangeMessageHandlerFunc = pdpStateChangeMessageHandler
)
// SetShutdownFlag sets the shutdown flag
continue
}
- switch opaPdpMessage.MessageType {
+ handlePdpMessageTypes(opaPdpMessage.MessageType, message, p)
+ }
+ }
- case "PDP_UPDATE":
- err = pdpUpdateMessageHandler(message, p)
- if err != nil {
- log.Warnf("Error processing Update Message: %v", err)
- }
+ }
+ return nil
- case "PDP_STATE_CHANGE":
- err = pdpStateChangeMessageHandler(message, p)
- if err != nil {
- log.Warnf("Error processing Update Message: %v", err)
- }
+}
- case "PDP_STATUS":
- log.Debugf("discarding event of type PDP_STATUS")
- continue
- default:
- log.Errorf("This is not a valid Message Type: %s", opaPdpMessage.MessageType)
- continue
+func handlePdpMessageTypes(messageType string, message []byte, p publisher.PdpStatusSender) {
+ log.Debugf("messageType: %s", messageType)
+ var err error
+ switch messageType {
- }
+ case "PDP_UPDATE":
+ err = pdpUpdateMessageHandlerVar(message, p)
+ if err != nil {
+ log.Warnf("Error processing Update Message: %v", err)
+ }
- }
+ case "PDP_STATE_CHANGE":
+ err = pdpStateChangeMessageHandlerVar(message, p)
+ if err != nil {
+ log.Warnf("Error processing Update Message: %v", err)
}
- }
- return nil
+ case "PDP_STATUS":
+ log.Debugf("discarding event of type PDP_STATUS")
+ break
+ default:
+ log.Errorf("This is not a valid Message Type: %s", messageType)
+ }
}
"policy-opa-pdp/consts"
"policy-opa-pdp/pkg/kafkacomm"
"policy-opa-pdp/pkg/kafkacomm/mocks"
+ "policy-opa-pdp/pkg/kafkacomm/publisher"
"policy-opa-pdp/pkg/pdpattributes"
"testing"
"time"
return args.Get(0).([]byte), args.Error(0)
}
-func (m *MockKafkaConsumer) PdpUpdateMessageHandler(msg string) error {
+func (m *MockKafkaConsumer) pdpUpdateMessageHandler(msg string) error {
args := m.Called(msg)
return args.Error(0)
}
func TestPdpMessageHandler_ValidPDPUpdate(t *testing.T) {
t.Run("Process PDP_UPDATE Message", func(t *testing.T) {
message := `{
- "source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
- "pdpHeartbeatIntervalMs":120000,
- "policiesToBeDeployed":[],
- "policiesToBeUndeployed":[],
- "messageName":"PDP_UPDATE",
- "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
- "timestampMs":1730722305297,
- "name":"",
- "pdpGroup":"opaGroup",
- "pdpSubgroup":"opa"
- }`
+ "source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
+ "pdpHeartbeatIntervalMs":120000,
+ "policiesToBeDeployed":[],
+ "policiesToBeUndeployed":[],
+ "messageName":"PDP_UPDATE",
+ "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
+ "timestampMs":1730722305297,
+ "name":"",
+ "pdpGroup":"opaGroup",
+ "pdpSubgroup":"opa"
+ }`
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
defer cancel() // cancel is called to release resources
func TestPdpMessageHandler_ValidPdpStateChange(t *testing.T) {
t.Run("Process PDP STATE CHANGE Message Handler", func(t *testing.T) {
message := `{
- "source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
- "pdpHeartbeatIntervalMs":120000,
- "policiesToBeDeployed":[],
- "policiesToBeUndeployed":[],
- "messageName": "PDP_STATE_CHANGE",
- "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
- "timestampMs":1730722305297,
- "name":"",
- "pdpGroup":"opaGroup",
- "pdpSubgroup":"opa"
- }`
+ "source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
+ "pdpHeartbeatIntervalMs":120000,
+ "policiesToBeDeployed":[],
+ "policiesToBeUndeployed":[],
+ "messageName": "PDP_STATE_CHANGE",
+ "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
+ "timestampMs":1730722305297,
+ "name":"",
+ "pdpGroup":"opaGroup",
+ "pdpSubgroup":"opa"
+ }`
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
defer cancel()
func TestPdpMessageHandler_DiscardPdpStatus(t *testing.T) {
t.Run("Process PDP STATUS Message Handler", func(t *testing.T) {
message := `{
- "source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
- "pdpHeartbeatIntervalMs":120000,
- "policiesToBeDeployed":[],
- "policiesToBeUndeployed":[],
- "messageName":"PDP_STATUS",
- "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
- "timestampMs":1730722305297,
- "name":"",
- "pdpGroup":"opaGroup",
- "pdpSubgroup":"opa"
- }`
+ "source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
+ "pdpHeartbeatIntervalMs":120000,
+ "policiesToBeDeployed":[],
+ "policiesToBeUndeployed":[],
+ "messageName":"PDP_STATUS",
+ "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
+ "timestampMs":1730722305297,
+ "name":"",
+ "pdpGroup":"opaGroup",
+ "pdpSubgroup":"opa"
+ }`
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
defer cancel()
func TestPdpMessageHandler_InvalidMessage(t *testing.T) {
t.Run("Process Invalid PDP Message Handler", func(t *testing.T) {
message := `{
- "source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
- "pdpHeartbeatIntervalMs":120000,
- "policiesToBeDeployed":[],
- "policiesToBeUndeployed":[],
- "messageName":"PDP_INVALID",
- "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
- "timestampMs":1730722305297,
- "name":"",
- "pdpGroup":"opaGroup",
- "pdpSubgroup":"opa"
- }`
+ "source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
+ "pdpHeartbeatIntervalMs":120000,
+ "policiesToBeDeployed":[],
+ "policiesToBeUndeployed":[],
+ "messageName":"PDP_INVALID",
+ "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
+ "timestampMs":1730722305297,
+ "name":"",
+ "pdpGroup":"opaGroup",
+ "pdpSubgroup":"opa"
+ }`
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
defer cancel()
func TestPdpMessageHandler_ContextCancelled(t *testing.T) {
t.Run("Context is canceled", func(t *testing.T) {
message := `{
- "source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
- "pdpHeartbeatIntervalMs":120000,
- "policiesToBeDeployed":[],
- "policiesToBeUndeployed":[],
- "messageName":"PDP_INVALID",
- "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
- "timestampMs":1730722305297,
- "name":"",
- "pdpGroup":"opaGroup",
- "pdpSubgroup":"opa"
- }`
+ "source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
+ "pdpHeartbeatIntervalMs":120000,
+ "policiesToBeDeployed":[],
+ "policiesToBeUndeployed":[],
+ "messageName":"PDP_INVALID",
+ "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
+ "timestampMs":1730722305297,
+ "name":"",
+ "pdpGroup":"opaGroup",
+ "pdpSubgroup":"opa"
+ }`
ctx, cancel := context.WithCancel(context.Background())
cancel() // Immediately cancel the context
func TestPdpMessageHandler_InvalidOPAPdpmessage(t *testing.T) {
t.Run("Invalid OPA PDP message", func(t *testing.T) {
message := `{
- "":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
- "pdpHeartbeatIntervalMs":120000,
- "policiesToBeDeployed":[],
- "policiesToBeUndeployed":[],
- "messageName":"PDP_UPDATE",
- "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
- "timestampMs":1730722305297,
- "name":"",
- "pdpGroup":"opaGroup",
- "pdpSubgroup":"opa"
- }`
+ "":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
+ "pdpHeartbeatIntervalMs":120000,
+ "policiesToBeDeployed":[],
+ "policiesToBeUndeployed":[],
+ "messageName":"PDP_UPDATE",
+ "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
+ "timestampMs":1730722305297,
+ "name":"",
+ "pdpGroup":"opaGroup",
+ "pdpSubgroup":"opa"
+ }`
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
defer cancel() // cancel is called to release resources
func TestPdpMessageHandler_InvalidOPAPdpStateChangemessage(t *testing.T) {
t.Run("Invalid OPA PDP State Change message", func(t *testing.T) {
message := `{
- "sourc":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
- "pdpHeartbeatIntervalMs":120000,
- "policiesToBeDeployed":[],
- "policiesToBeUndeployed":[],
- "messageName":"PDP_STATE_CHANGE",
- "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
- "timestampMs":1730722305297,
- "name":"",
- "pdpGroup":"opaGroup",
- "pdpSubgroup":"opa"
- }`
+ "sourc":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
+ "pdpHeartbeatIntervalMs":120000,
+ "policiesToBeDeployed":[],
+ "policiesToBeUndeployed":[],
+ "messageName":"PDP_STATE_CHANGE",
+ "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
+ "timestampMs":1730722305297,
+ "name":"",
+ "pdpGroup":"opaGroup",
+ "pdpSubgroup":"opa"
+ }`
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
defer cancel()
func TestPdpMessageHandler_jsonunmarshallOPAPdpStateChangemessage(t *testing.T) {
t.Run("Invalid OPA PDP State Change message", func(t *testing.T) {
message := `{
- "source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
- "pdpHeartbeatIntervalMs":120000,
- "policiesToBeDeployed":[],
- "policiesToBeUndeployed":[],
- "messageName":"PDP_STATE_CHANGE"
- "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
- "timestampMs":1730722305297,
- "name":"",
- "pdpGroup":"opaGroup",
- "pdpSubgroup":"opa"
- }`
+ "source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
+ "pdpHeartbeatIntervalMs":120000,
+ "policiesToBeDeployed":[],
+ "policiesToBeUndeployed":[],
+ "messageName":"PDP_STATE_CHANGE"
+ "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
+ "timestampMs":1730722305297,
+ "name":"",
+ "pdpGroup":"opaGroup",
+ "pdpSubgroup":"opa"
+ }`
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
defer cancel()
})
}
+
+func TestHandlePdpMessageTypes_Update(t *testing.T) {
+ mockSender := new(MockPdpStatusSender)
+
+ pdpUpdateMessageHandlerVar = func(msg []byte, p publisher.PdpStatusSender) error {
+ assert.Equal(t, "update-message", string(msg))
+ return nil
+ }
+
+ handlePdpMessageTypes("PDP_UPDATE", []byte("update-message"), mockSender)
+ // Add assertions on log output if needed
+}
+
+func TestHandlePdpMessageTypes_Update_Error(t *testing.T) {
+ mockSender := new(MockPdpStatusSender)
+
+ pdpUpdateMessageHandlerVar = func(msg []byte, p publisher.PdpStatusSender) error {
+ return errors.New("mock update error")
+ }
+
+ handlePdpMessageTypes("PDP_UPDATE", []byte("bad-message"), mockSender)
+}
+
+func TestHandlePdpMessageTypes_StateChange(t *testing.T) {
+ mockSender := new(MockPdpStatusSender)
+
+ pdpStateChangeMessageHandlerVar = func(msg []byte, p publisher.PdpStatusSender) error {
+ assert.Equal(t, "state-change", string(msg))
+ return nil
+ }
+
+ handlePdpMessageTypes("PDP_STATE_CHANGE", []byte("state-change"), mockSender)
+}
+
+func TestHandlePdpMessageTypes_StateChange_Error(t *testing.T) {
+ mockSender := new(MockPdpStatusSender)
+
+ pdpStateChangeMessageHandlerVar = func(msg []byte, p publisher.PdpStatusSender) error {
+ return errors.New("mock state change error")
+ }
+
+ handlePdpMessageTypes("PDP_STATE_CHANGE", []byte("bad-state"), mockSender)
+}
+
+func TestHandlePdpMessageTypes_Status(t *testing.T) {
+ mockSender := new(MockPdpStatusSender)
+ handlePdpMessageTypes("PDP_STATUS", []byte("ignore"), mockSender)
+}
+
+func TestHandlePdpMessageTypes_Invalid(t *testing.T) {
+ mockSender := new(MockPdpStatusSender)
+ handlePdpMessageTypes("INVALID_TYPE", []byte("invalid"), mockSender)
+}
expectError: false,
checkNotEqual: false,
},
+ "Empty SendStateChangeResponse": {
+ message: []byte(`{"state":"Hello"}`),
+ expectedState: "PASSIVE",
+ mockError: assert.AnError,
+ expectError: true,
+ checkNotEqual: false,
+ },
+ "Empty SendStateChangeJson": {
+ message: []byte(`{}`),
+ expectedState: "PASSIVE",
+ mockError: assert.AnError,
+ expectError: false,
+ checkNotEqual: false,
+ },
}
- orderedKeys := []string{"Valid state change", "Invalid JSON", "Error in SendStateChangeResponse"}
+ orderedKeys := []string{"Valid state change", "Invalid JSON", "Error in SendStateChangeResponse", "Empty SendStateChangeResponse", "Empty SendStateChangeJson"}
for _, name := range orderedKeys {
tt := tests[name]
return decodedData, keys, nil
}
-// Function to extract folder name based on policy
-func getDirName(policy model.ToscaPolicy) []string {
- // Split the policy name to identify the folder part (i.e., the first part before ".")
-
- var dirNames []string
-
- for key, _ := range policy.Properties.Data {
-
- dirNames = append(dirNames, strings.ReplaceAll(consts.DataNode+key, ".", "/"))
-
- }
- for key, _ := range policy.Properties.Policy {
-
- dirNames = append(dirNames, strings.ReplaceAll(consts.Policies+"/"+key, ".", "/"))
-
- }
-
- return dirNames
-}
// upsert policy to sdk.
func upsertPolicy(policy model.ToscaPolicy) error {
pdpUpdate.PoliciesToBeDeployed = checkIfPolicyAlreadyDeployed(pdpUpdate)
for _, policy := range pdpUpdate.PoliciesToBeDeployed {
- // Validate the policy
-
- policyAllowed, err := validateParentPolicyVar(policy)
- if err != nil {
- log.Warnf("Tosca Policy Id validation failed for policy nameas it is a parent folder:%s, %v", policy.Name, err)
- failureMessages = append(failureMessages, fmt.Sprintf("%s, %v", policy.Name, err))
- metrics.IncrementDeployFailureCount()
- metrics.IncrementTotalErrorCount()
- continue
- }
- if policyAllowed {
- log.Debugf("Policy Is Allowed: %s", policy.Name)
- }
-
- if err := utils.ValidateToscaPolicyJsonFields(policy); err != nil {
- log.Debugf("Tosca Policy Validation Failed for policy Name: %s, %v", policy.Name, err)
- failureMessages = append(failureMessages, fmt.Sprintf("Tosca Policy Validation failed for Policy: %s: %v", policy.Name, err))
- metrics.IncrementDeployFailureCount()
- metrics.IncrementTotalErrorCount()
+ if err := validateAndPreparePolicy(policy, &failureMessages); err != nil {
continue
}
-
- // Create and store policy data
- if err := createAndStorePolicyDataVar(policy); err != nil {
- failureMessages = append(failureMessages, fmt.Sprintf("%s: %v", policy.Name, err))
- metrics.IncrementDeployFailureCount()
- metrics.IncrementTotalErrorCount()
- continue
- }
-
- // Build the bundle
- if err := verifyPolicyByBundleCreation(policy); err != nil {
- failureMessages = append(failureMessages, fmt.Sprintf("Failed to build Rego File for %s: %v", policy.Name, err))
- metrics.IncrementDeployFailureCount()
- metrics.IncrementTotalErrorCount()
- continue
- }
-
- // Upsert policy and data
- if err := upsertPolicyAndData(policy, successPolicies); err != nil {
+ if err := deployPolicyAndData(policy, successPolicies); err != nil {
failureMessages = append(failureMessages, err.Error())
- metrics.IncrementDeployFailureCount()
- metrics.IncrementTotalErrorCount()
continue
- } else {
- successPolicies[policy.Name] = policy.Version
- if _, err := policymap.UpdateDeployedPoliciesinMap(policy); err != nil {
- log.Warnf("Failed to store policy data map after deploying policy %s: %v", policy.Name, err)
- }
}
- metrics.IncrementDeploySuccessCount()
- log.Debugf("Loaded Policy: %s", policy.Name)
}
metrics.SetTotalPoliciesCount(int64(totalPolicies))
return failureMessages, successPolicies
+
+}
+
+func validateAndPreparePolicy(policy model.ToscaPolicy, failureMessages *[]string) error {
+ // Validate the policy
+
+ policyAllowed, err := validateParentPolicyVar(policy)
+ if err != nil {
+ log.Warnf("Tosca Policy Id validation failed for policy nameas it is a parent folder:%s, %v", policy.Name, err)
+ *failureMessages = append(*failureMessages, fmt.Sprintf("%s, %v", policy.Name, err))
+ metrics.IncrementDeployFailureCount()
+ metrics.IncrementTotalErrorCount()
+ return err
+ }
+ if policyAllowed {
+ log.Debugf("Policy Is Allowed: %s", policy.Name)
+ } else {
+ return fmt.Errorf("policy not Allowed")
+ }
+
+ if err := utils.ValidateToscaPolicyJsonFields(policy); err != nil {
+ log.Debugf("Tosca Policy Validation Failed for policy Name: %s, %v", policy.Name, err)
+ *failureMessages = append(*failureMessages, fmt.Sprintf("Tosca Policy Validation failed for Policy: %s: %v", policy.Name, err))
+ metrics.IncrementDeployFailureCount()
+ metrics.IncrementTotalErrorCount()
+ return err
+ }
+
+ // Create and store policy data
+ if err := createAndStorePolicyDataVar(policy); err != nil {
+ *failureMessages = append(*failureMessages, fmt.Sprintf("%s: %v", policy.Name, err))
+ metrics.IncrementDeployFailureCount()
+ metrics.IncrementTotalErrorCount()
+ return err
+ }
+ return nil
+
+}
+
+func deployPolicyAndData(policy model.ToscaPolicy, successPolicies map[string]string) error {
+
+ // Build the bundle
+ if output, err := verifyPolicyByBundleCreation(policy); err != nil {
+ if len(output) > consts.MaxOutputResponseLength {
+ output = output[:consts.MaxOutputResponseLength] + "..."
+ }
+ metrics.IncrementDeployFailureCount()
+ metrics.IncrementTotalErrorCount()
+ return fmt.Errorf("Failed to build Rego File for %s: %v", policy.Name, string(output))
+ }
+
+ // Upsert policy and data
+ if err := upsertPolicyAndData(policy, successPolicies); err != nil {
+ metrics.IncrementDeployFailureCount()
+ metrics.IncrementTotalErrorCount()
+ return err
+ } else {
+ successPolicies[policy.Name] = policy.Version
+ if _, err := policymap.UpdateDeployedPoliciesinMap(policy); err != nil {
+ log.Warnf("Failed to store policy data map after deploying policy %s: %v", policy.Name, err)
+ }
+ }
+ metrics.IncrementDeploySuccessCount()
+ log.Debugf("Loaded Policy: %s", policy.Name)
+ return nil
}
// checks if policy exists in the map.
}
// verfies policy by creating bundle.
-func verifyPolicyByBundleCreation(policy model.ToscaPolicy) error {
+func verifyPolicyByBundleCreation(policy model.ToscaPolicy) (string, error) {
// get directory name
dirNames := []string{strings.ReplaceAll(consts.DataNode+"/"+policy.Name, ".", "/"), strings.ReplaceAll(consts.Policies+"/"+policy.Name, ".", "/")}
// create bundle
}
}
log.Debugf("Directory cleanup as bundle creation failed")
- return fmt.Errorf("failed to build bundle: %v", err)
+ return output, fmt.Errorf("failed to build bundle: %v", err)
}
- return nil
+ return output, nil
}
// handles Upsert func for policy and data
"policy-opa-pdp/pkg/utils"
"strings"
"testing"
+ "fmt"
)
func TestValidatePackageName(t *testing.T) {
createBundleFuncVar = func(execCmd func(string, ...string) *exec.Cmd, toscaPolicy model.ToscaPolicy) (string, error) {
return "", nil
}
- err := verifyPolicyByBundleCreation(policy)
+ _, err := verifyPolicyByBundleCreation(policy)
assert.NoError(t, err)
}
}
//Mocking the CreateBundle
- err := verifyPolicyByBundleCreation(policy)
+ _, err := verifyPolicyByBundleCreation(policy)
assert.NoError(t, err)
}
createBundleFuncVar = func(execCmd func(string, ...string) *exec.Cmd, toscaPolicy model.ToscaPolicy) (string, error) {
return "", errors.New("Fail to Initialize Bundle")
}
- err := verifyPolicyByBundleCreation(policy)
+ _, err := verifyPolicyByBundleCreation(policy)
assert.Error(t, err)
}
err, _ := handlePolicyDeployment(pdpUpdate, mockSender)
found := false
for _, message := range err {
- if strings.Contains(message, "Failed to Bundle") {
+ fmt.Println(message)
+ if strings.Contains(message, "Failed to build Rego File for") {
found = true
break
}
)
type (
- sendSuccessResponseFunc func(p publisher.PdpStatusSender, pdpUpdate *model.PdpUpdate, respMessage string) error
- sendFailureResponseFunc func(p publisher.PdpStatusSender, pdpUpdate *model.PdpUpdate, respMessage error) error
- createBundleFuncRef func(execCmd func(string, ...string) *exec.Cmd, toscaPolicy model.ToscaPolicy) (string, error)
+ sendSuccessResponseFunc func(p publisher.PdpStatusSender, pdpUpdate *model.PdpUpdate, respMessage string) error
+ sendFailureResponseFunc func(p publisher.PdpStatusSender, pdpUpdate *model.PdpUpdate, respMessage error) error
+ createBundleFuncRef func(execCmd func(string, ...string) *exec.Cmd, toscaPolicy model.ToscaPolicy) (string, error)
+ handlePdpUpdateDeploymentFunc func(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender) (string, error, []string)
+ handlePdpUpdateUndeploymentFunc func(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender) (string, error, []string)
+ sendFinalResponseFunc func(p publisher.PdpStatusSender, pdpUpdate *model.PdpUpdate, loggingPoliciesList string, failureMessages []string) error
)
var (
- basePolicyDir = consts.Policies
- baseDataDir = consts.Data
- sendSuccessResponseVar sendSuccessResponseFunc = sendSuccessResponse
- sendFailureResponseVar sendFailureResponseFunc = sendFailureResponse
- createBundleFuncVar createBundleFuncRef = createBundleFunc
+ basePolicyDir = consts.Policies
+ baseDataDir = consts.Data
+ sendSuccessResponseVar sendSuccessResponseFunc = sendSuccessResponse
+ sendFailureResponseVar sendFailureResponseFunc = sendFailureResponse
+ sendFinalResponseVar sendFinalResponseFunc = sendFinalResponse
+ createBundleFuncVar createBundleFuncRef = createBundleFunc
+ handlePdpUpdateDeploymentVar handlePdpUpdateDeploymentFunc = handlePdpUpdateDeployment
+ handlePdpUpdateUndeploymentVar handlePdpUpdateUndeploymentFunc = handlePdpUpdateUndeployment
+ sendPDPStatusResponseFunc = sendPDPStatusResponse
+
)
// Handles messages of type PDP_UPDATE sent from the Policy Administration Point (PAP).
err := json.Unmarshal(message, &pdpUpdate)
if err != nil {
log.Debugf("Failed to UnMarshal Messages: %v\n", err)
- resMessage := fmt.Errorf("PDP Update Failed: %v", err)
+ resMessage := fmt.Errorf("PDP Update Failed as failed Unmarshalling: %v", err)
if err := sendFailureResponseVar(p, &pdpUpdate, resMessage); err != nil {
- log.Debugf("Failed to send update error response: %v", err)
+ log.Debugf("Failed to send update unmarshal error response: %v", err)
return err
}
return err
}
//Initialize Validator and validate Struct after unmarshalling
- err = utils.ValidateFieldsStructs(pdpUpdate)
+ err = utils.ValidateFieldsStructsVar(pdpUpdate)
if err != nil {
resMessage := fmt.Errorf("PDP Update Failed: %v", err)
if err := sendFailureResponseVar(p, &pdpUpdate, resMessage); err != nil {
- log.Debugf("Failed to send update error response: %v", err)
+ log.Debugf("Failed to send pdp update validate fields error response: %v", err)
return err
}
return err
log.Debugf("PDP_UPDATE Message received: %s", string(message))
pdpattributes.SetPdpSubgroup(pdpUpdate.PdpSubgroup)
+ pdpattributes.SetPdpHeartbeatInterval(pdpUpdate.PdpHeartbeatIntervalMs)
+
+ depPoliciesList, err, depFailures := handlePdpUpdateDeploymentVar(pdpUpdate, p)
+ undepPoliciesList, undepErr, undepFailures := handlePdpUpdateUndeploymentVar(pdpUpdate, p)
+
+ if err != nil {
+ return err
+ }
+
+ if undepErr != nil {
+ return undepErr
+ }
+ failureMessages = append(depFailures, undepFailures...)
+ loggingPoliciesList = depPoliciesList
+
+ if undepPoliciesList != "" {
+ loggingPoliciesList += "," + undepPoliciesList
+ }
+
+ err = sendFinalResponseVar(p, &pdpUpdate, loggingPoliciesList, failureMessages)
+ if err != nil {
+ return err
+ }
+
+ log.Infof("PDP_STATUS Message Sent Successfully")
+ log.Debug(pdpUpdate.PdpHeartbeatIntervalMs)
+
+ if pdpattributes.PdpHeartbeatInterval != pdpUpdate.PdpHeartbeatIntervalMs && pdpUpdate.PdpHeartbeatIntervalMs != 0 {
+ //restart the ticker.
+ publisher.StopTicker()
+ pdpattributes.SetPdpHeartbeatInterval(pdpUpdate.PdpHeartbeatIntervalMs)
+ go publisher.StartHeartbeatIntervalTimer(pdpattributes.PdpHeartbeatInterval, p)
+ }
+ go publisher.StartHeartbeatIntervalTimer(pdpattributes.PdpHeartbeatInterval, p)
+ return nil
+
+}
+
+func handlePdpUpdateDeployment(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender) (string, error, []string) {
+ var failureMessages []string
+ var mapJson string
+ var err error
if len(pdpUpdate.PoliciesToBeDeployed) > 0 {
failureMessage, successfullyDeployedPolicies := handlePolicyDeploymentVar(pdpUpdate, p)
- mapJson, err := policymap.FormatMapofAnyType(successfullyDeployedPolicies)
+ mapJson, err = policymap.FormatMapOfAnyTypeVar(successfullyDeployedPolicies)
if len(failureMessage) > 0 {
failureMessages = append(failureMessages, "{Deployment Errors:"+strings.Join(failureMessage, "")+"}")
}
if err != nil {
failureMessages = append(failureMessages, "|Internal Map Error:"+err.Error()+"|")
- resMessage := fmt.Errorf("PDP Update Failed: failed to format successfullyDeployedPolicies json %v", failureMessages)
+ resMessage := fmt.Errorf("PDP Update Failed as failed to format successfullyDeployedPolicies json %v", failureMessages)
if err = sendFailureResponseVar(p, &pdpUpdate, resMessage); err != nil {
- log.Debugf("Failed to send update error response: %v", err)
- return err
+ log.Debugf("Failed to send update internal map error response: %v", err)
+ return "", err, failureMessages
}
}
- loggingPoliciesList = mapJson
+
}
+ return mapJson, nil, failureMessages
+}
+
+func handlePdpUpdateUndeployment(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender) (string, error, []string) {
+ var failureMessages []string
+ var mapJson string
+ var err error
+
// Check if "PoliciesToBeUndeployed" is empty or not
if len(pdpUpdate.PoliciesToBeUndeployed) > 0 {
log.Infof("Found Policies to be undeployed")
failureMessage, successfullyUndeployedPolicies := handlePolicyUndeploymentVar(pdpUpdate, p)
- mapJson, err := policymap.FormatMapofAnyType(successfullyUndeployedPolicies)
+ mapJson, err = policymap.FormatMapOfAnyTypeVar(successfullyUndeployedPolicies)
if len(failureMessage) > 0 {
failureMessages = append(failureMessages, "{UnDeployment Errors:"+strings.Join(failureMessage, "")+"}")
}
if err != nil {
failureMessages = append(failureMessages, "|Internal Map Error:"+err.Error()+"|")
- resMessage := fmt.Errorf("PDP Update Failed: failed to format successfullyUnDeployedPolicies json %v", failureMessages)
+ resMessage := fmt.Errorf("PDP Update Failed as failed to format successfullyUnDeployedPolicies json %v", failureMessages)
if err = sendFailureResponseVar(p, &pdpUpdate, resMessage); err != nil {
- log.Debugf("Failed to send update error response: %v", err)
- return err
+ log.Debugf("Failed to send update error response: %v", err)
+ return "", err, failureMessages
}
}
- loggingPoliciesList = mapJson
}
+ return mapJson, nil, failureMessages
+}
+func sendFinalResponse(p publisher.PdpStatusSender, pdpUpdate *model.PdpUpdate, loggingPoliciesList string, failureMessages []string) error {
if len(pdpUpdate.PoliciesToBeDeployed) == 0 && len(pdpUpdate.PoliciesToBeUndeployed) == 0 {
//Response for PAP Registration
- err = sendSuccessResponseVar(p, &pdpUpdate, "PDP UPDATE is successfull")
- if err != nil {
- log.Debugf("Failed to Send Update Response Message: %v\n", err)
- return err
- }
- } else {
- //Send Response for Deployment or Undeployment or when both deployment and undeployment comes together
- if err := sendPDPStatusResponse(pdpUpdate, p, loggingPoliciesList, failureMessages); err != nil {
- return err
- }
+ return sendSuccessResponseVar(p, pdpUpdate, "PDP UPDATE is successfull")
}
- log.Infof("PDP_STATUS Message Sent Successfully")
- log.Debug(pdpUpdate.PdpHeartbeatIntervalMs)
-
- if pdpattributes.PdpHeartbeatInterval != pdpUpdate.PdpHeartbeatIntervalMs && pdpUpdate.PdpHeartbeatIntervalMs != 0 {
- //restart the ticker.
- publisher.StopTicker()
- pdpattributes.SetPdpHeartbeatInterval(pdpUpdate.PdpHeartbeatIntervalMs)
- go publisher.StartHeartbeatIntervalTimer(pdpattributes.PdpHeartbeatInterval, p)
+ //Send Response for Deployment or Undeployment or when both deployment and undeployment comes together
+ if err := sendPDPStatusResponseFunc(*pdpUpdate, p, loggingPoliciesList, failureMessages); err != nil {
+ return err
}
-
return nil
}
}
func sendSuccessResponse(p publisher.PdpStatusSender, pdpUpdate *model.PdpUpdate, respMessage string) error {
- if err := publisher.SendPdpUpdateResponse(p, pdpUpdate, respMessage); err != nil {
+ if err := publisher.SendPdpUpdateResponseVar(p, pdpUpdate, respMessage); err != nil {
return err
}
return nil
func sendPDPStatusResponse(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender, loggingPoliciesList string, failureMessages []string) error {
if len(failureMessages) > 0 {
- resMessage := fmt.Errorf("PDP Update Failed: %v", failureMessages)
- if err := sendFailureResponseVar(p, &pdpUpdate, resMessage); err != nil {
- log.Warnf("Failed to send update error response: %v", err)
- return err
- }
+ return sendPDPStatusFailureResponse(pdpUpdate, p, loggingPoliciesList, failureMessages)
} else {
+ return sendPDPStatusSuccessResponse(pdpUpdate, p, loggingPoliciesList)
+ }
+}
- if len(pdpUpdate.PoliciesToBeUndeployed) == 0 {
- resMessage := fmt.Sprintf("PDP Update Successful for all policies: %v", loggingPoliciesList)
- if err := sendSuccessResponseVar(p, &pdpUpdate, resMessage); err != nil {
- log.Warnf("Failed to send update response: %v", err)
- return err
- }
- log.Infof("Processed policies_to_be_deployed successfully")
- } else if len(pdpUpdate.PoliciesToBeDeployed) == 0 {
+func sendPDPStatusFailureResponse(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender, loggingPoliciesList string, failureMessages []string) error {
+ resMessage := fmt.Errorf("PDP Update Failed: %v", failureMessages)
+ if err := sendFailureResponseVar(p, &pdpUpdate, resMessage); err != nil {
+ log.Warnf("Failed to send update error response: %v", err)
+ return err
+ }
+ return nil
+}
- resMessage := fmt.Sprintf("PDP Update Policies undeployed :%v", loggingPoliciesList)
+func sendPDPStatusSuccessResponse(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender, loggingPoliciesList string) error {
- if err := sendSuccessResponseVar(p, &pdpUpdate, resMessage); err != nil {
- log.Warnf("Failed to Send Update Response Message: %v", err)
- return err
- }
- log.Infof("Processed policies_to_be_undeployed successfully")
- } else {
+ var resMessage string
- if err := sendSuccessResponseVar(p, &pdpUpdate, "PDP UPDATE is successfull"); err != nil {
- log.Warnf("Failed to Send Update Response Message: %v", err)
- return err
- }
- }
+ if len(pdpUpdate.PoliciesToBeDeployed) > 0 {
+ resMessage = fmt.Sprintf("PDP Update Successful for all policies: %v", loggingPoliciesList)
+ log.Infof("Processed policies_to_be_deployed successfully")
+ } else if len(pdpUpdate.PoliciesToBeUndeployed) > 0 {
+ resMessage = fmt.Sprintf("PDP Update Policies undeployed :%v", loggingPoliciesList)
+ log.Infof("Processed policies_to_be_undeployed successfully")
+ } else {
+ resMessage = "PDP_UPDATE is successful"
+ }
+ if err := sendSuccessResponseVar(p, &pdpUpdate, resMessage); err != nil {
+ log.Warnf("Failed to Send Update Response Message: %v", err)
+ return err
}
return nil
}
"policy-opa-pdp/pkg/kafkacomm/publisher/mocks"
"policy-opa-pdp/pkg/model"
"policy-opa-pdp/pkg/policymap"
+ "policy-opa-pdp/pkg/utils"
"testing"
)
/*
-var (
- handlePolicyDeploymentFunc = handlePolicyDeployment
-)*/
-
-/*
-PdpUpdateMessageHandler_success
-Description: Test by sending a valid input message for pdp update
-Input: valid input
-Expected Output: PDP Update Message should be sent sucessfully.
-*/
-func TestPdpUpdateMessageHandler_Success(t *testing.T) {
-
- messageString := `{
- "source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
- "pdpHeartbeatIntervalMs":120000,
- "policiesToBeDeployed":[],
- "policiesToBeUndeployed":[],
- "messageName":"PDP_UPDATE",
- "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
- "timestampMs":1730722305297,
- "name":"opa-21cabb3e-f652-4ca6-b498-a77e62fcd059",
- "pdpGroup":"opaGroup",
- "pdpSubgroup":"opa"
- }`
-
- mockSender := new(mocks.PdpStatusSender)
- mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
-
- err := pdpUpdateMessageHandler([]byte(messageString), mockSender)
- assert.NoError(t, err)
-
-}
-
-/*
-PdpUpdateMessageHandler_Message_Unmarshal_Failure1
+pdpUpdateMessageHandler_Message_Unmarshal_Failure2
Description: Test by sending a invalid input message which should result in a Json unmarhsal error
Input: invalid input Message by renaming params or removing certain params
Expected Output: Message Handler should exit gracefully stating the error.
*/
-func TestPdpUpdateMessageHandler_Message_Unmarshal_Failure1(t *testing.T) {
-
- // sending only source parameter in the message string
- messageString := `{
- "source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0"}`
-
- mockSender := new(mocks.PdpStatusSender)
- mockSender.On("SendPdpStatus", mock.Anything).Return(errors.New("Jsonunmarshal Error"))
-
- err := pdpUpdateMessageHandler([]byte(messageString), mockSender)
- assert.Error(t, err)
-
-}
-
-/*
-PdpUpdateMessageHandler_Message_Unmarshal_Failure2
-Description: Test by sending a invalid input message which should result in a Json unmarhsal error
-Input: invalid input Message by renaming params or removing certain params
-Expected Output: Message Handler should exit gracefully stating the error.
-*/
-func TestPdpUpdateMessageHandler_Message_Unmarshal_Failure2(t *testing.T) {
+func TestpdpUpdateMessageHandler_Message_Unmarshal_Failure2(t *testing.T) {
// invlaid params by mispelling a param "source"
}
/*
-PdpUpdateMessageHandler_Message_Unmarshal_Failure3
+pdpUpdateMessageHandler_Message_Unmarshal_Failure3
Description: Test by sending a invalid input message which should result in a Json unmarhsal error
Input: {}
Expected Output: Message Handler should exit gracefully stating the error.
*/
-func TestPdpUpdateMessageHandler_Message_Unmarshal_Failure3(t *testing.T) {
+func TestpdpUpdateMessageHandler_Message_Unmarshal_Failure3(t *testing.T) {
// invlaid params by mispelling a param "source"
messageString := `{
- "soce:"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
- "pdpHeartbeatIntervalMs":120000}`
+ "soce:"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
+ "pdpHeartbeatIntervalMs":120000}`
mockSender := new(mocks.PdpStatusSender)
mockSender.On("SendPdpStatus", mock.Anything).Return(errors.New("Jsonunmarshal Error"))
}
/*
-PdpUpdateMessageHandler_Message_Unmarshal_Failure4
+pdpUpdateMessageHandler_Message_Unmarshal_Failure4
Description: Test by sending a invalid input message which should result in a Json unmarhsal error
Input: empty
Expected Output: Message Handler should exit gracefully stating the error.
*/
-func TestPdpUpdateMessageHandler_Message_Unmarshal_Failure4(t *testing.T) {
+func TestpdpUpdateMessageHandler_Message_Unmarshal_Failure4(t *testing.T) {
// invlaid params by mispelling a param "source"
}
/*
-PdpUpdateMessageHandler_Fails_Sending_PdpUpdateResponse
+pdpUpdateMessageHandler_Fails_Sending_PdpUpdateResponse
Description: Test by sending a invalid attribute for pdpstate which should result in a failure in sending pdp update response
Input: invalid input config set for pdpstate
Expected Output: Message Handler should exit gracefully stating the error.
*/
-func TestPdpUpdateMessageHandler_Fails_Sending_UpdateResponse(t *testing.T) {
+func TestpdpUpdateMessageHandler_Fails_Sending_UpdateResponse(t *testing.T) {
// invalid value set to pdpSubgroup -->empty ""
messageString := `{
"timestampMs":1730722305297,
"name":"opa-21cabb3e-f652-4ca6-b498-a77e62fcd059",
"pdpGroup":"opaGroup"
- }`
+ }`
mockSender := new(mocks.PdpStatusSender)
mockSender.On("SendPdpStatus", mock.Anything).Return(errors.New("Error in Sending PDP Update Response"))
}
/*
-PdpUpdateMessageHandler_Invalid_Starttimeinterval
+pdpUpdateMessageHandler_Invalid_Starttimeinterval
Description: Test by sending a invalid time value attribute for pdpstate which should result in a failure in starting heartbeat interval
Input: invalid input message for pdpstate heartbeat interval
Expected Output: Message Handler should exit gracefully stating the error.
*/
-func TestPdpUpdateMessageHandler_Invalid_Starttimeinterval(t *testing.T) {
+func TestpdpUpdateMessageHandler_Invalid_Starttimeinterval(t *testing.T) {
//invalid interval set to negative -1000
messageString := `{
"name":"opa-21cabb3e-f652-4ca6-b498-a77e62fcd059",
"pdpGroup":"opaGroup",
"pdpSubgroup":"opa"
- }`
+ }`
mockSender := new(mocks.PdpStatusSender)
mockSender.On("SendPdpStatus", mock.Anything).Return(errors.New("Invalid Interval Time for Heartbeat"))
}
/*
-PdpUpdateMessageHandler_Successful_Deployment
+pdpUpdateMessageHandler_Successful_Deployment
*/
-func TestPdpUpdateMessageHandler_Invalid_Deployment(t *testing.T) {
+func TestpdpUpdateMessageHandler_Invalid_Deployment(t *testing.T) {
messageString := `{
"source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
"pdpHeartbeatIntervalMs":120000,
}
/*
-PdpUpdateMessageHandler_Successful_Deployment
+pdpUpdateMessageHandler_Successful_Deployment
*/
-func TestPdpUpdateMessageHandler_Successful_Deployment(t *testing.T) {
+func TestpdpUpdateMessageHandler_Successful_Deployment(t *testing.T) {
messageString := `{
"source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
"pdpHeartbeatIntervalMs":120000,
}
/*
-PdpUpdateMessageHandler_Skipping_Deployment
+pdpUpdateMessageHandler_Skipping_Deployment
*/
-func TestPdpUpdateMessageHandler_Skipping_Deployment(t *testing.T) {
+func TestpdpUpdateMessageHandler_Skipping_Deployment(t *testing.T) {
messageString := `{
"source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
"pdpHeartbeatIntervalMs":120000,
}
/*
-PdpUpdateMessageHandler_FailureIn_Deployment_UnDeployment
+pdpUpdateMessageHandler_FailureIn_Deployment_UnDeployment
*/
-func TestPdpUpdateMessageHandler_FailureIn_Deployment_UnDeployment(t *testing.T) {
+func TestpdpUpdateMessageHandler_FailureIn_Deployment_UnDeployment(t *testing.T) {
messageString := `{
"source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
"pdpHeartbeatIntervalMs":120000,
return nil, map[string]string{"zone": "1.0.0"}
}
//mock the policy undeployment
- handlePolicyUndeploymentVar = func(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender) ([]string, map[string]string) {
+ handlePolicyDeploymentVar = func(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender) ([]string, map[string]string) {
return nil, map[string]string{"role": "1.0.0"}
}
}
/*
-PdpUpdateMessageHandler_Successful_Undeployment
+pdpUpdateMessageHandler_Successful_Undeployment
*/
-func TestPdpUpdateMessageHandler_Successful_Undeployment(t *testing.T) {
+func TestpdpUpdateMessageHandler_Successful_Undeployment(t *testing.T) {
messageString := `{
"source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
"pdpHeartbeatIntervalMs":120000,
policymap.LastDeployedPolicies = `{"deployed_policies_dict": [{"data": ["zone"],"policy": ["zone"],"policy-id": "zone","policy-version": "1.0.0"}]}`
//mock the policy undeployment
- handlePolicyUndeploymentVar = func(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender) ([]string, map[string]string) {
+ handlePolicyDeploymentVar = func(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender) ([]string, map[string]string) {
return nil, map[string]string{"zone": "1.0.0"}
}
}
/*
-PdpUpdateMessageHandler_Successful_Registration
+pdpUpdateMessageHandler_Successful_Registration
*/
-func TestPdpUpdateMessageHandler_Successful_Registration(t *testing.T) {
+func TestpdpUpdateMessageHandler_Successful_Registration(t *testing.T) {
messageString := `{
"source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
"pdpHeartbeatIntervalMs":120000,
}
/*
-PdpUpdateMessageHandler_Unsuccessful_Undeployment
+pdpUpdateMessageHandler_Unsuccessful_Undeployment
*/
-func TestPdpUpdateMessageHandler_UnSuccessful_Undeployment(t *testing.T) {
+func TestpdpUpdateMessageHandler_UnSuccessful_Undeployment(t *testing.T) {
messageString := `{
"source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
"pdpHeartbeatIntervalMs":120000,
policymap.LastDeployedPolicies = `{"deployed_policies_dict": []}`
//mock the policy undeployment
- handlePolicyUndeploymentVar = func(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender) ([]string, map[string]string) {
+ handlePolicyDeploymentVar = func(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender) ([]string, map[string]string) {
return []string{"Error in undeployment"}, map[string]string{}
}
}
/*
-PdpUpdateMessageHandler_Partial_FailureIn_Undeployment
+pdpUpdateMessageHandler_Partial_FailureIn_Undeployment
*/
-func TestPdpUpdateMessageHandler_Partial_FailureIn_Undeployment(t *testing.T) {
+func TestpdpUpdateMessageHandler_Partial_FailureIn_Undeployment(t *testing.T) {
messageString := `{
"source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
"pdpHeartbeatIntervalMs":120000,
policymap.LastDeployedPolicies = `{"deployed_policies_dict": [{"data": ["zone"],"policy": ["zone"],"policy-id": "zone","policy-version": "1.0.0"}]}`
//mock the policy undeployment
- handlePolicyUndeploymentVar = func(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender) ([]string, map[string]string) {
+ handlePdpUpdateUndeploymentVar = func(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender) (string, error, []string) {
- return []string{"Error in undeployment"}, map[string]string{"zone:": "1.0.0"}
+ return "", errors.New("error in undeployment"), []string{}
}
+ sendFinalResponseVar = func(p publisher.PdpStatusSender, update *model.PdpUpdate, policies string, failures []string) error {
+ assert.Equal(t, "{}", policies)
+ return nil
+ }
+ defer func() {
+ sendFinalResponseVar = sendFinalResponse
+ handlePdpUpdateUndeploymentVar = handlePdpUpdateUndeployment
+ }()
mockSender := new(mocks.PdpStatusSender)
mockSender.On("SendPdpStatus", mock.Anything).Return(errors.New("error in undeployment"))
assert.Error(t, err)
}
-/*
-PdpUpdateMessageHandler_Unsuccessful_Deployment
-*/
-func TestPdpUpdateMessageHandler_Unsuccessful_Deployment(t *testing.T) {
- messageString := `{
- "source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
- "pdpHeartbeatIntervalMs":120000,
- "policiesToBeDeployed": [{"type": "onap.policies.native.opa","type_version": "1.0.0","properties": {"data": {"zone": "ewogICJ6b25lIjogewogICAgInpvbmVfYWNjZXNzX2xvZ3MiOiBbCiAgICAgIHsgImxvZ19pZCI6ICJsb2cxIiwgInRpbWVzdGFtcCI6ICIyMDI0LTExLTAxVDA5OjAwOjAwWiIsICJ6b25lX2lkIjogInpvbmVBIiwgImFjY2VzcyI6ICJncmFudGVkIiwgInVzZXIiOiAidXNlcjEiIH0sCiAgICAgIHsgImxvZ19pZCI6ICJsb2cyIiwgInRpbWVzdGFtcCI6ICIyMDI0LTExLTAxVDEwOjMwOjAwWiIsICJ6b25lX2lkIjogInpvbmVBIiwgImFjY2VzcyI6ICJkZW5pZWQiLCAidXNlciI6ICJ1c2VyMiIgfSwKICAgICAgeyAibG9nX2lkIjogImxvZzMiLCAidGltZXN0YW1wIjogIjIwMjQtMTEtMDFUMTE6MDA6MDBaIiwgInpvbmVfaWQiOiAiem9uZUIiLCAiYWNjZXNzIjogImdyYW50ZWQiLCAidXNlciI6ICJ1c2VyMyIgfQogICAgXQogIH0KfQo="},"policy": {"zone": "cGFja2FnZSB6b25lCgppbXBvcnQgcmVnby52MQoKZGVmYXVsdCBhbGxvdyA6PSBmYWxzZQoKYWxsb3cgaWYgewogICAgaGFzX3pvbmVfYWNjZXNzCiAgICBhY3Rpb25faXNfbG9nX3ZpZXcKfQoKYWN0aW9uX2lzX2xvZ192aWV3IGlmIHsKICAgICJ2aWV3IiBpbiBpbnB1dC5hY3Rpb25zCn0KCmhhc196b25lX2FjY2VzcyBjb250YWlucyBhY2Nlc3NfZGF0YSBpZiB7CiAgICBzb21lIHpvbmVfZGF0YSBpbiBkYXRhLnpvbmUuem9uZS56b25lX2FjY2Vzc19sb2dzCiAgICB6b25lX2RhdGEudGltZXN0YW1wID49IGlucHV0LnRpbWVfcGVyaW9kLmZyb20KICAgIHpvbmVfZGF0YS50aW1lc3RhbXAgPCBpbnB1dC50aW1lX3BlcmlvZC50bwogICAgem9uZV9kYXRhLnpvbmVfaWQgPT0gaW5wdXQuem9uZV9pZAogICAgYWNjZXNzX2RhdGEgOj0ge2RhdGF0eXBlOiB6b25lX2RhdGFbZGF0YXR5cGVdIHwgZGF0YXR5cGUgaW4gaW5wdXQuZGF0YXR5cGVzfQp9Cg=="}},"name": "zone","version": "1.0.0","metadata": {"policy-id": "zone","policy-version": "1.0.0"}}],
- "policiesToBeUndeployed":[],
- "messageName":"PDP_UPDATE",
- "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
- "timestampMs":1730722305297,
- "name":"opa-21cabb3e-f652-4ca6-b498-a77e62fcd059",
- "pdpGroup":"opaGroup",
- "pdpSubgroup":"opa"
- }`
- mockSender := new(mocks.PdpStatusSender)
- mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
-
- // Mock the policy deployment logic
- handlePolicyDeploymentVar = func(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender) ([]string, map[string]string) {
-
- return []string{"Error in Deployment with Rego Err"}, map[string]string{}
- }
-
- err := pdpUpdateMessageHandler([]byte(messageString), mockSender)
- assert.NoError(t, err)
-}
-
func TestSendPDPStatusResponse(t *testing.T) {
mockSender := new(MockPdpStatusSender)
// Test case: Success with policies to be deployed
func TestCreateBundleFunc(t *testing.T) {
}
+
+func TesthandlePdpUpdateDeploymentVarSuccess(t *testing.T) {
+ mockSender := new(MockPdpStatusSender)
+
+ handlePolicyDeploymentVar = func(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender) ([]string, map[string]string) {
+ return nil, map[string]string{"policy1": "deployed"}
+ }
+ policymap.FormatMapOfAnyTypeVar = func(input any) (string, error) {
+ return `{"policy1":"deployed"}`, nil
+ }
+
+ update := model.PdpUpdate{
+ PoliciesToBeDeployed: []model.ToscaPolicy{{Name: "policy1"}},
+ }
+
+ jsonStr, err, failureMsgs := handlePdpUpdateDeployment(update, mockSender)
+
+ assert.NoError(t, err)
+ assert.Equal(t, `{"policy1":"deployed"}`, jsonStr)
+ assert.Empty(t, failureMsgs)
+}
+
+func TesthandlePdpUpdateDeploymentVarFormatError(t *testing.T) {
+ mockSender := new(MockPdpStatusSender)
+
+ handlePolicyDeploymentVar = func(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender) ([]string, map[string]string) {
+ return nil, map[string]string{"policy1": "deployed"}
+ }
+ policymap.FormatMapOfAnyTypeVar = func(input any) (string, error) {
+ return "", errors.New("formatting error")
+ }
+ sendFailureResponseVar = func(p publisher.PdpStatusSender, update *model.PdpUpdate, err error) error {
+ return nil
+ }
+
+ update := model.PdpUpdate{
+ PoliciesToBeDeployed: []model.ToscaPolicy{{Name: "policy1"}},
+ }
+
+ jsonStr, err, failureMsgs := handlePdpUpdateDeployment(update, mockSender)
+
+ assert.NoError(t, err)
+ assert.Equal(t, "", jsonStr)
+ assert.Contains(t, failureMsgs[0], "Internal Map Error")
+}
+
+func TesthandlePdpUpdateUndeploymentVarSuccess(t *testing.T) {
+ mockSender := new(MockPdpStatusSender)
+
+ handlePolicyUndeploymentVar = func(update model.PdpUpdate, p publisher.PdpStatusSender) ([]string, map[string]string) {
+ return nil, map[string]string{"policy1": "undeployed"}
+ }
+ policymap.FormatMapOfAnyTypeVar = func(input any) (string, error) {
+ return `{"policy1":"undeployed"}`, nil
+ }
+
+ update := model.PdpUpdate{
+ PoliciesToBeUndeployed: []model.ToscaConceptIdentifier{{Name: "policy1"}},
+ }
+
+ jsonStr, err, failureMsgs := handlePdpUpdateUndeployment(update, mockSender)
+
+ assert.NoError(t, err)
+ assert.Equal(t, `{"policy1":"undeployed"}`, jsonStr)
+ assert.Empty(t, failureMsgs)
+}
+
+func TesthandlePdpUpdateUndeploymentVarFormatError(t *testing.T) {
+ mockSender := new(MockPdpStatusSender)
+
+ handlePolicyUndeploymentVar = func(update model.PdpUpdate, p publisher.PdpStatusSender) ([]string, map[string]string) {
+ return nil, map[string]string{"policy1": "undeployed"}
+ }
+ policymap.FormatMapOfAnyTypeVar = func(input any) (string, error) {
+ return "", errors.New("formatting error")
+ }
+ sendFailureResponseVar = func(p publisher.PdpStatusSender, update *model.PdpUpdate, err error) error {
+ return nil
+ }
+
+ update := model.PdpUpdate{
+ PoliciesToBeUndeployed: []model.ToscaConceptIdentifier{{Name: "policy1"}},
+ }
+
+ jsonStr, err, failureMsgs := handlePdpUpdateUndeployment(update, mockSender)
+
+ assert.NoError(t, err)
+ assert.Equal(t, "", jsonStr)
+ assert.Contains(t, failureMsgs[0], "Internal Map Error")
+}
+
+func Test_UnmarshalFails(t *testing.T) {
+ msg := []byte(`invalid json`)
+ mockPublisher := new(mocks.PdpStatusSender)
+
+ var called bool
+ sendFailureResponseVar = func(p publisher.PdpStatusSender, update *model.PdpUpdate, err error) error {
+ called = true
+ return nil
+ }
+ defer func() { sendFailureResponseVar = sendFailureResponse }()
+
+ err := pdpUpdateMessageHandler(msg, mockPublisher)
+ assert.Error(t, err)
+ assert.True(t, called)
+}
+
+func Test_ValidationFails(t *testing.T) {
+ msg := []byte(`{"pdpSubgroup":"test","pdpHeartbeatIntervalMs":3000}`)
+ mockPublisher := new(mocks.PdpStatusSender)
+
+ utils.ValidateFieldsStructsVar = func(pdpUpdate model.PdpUpdate) error {
+ return errors.New("validation error")
+ }
+ defer func() { utils.ValidateFieldsStructsVar = utils.ValidateFieldsStructs }()
+
+ var called bool
+ sendFailureResponseVar = func(p publisher.PdpStatusSender, update *model.PdpUpdate, err error) error {
+ called = true
+ return nil
+ }
+ defer func() { sendFailureResponseVar = sendFailureResponse }()
+
+ err := pdpUpdateMessageHandler(msg, mockPublisher)
+ assert.Error(t, err)
+ assert.True(t, called)
+}
+
+func Test_DeploymentHandlerFails(t *testing.T) {
+ msg := []byte(`{
+ "source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
+ "pdpHeartbeatIntervalMs":120000,
+ "policiesToBeDeployed": [{"type": "onap.policies.native.opa","type_version": "1.0.0","properties": {"data": {"zone": "ewogICJ6b25lIjogewogICAgInpvbmVfYWNjZXNzX2xvZ3MiOiBbCiAgICAgIHsgImxvZ19pZCI6ICJsb2cxIiwgInRpbWVzdGFtcCI6ICIyMDI0LTExLTAxVDA5OjAwOjAwWiIsICJ6b25lX2lkIjogInpvbmVBIiwgImFjY2VzcyI6ICJncmFudGVkIiwgInVzZXIiOiAidXNlcjEiIH0sCiAgICAgIHsgImxvZ19pZCI6ICJsb2cyIiwgInRpbWVzdGFtcCI6ICIyMDI0LTExLTAxVDEwOjMwOjAwWiIsICJ6b25lX2lkIjogInpvbmVBIiwgImFjY2VzcyI6ICJkZW5pZWQiLCAidXNlciI6ICJ1c2VyMiIgfSwKICAgICAgeyAibG9nX2lkIjogImxvZzMiLCAidGltZXN0YW1wIjogIjIwMjQtMTEtMDFUMTE6MDA6MDBaIiwgInpvbmVfaWQiOiAiem9uZUIiLCAiYWNjZXNzIjogImdyYW50ZWQiLCAidXNlciI6ICJ1c2VyMyIgfQogICAgXQogIH0KfQo="},"policy": {"zone": "cGFja2FnZSB6b25lCgppbXBvcnQgcmVnby52MQoKZGVmYXVsdCBhbGxvdyA6PSBmYWxzZQoKYWxsb3cgaWYgewogICAgaGFzX3pvbmVfYWNjZXNzCiAgICBhY3Rpb25faXNfbG9nX3ZpZXcKfQoKYWN0aW9uX2lzX2xvZ192aWV3IGlmIHsKICAgICJ2aWV3IiBpbiBpbnB1dC5hY3Rpb25zCn0KCmhhc196b25lX2FjY2VzcyBjb250YWlucyBhY2Nlc3NfZGF0YSBpZiB7CiAgICBzb21lIHpvbmVfZGF0YSBpbiBkYXRhLnpvbmUuem9uZS56b25lX2FjY2Vzc19sb2dzCiAgICB6b25lX2RhdGEudGltZXN0YW1wID49IGlucHV0LnRpbWVfcGVyaW9kLmZyb20KICAgIHpvbmVfZGF0YS50aW1lc3RhbXAgPCBpbnB1dC50aW1lX3BlcmlvZC50bwogICAgem9uZV9kYXRhLnpvbmVfaWQgPT0gaW5wdXQuem9uZV9pZAogICAgYWNjZXNzX2RhdGEgOj0ge2RhdGF0eXBlOiB6b25lX2RhdGFbZGF0YXR5cGVdIHwgZGF0YXR5cGUgaW4gaW5wdXQuZGF0YXR5cGVzfQp9Cg=="}},"name": "zone","version": "1.0.0","metadata": {"policy-id": "zone","policy-version": "1.0.0"}}],
+ "policiesToBeUndeployed":[],
+ "messageName":"PDP_UPDATE",
+ "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
+ "timestampMs":1730722305297,
+ "name":"opa-21cabb3e-f652-4ca6-b498-a77e62fcd059",
+ "pdpGroup":"opaGroup",
+ "pdpSubgroup":"opa"
+ }`)
+
+ policymap.LastDeployedPolicies = `{"deployed_policies_dict": [{"data": ["zone"],"policy": ["zone"],"policy-id": "zone","policy-version": "1.0.0"}]}`
+ mockPublisher := new(mocks.PdpStatusSender)
+ mockPublisher.On("SendPdpStatus", mock.Anything).Return(nil)
+ sendFinalResponseVar = func(p publisher.PdpStatusSender, update *model.PdpUpdate, policies string, failures []string) error {
+ assert.Equal(t, "{}", policies)
+ return nil
+ }
+ defer func() {
+ sendFinalResponseVar = sendFinalResponse
+ }()
+ err := pdpUpdateMessageHandler(msg, mockPublisher)
+ assert.NoError(t, err)
+}
+
+func Test_UndeploymentHandlerFails(t *testing.T) {
+ msg := []byte(`{
+ "source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
+ "pdpHeartbeatIntervalMs":120000,
+ "policiesToBeDeployed":[],
+ "policiesToBeUndeployed":[{"name":"zone","version":"1.0.0"}],
+ "messageName":"PDP_UPDATE",
+ "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
+ "timestampMs":1730722305297,
+ "name":"opa-21cabb3e-f652-4ca6-b498-a77e62fcd059",
+ "pdpGroup":"opaGroup",
+ "pdpSubgroup":"opa"
+ }`)
+ policymap.LastDeployedPolicies = `{"deployed_policies_dict": []}`
+ mockPublisher := new(mocks.PdpStatusSender)
+ handlePdpUpdateUndeploymentVar = func(update model.PdpUpdate, p publisher.PdpStatusSender) (string, error, []string) {
+ return "", errors.New("undeployment error"), []string{}
+ }
+ defer func() {
+ handlePdpUpdateDeploymentVar = handlePdpUpdateDeployment
+ handlePdpUpdateUndeploymentVar = handlePdpUpdateUndeployment
+ }()
+ mockPublisher.On("SendPdpStatus", mock.Anything).Return(errors.New("undeployment error"))
+ err := pdpUpdateMessageHandler(msg, mockPublisher)
+ assert.Error(t, err)
+ assert.Contains(t, err.Error(), "undeployment error")
+}
+
+func Test_SuccessFlow(t *testing.T) {
+ msg := []byte(`{
+ "source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
+ "pdpHeartbeatIntervalMs":120000,
+ "policiesToBeDeployed":[],
+ "policiesToBeUndeployed":[],
+ "messageName":"PDP_UPDATE",
+ "requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
+ "timestampMs":1730722305297,
+ "name":"opa-21cabb3e-f652-4ca6-b498-a77e62fcd059",
+ "pdpGroup":"opaGroup",
+ "pdpSubgroup":"opa"
+ }`)
+
+ mockPublisher := new(mocks.PdpStatusSender)
+
+ handlePdpUpdateDeploymentVar = func(update model.PdpUpdate, p publisher.PdpStatusSender) (string, error, []string) {
+ return "dep1", nil, []string{}
+ }
+ handlePdpUpdateUndeploymentVar = func(update model.PdpUpdate, p publisher.PdpStatusSender) (string, error, []string) {
+ return "undep1", nil, []string{}
+ }
+ sendFinalResponseVar = func(p publisher.PdpStatusSender, update *model.PdpUpdate, policies string, failures []string) error {
+ assert.Equal(t, "dep1,undep1", policies)
+ return nil
+ }
+
+ defer func() {
+ handlePdpUpdateDeploymentVar = handlePdpUpdateDeployment
+ handlePdpUpdateUndeploymentVar = handlePdpUpdateUndeployment
+ sendFinalResponseVar = sendFinalResponse
+ }()
+ mockPublisher.On("SendPdpStatus", mock.Anything).Return(nil)
+ err := pdpUpdateMessageHandler(msg, mockPublisher)
+ assert.NoError(t, err)
+}
+
+func TestSendPDPStatusFailureResponse_Mocked(t *testing.T) {
+ original := sendFailureResponseVar
+ defer func() { sendFailureResponseVar = original }() // restore after test
+
+ called := false
+ sendFailureResponseVar = func(p publisher.PdpStatusSender, update *model.PdpUpdate, msg error) error {
+ called = true
+ assert.Equal(t, "PDP Update Failed: [mock fail]", msg.Error())
+ return nil
+ }
+
+ err := sendPDPStatusFailureResponse(model.PdpUpdate{}, nil, "mockPolicy", []string{"mock fail"})
+ assert.NoError(t, err)
+ assert.True(t, called, "sendFailureResponseVar should be called")
+}
+
+func TestSendPDPStatusSuccessResponse_Mocked(t *testing.T) {
+ original := sendSuccessResponseVar
+ defer func() { sendSuccessResponseVar = original }() // restore after test
+
+ called := false
+ sendSuccessResponseVar = func(p publisher.PdpStatusSender, update *model.PdpUpdate, msg string) error {
+ called = true
+ assert.Equal(t, "PDP Update Successful for all policies: p1,p2", msg)
+ return nil
+ }
+
+ update := model.PdpUpdate{
+ PoliciesToBeDeployed: []model.ToscaPolicy{
+ {
+ Type: "onap.policies.native.opa",
+ TypeVersion: "1.0.0",
+ },
+ },
+
+ PoliciesToBeUndeployed: []model.ToscaConceptIdentifier{
+ {
+ Name: "policy-to-undeply",
+ },
+ },
+ }
+
+ err := sendPDPStatusSuccessResponse(update, nil, "p1,p2")
+ assert.NoError(t, err)
+ assert.True(t, called, "sendSuccessResponseVar should be called")
+}
+
+func TestSendFinalResponse_MockedSendPDPStatusResponse_Success(t *testing.T) {
+ defer func() { sendPDPStatusResponseFunc = sendPDPStatusResponse }() // Reset after test
+
+ mockSender := new(mocks.PdpStatusSender)
+ pdpUpdate := &model.PdpUpdate{
+ PoliciesToBeDeployed: []model.ToscaPolicy{{Name: "TestPolicy"}},
+ }
+
+ // Override the global function for testing
+ sendPDPStatusResponseFunc = func(update model.PdpUpdate, p publisher.PdpStatusSender, loggingPoliciesList string, failureMessages []string) error {
+ return nil
+ }
+
+ err := sendFinalResponse(mockSender, pdpUpdate, "TestPolicy", nil)
+ assert.NoError(t, err)
+}
+
+func TestSendFinalResponse_MockedSendPDPStatusResponse_Failure(t *testing.T) {
+ defer func() { sendPDPStatusResponseFunc = sendPDPStatusResponse }() // Reset after test
+
+ mockSender := new(mocks.PdpStatusSender)
+ pdpUpdate := &model.PdpUpdate{
+ PoliciesToBeDeployed: []model.ToscaPolicy{{Name: "FailPolicy"}},
+ }
+
+ sendPDPStatusResponseFunc = func(update model.PdpUpdate, p publisher.PdpStatusSender, loggingPoliciesList string, failureMessages []string) error {
+ return errors.New("mock failure")
+ }
+
+ err := sendFinalResponse(mockSender, pdpUpdate, "FailPolicy", nil)
+ assert.Error(t, err)
+ assert.Equal(t, "mock failure", err.Error())
+}
+
+func TestHandlePdpUpdateUndeployment_WithFailureMessage(t *testing.T) {
+ defer func() {
+ handlePolicyUndeploymentVar = handlePolicyUndeployment
+ policymap.FormatMapOfAnyTypeVar = policymap.FormatMapofAnyType
+ }()
+
+ mockSender := new(mocks.PdpStatusSender)
+ update := model.PdpUpdate{
+ PoliciesToBeUndeployed: []model.ToscaConceptIdentifier{{Name: "Policy1"}},
+ }
+
+ handlePolicyUndeploymentVar = func(update model.PdpUpdate, p publisher.PdpStatusSender) ([]string, map[string]string) {
+
+ return []string{"UndeployError"}, map[string]string{"Policy1": "undeployed"}
+ }
+
+ policymap.FormatMapOfAnyTypeVar = func(data interface{}) (string, error) {
+ return "Policy1", nil
+ }
+
+ json, err, failures := handlePdpUpdateUndeployment(update, mockSender)
+
+ assert.NoError(t, err)
+ assert.Equal(t, "Policy1", json)
+ assert.Contains(t, failures[0], "UnDeployment Errors:UndeployError")
+}
+
+func TestHandlePdpUpdateUndeployment_SendFailureResponseFails(t *testing.T) {
+ defer func() {
+ handlePolicyUndeploymentVar = handlePolicyUndeployment
+ policymap.FormatMapOfAnyTypeVar = policymap.FormatMapofAnyType
+ sendFailureResponseVar = sendFailureResponse
+ }()
+
+ mockSender := new(mocks.PdpStatusSender)
+ update := model.PdpUpdate{
+ PoliciesToBeUndeployed: []model.ToscaConceptIdentifier{{Name: "Policy1"}},
+ }
+
+ handlePolicyUndeploymentVar = func(update model.PdpUpdate, p publisher.PdpStatusSender) ([]string, map[string]string) {
+ return nil, map[string]string{"Policy1": "undeployed"}
+ }
+
+ policymap.FormatMapOfAnyTypeVar = func(data interface{}) (string, error) {
+ return "", errors.New("mock format error")
+ }
+
+ sendFailureResponseVar = func(p publisher.PdpStatusSender, update *model.PdpUpdate, err error) error {
+ return errors.New("send failed")
+ }
+
+ json, err, failures := handlePdpUpdateUndeployment(update, mockSender)
+
+ assert.Error(t, err)
+ assert.Equal(t, "send failed", err.Error())
+ assert.Empty(t, json)
+ assert.NotEmpty(t, failures)
+}
+
+func TestSendSuccessResponse_Success(t *testing.T) {
+ original := publisher.SendPdpUpdateResponseVar
+ defer func() { publisher.SendPdpUpdateResponseVar = original }()
+
+ mockSender := new(mocks.PdpStatusSender)
+ update := &model.PdpUpdate{RequestId: "123"}
+
+ publisher.SendPdpUpdateResponseVar = func(p publisher.PdpStatusSender, pdpUpdate *model.PdpUpdate, message string) error {
+ assert.Equal(t, "123", pdpUpdate.RequestId)
+ assert.Equal(t, "Success", message)
+ return nil
+ }
+
+ err := sendSuccessResponse(mockSender, update, "Success")
+ assert.NoError(t, err)
+}
+
+func TestSendSuccessResponse_Error(t *testing.T) {
+ original := publisher.SendPdpUpdateResponseVar
+ defer func() { publisher.SendPdpUpdateResponseVar = original }()
+
+ mockSender := new(mocks.PdpStatusSender)
+ update := &model.PdpUpdate{RequestId: "123"}
+
+ publisher.SendPdpUpdateResponseVar = func(p publisher.PdpStatusSender, pdpUpdate *model.PdpUpdate, message string) error {
+ return errors.New("mock error")
+ }
+
+ err := sendSuccessResponse(mockSender, update, "test")
+ assert.Error(t, err)
+ assert.Equal(t, "mock error", err.Error())
+}
+
+func TestPdpUpdateMessageHandler_UnmarshalError_SendFailureFails(t *testing.T) {
+ defer func() { sendFailureResponseVar = sendFailureResponse }()
+
+ mockSender := new(mocks.PdpStatusSender)
+ invalidMessage := []byte(`{invalid json}`)
+
+ sendFailureResponseVar = func(p publisher.PdpStatusSender, update *model.PdpUpdate, err error) error {
+ return errors.New("send failure after unmarshal error")
+ }
+
+ err := pdpUpdateMessageHandler(invalidMessage, mockSender)
+ assert.Error(t, err)
+ assert.EqualError(t, err, "send failure after unmarshal error")
+}
+
+func TestPdpUpdateMessageHandler_ValidationError_SendFailureFails(t *testing.T) {
+ defer func() {
+ sendFailureResponseVar = sendFailureResponse
+ utils.ValidateFieldsStructsVar = utils.ValidateFieldsStructs
+ }()
+
+ mockSender := new(mocks.PdpStatusSender)
+ message := []byte(`{"PdpSubgroup":"test", "PdpHeartbeatIntervalMs":30000}`)
+
+ utils.ValidateFieldsStructsVar = func(update model.PdpUpdate) error {
+ return errors.New("mock validation error")
+ }
+
+ sendFailureResponseVar = func(p publisher.PdpStatusSender, update *model.PdpUpdate, err error) error {
+ return errors.New("send failure after validation")
+ }
+
+ err := pdpUpdateMessageHandler(message, mockSender)
+ assert.Error(t, err)
+ assert.EqualError(t, err, "send failure after validation")
+}
+
+func TestPdpUpdateMessageHandler_DeploymentFails(t *testing.T) {
+ defer func() {
+ handlePdpUpdateDeploymentVar = handlePdpUpdateDeployment
+ handlePdpUpdateUndeploymentVar = handlePdpUpdateUndeployment
+ utils.ValidateFieldsStructsVar = utils.ValidateFieldsStructs
+ sendFinalResponseVar = sendFinalResponse
+ }()
+
+ mockSender := new(mocks.PdpStatusSender)
+ message := []byte(`{"PdpSubgroup":"test", "PdpHeartbeatIntervalMs":30000}`)
+
+ utils.ValidateFieldsStructsVar = func(update model.PdpUpdate) error {
+ return nil
+ }
+
+ handlePdpUpdateDeploymentVar = func(update model.PdpUpdate, p publisher.PdpStatusSender) (string, error, []string) {
+ return "", errors.New("deployment error"), []string{"failure"}
+ }
+
+ err := pdpUpdateMessageHandler(message, mockSender)
+ assert.Error(t, err)
+ assert.EqualError(t, err, "deployment error")
+}
+
+func TestHandlePdpUpdateDeployment_WithDeploymentFailures(t *testing.T) {
+ defer func() {
+ handlePolicyDeploymentVar = handlePolicyDeployment
+ policymap.FormatMapOfAnyTypeVar = policymap.FormatMapofAnyType
+ }()
+
+ mockSender := new(mocks.PdpStatusSender)
+
+ handlePolicyDeploymentVar = func(update model.PdpUpdate, sender publisher.PdpStatusSender) ([]string, map[string]string) {
+ return []string{"failedPolicy1"}, map[string]string{"successPolicy": "test"}
+ }
+
+ policymap.FormatMapOfAnyTypeVar = func(data interface{}) (string, error) {
+ return `{"successPolicy":"test"}`, nil
+ }
+
+ update := model.PdpUpdate{
+ PoliciesToBeDeployed: []model.ToscaPolicy{{Name: "test-policy"}},
+ }
+
+ mapJson, err, failures := handlePdpUpdateDeployment(update, mockSender)
+ assert.NoError(t, err)
+ assert.Contains(t, failures[0], "Deployment Errors")
+ assert.Contains(t, mapJson, `"successPolicy":"test"`)
+}
+
+func TestHandlePdpUpdateDeployment_FormatMapFails(t *testing.T) {
+ defer func() {
+ handlePolicyDeploymentVar = handlePolicyDeployment
+ policymap.FormatMapOfAnyTypeVar = policymap.FormatMapofAnyType
+ sendFailureResponseVar = sendFailureResponse
+ }()
+
+ mockSender := new(mocks.PdpStatusSender)
+
+ handlePolicyDeploymentVar = func(update model.PdpUpdate, sender publisher.PdpStatusSender) ([]string, map[string]string) {
+ return nil, map[string]string{"some": "policy"}
+ }
+
+ policymap.FormatMapOfAnyTypeVar = func(data interface{}) (string, error) {
+ return "", errors.New("mock formatting error")
+ }
+
+ sendFailureResponseVar = func(sender publisher.PdpStatusSender, update *model.PdpUpdate, err error) error {
+ return nil
+ }
+
+ update := model.PdpUpdate{
+ PoliciesToBeDeployed: []model.ToscaPolicy{{Name: "test-policy"}},
+ }
+
+ mapJson, err, failures := handlePdpUpdateDeployment(update, mockSender)
+ assert.NoError(t, err)
+ assert.Equal(t, "", mapJson)
+ assert.Contains(t, failures[0], "Internal Map Error")
+}
)
type (
- HandlePolicyUndeploymentFunc func(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender) ([]string, map[string]string)
- opasdkGetDataFunc func(ctx context.Context, dataPath string) (data *oapicodegen.OPADataResponse_Data, err error)
+ HandlePolicyUndeploymentFunc func(pdpUpdate model.PdpUpdate, p publisher.PdpStatusSender) ([]string, map[string]string)
+ opasdkGetDataFunc func(ctx context.Context, dataPath string) (data *oapicodegen.OPADataResponse_Data, err error)
+ policyUndeploymentActionFunc func(policy map[string]interface{}) []string
+ removeUndeployedPoliciesfromMapFunc func(undeployedPolicy map[string]interface{}) (string, error)
)
var (
removePolicyDirectoryFunc = removePolicyDirectory
- policyUndeploymentActionFunc = policyUndeploymentAction
+ policyUndeploymentActionVar policyUndeploymentActionFunc = policyUndeploymentAction
+
+ removeUndeployedPoliciesfromMapVar removeUndeployedPoliciesfromMapFunc = policymap.RemoveUndeployedPoliciesfromMap
removePolicyFromSdkandDirFunc = removePolicyFromSdkandDir
removeDataFromSdkandDirFunc = removeDataFromSdkandDir
+
+ analyseEmptyParentNodesFunc = analyseEmptyParentNodes
+
+ processDataDeletionFromSdkAndDirFunc = processDataDeletionFromSdkAndDir
)
// processPoliciesTobeUndeployed handles the undeployment of policies
func processPoliciesTobeUndeployed(undeployedPolicies map[string]string) ([]string, map[string]string) {
var failureMessages []string
+ hasFailure := false
successfullyUndeployedPolicies := make(map[string]string)
-
// Unmarshal the last known policies
deployedPolicies, err := policymap.UnmarshalLastDeployedPolicies(policymap.LastDeployedPolicies)
if err != nil {
matchedPolicy := findDeployedPolicy(policyID, policyVersion, deployedPolicies)
if matchedPolicy != nil {
// Handle undeployment for the policy
- errs := policyUndeploymentActionFunc(matchedPolicy)
+ errs := policyUndeploymentActionVar(matchedPolicy)
if len(errs) > 0 {
+ hasFailure = true
metrics.IncrementUndeployFailureCount()
metrics.IncrementTotalErrorCount()
failureMessages = append(failureMessages, errs...)
}
- deployedPoliciesMap, err := policymap.RemoveUndeployedPoliciesfromMap(matchedPolicy)
+ deployedPoliciesMap, err := removeUndeployedPoliciesfromMapVar(matchedPolicy)
if err != nil {
log.Warnf("Policy Name: %s, Version: %s is not removed from LastDeployedPolicies", policyID, policyVersion)
failureMessages = append(failureMessages, "Error in removing from LastDeployedPolicies")
}
log.Debugf("Policies Map After Undeployment : %s", deployedPoliciesMap)
- metrics.IncrementUndeploySuccessCount()
- successfullyUndeployedPolicies[policyID] = policyVersion
+ if !hasFailure {
+ metrics.IncrementUndeploySuccessCount()
+ successfullyUndeployedPolicies[policyID] = policyVersion
+ }
} else {
// Log failure if no match is found
log.Debugf("Policy Name: %s, Version: %s is marked for undeployment but was not deployed", policyID, policyVersion)
if strKey, ok := dataKey.(string); ok {
dataKeysSlice = append(dataKeysSlice, strKey)
} else {
- failureMessages = append(failureMessages, fmt.Sprintf("Invalid Key :%s", dataKey))
+ failureMessages = append(failureMessages, fmt.Sprintf("Invalid Key :%v", dataKey))
}
}
sort.Sort(utils.ByDotCount{Keys: dataKeysSlice, Ascend: false})
for _, keyPath := range dataKeysSlice {
keyPath = "/" + strings.Replace(keyPath, ".", "/", -1)
log.Debugf("Deleting data from OPA : %s", keyPath)
- // Prepare to handle any errors
- var err error
- var dataPath string
- // Fetch data first
- // Call the function to check and Analyse empty parent nodes
- if dataPath, err = analyseEmptyParentNodes(keyPath); err != nil {
- failureMessages = append(failureMessages, err.Error())
- }
- if err := deleteDataSdkFunc(context.Background(), dataPath); err != nil {
- log.Errorf("Error while deleting Data from SDK for path : %s , %v", keyPath, err.Error())
- failureMessages = append(failureMessages, err.Error())
- continue
- }
- if err := removeDataDirectoryFunc(keyPath); err != nil {
- failureMessages = append(failureMessages, err.Error())
- }
+ errs := processDataDeletionFromSdkAndDirFunc(keyPath)
+ failureMessages = append(failureMessages, errs...)
}
} else {
- failureMessages = append(failureMessages, fmt.Sprintf("%s:%s Invalid JSON structure: 'data' is missing or not an array", policy["policy-id"], policy["policy-version"]))
+ policyID, _ := policy[consts.PolicyId].(string)
+ policyVersion, _ := policy[consts.PolicyVersion].(string)
+ failureMessages = append(failureMessages, fmt.Sprintf("%v:%v Invalid JSON structure: 'data' is missing or not an array", policyID, policyVersion))
+ }
+
+ return failureMessages
+}
+
+func processDataDeletionFromSdkAndDir(keyPath string) []string {
+ var failureMessages []string
+ var dataPath string
+ var err error
+ // Fetch data first
+ // Call the function to check and Analyse empty parent nodes
+ if dataPath, err = analyseEmptyParentNodesFunc(keyPath); err != nil {
+ failureMessages = append(failureMessages, err.Error())
+ }
+ if err := deleteDataSdkFunc(context.Background(), dataPath); err != nil {
+ log.Errorf("Error while deleting Data from SDK for path : %s , %v", keyPath, err.Error())
+ failureMessages = append(failureMessages, err.Error())
+ }
+ if err := removeDataDirectoryFunc(keyPath); err != nil {
+ failureMessages = append(failureMessages, err.Error())
}
return failureMessages
+
}
// removePolicyFromSdkandDir handles the "policy" directories in the policy
}
}
} else {
- failureMessages = append(failureMessages, fmt.Sprintf("%s:%s Invalid JSON structure: 'policy' is missing or not an array", policy["policy-id"], policy["policy-version"]))
+ failureMessages = append(failureMessages, fmt.Sprintf("%s:%s Invalid JSON structure: 'policy' is missing or not an array", policy[consts.PolicyId], policy[consts.PolicyVersion]))
}
return failureMessages
func findDeployedPolicy(policyID, policyVersion string, deployedPolicies []map[string]interface{}) map[string]interface{} {
for _, policy := range deployedPolicies {
// Extract policy-id and policy-version from the deployed policy
- id, idOk := policy["policy-id"].(string)
- version, versionOk := policy["policy-version"].(string)
+ id, idOk := policy[consts.PolicyId].(string)
+ version, versionOk := policy[consts.PolicyVersion].(string)
// Check if the deployed policy matches the undeployed policy
if idOk && versionOk && id == policyID && version == policyVersion {
// ========================LICENSE_END===================================
// will process the update message from pap and send the pdp status response.
+
package handler
import (
"policy-opa-pdp/pkg/model"
"policy-opa-pdp/pkg/model/oapicodegen"
"policy-opa-pdp/pkg/policymap"
+ "reflect"
"testing"
)
assert.Equal(t, "", success["test-policy"])
}
-// Failure case: Policy undeployment fails due to missing policy
-func TestProcessPoliciesTobeUndeployed_Failure_NoMatch(t *testing.T) {
- undeployedPolicies := map[string]string{"non-existent-policy": "v1"}
-
- // Mock deployed policies (empty list)
- deployedPolicies := []map[string]interface{}{}
-
- mockPolicyMap := new(MockPolicyMap)
- mockPolicyMap.On("UnmarshalLastDeployedPolicies", mock.Anything).Return(deployedPolicies, nil)
-
- policymap.LastDeployedPolicies = `{"test-policy": "v1"}`
-
- failures, success := processPoliciesTobeUndeployed(undeployedPolicies)
-
- assert.Empty(t, success, "Expected no policies to be successfully undeployed")
- assert.Empty(t, failures, "Expected no failure messages")
-}
-
func TestProcessPoliciesTobeUndeployed_Failure_UnmarshalError(t *testing.T) {
undeployedPolicies := map[string]string{"test-policy": "v1"}
assert.Empty(t, failures, "Expected failure messages due to unmarshal error")
}
-func TestProcessPoliciesTobeUndeployed_Failure_PolicyNotFound(t *testing.T) {
- undeployedPolicies := map[string]string{"non-existent-policy": "v1"}
- mockPolicyMap := new(MockPolicyMap)
- mockPolicyMap.On("UnmarshalLastDeployedPolicies", mock.Anything).Return([]map[string]interface{}{}, nil)
-
- failures, success := processPoliciesTobeUndeployed(undeployedPolicies)
-
- assert.Empty(t, success, "Expected no successful undeployments since policy doesn't exist")
- assert.Empty(t, failures, "Failures list should be empty since policy wasn't found")
-}
-
-func TestProcessPoliciesTobeUndeployed_FailureInUndeployment(t *testing.T) {
- // Backup original function
- originalFunc := policyUndeploymentActionFunc
- defer func() { policyUndeploymentActionFunc = originalFunc }()
-
- // Mock policy undeployment action to fail
- policyUndeploymentActionFunc = func(policy map[string]interface{}) []string {
- return []string{"Failed to undeploy"}
- }
-
- mockPolicyMap := new(MockPolicyMap)
- undeployedPolicies := map[string]string{
- "policy2": "v1",
- }
-
- mockPolicy := map[string]interface{}{
- "policyID": "policy2",
- "policyVersion": "v1",
- }
-
- mockPolicyMap.On("UnmarshalLastDeployedPolicies", mock.Anything).Return([]map[string]interface{}{mockPolicy}, nil)
- mockPolicyMap.On("RemoveUndeployedPoliciesfromMap", mockPolicy).Return("{}", nil)
-
- // Run function
- failureMessages, successPolicies := processPoliciesTobeUndeployed(undeployedPolicies)
-
- // Assertions
- assert.Empty(t, failureMessages)
- assert.Empty(t, successPolicies)
-}
-
-func TestProcessPoliciesTobeUndeployed_PolicyNotDeployed(t *testing.T) {
- // Backup original function
- originalFunc := policyUndeploymentActionFunc
- defer func() { policyUndeploymentActionFunc = originalFunc }()
-
- // Mock policy undeployment action to succeed
- policyUndeploymentActionFunc = func(policy map[string]interface{}) []string {
- return nil
- }
-
- mockPolicyMap := new(MockPolicyMap)
- undeployedPolicies := map[string]string{
- "policy3": "v1",
- }
-
- mockPolicyMap.On("UnmarshalLastDeployedPolicies", mock.Anything).Return([]map[string]interface{}{}, nil)
-
- // Run function
- failureMessages, successPolicies := processPoliciesTobeUndeployed(undeployedPolicies)
-
- // Assertions
- assert.Empty(t, failureMessages)
- assert.Empty(t, successPolicies)
-}
-
-func TestProcessPoliciesTobeUndeployed_ErrorInRemoveFromMap(t *testing.T) {
- // Backup original function
- originalFunc := policyUndeploymentActionFunc
- defer func() { policyUndeploymentActionFunc = originalFunc }()
-
- // Mock policy undeployment action to succeed
- policyUndeploymentActionFunc = func(policy map[string]interface{}) []string {
- return nil
- }
-
- mockPolicyMap := new(MockPolicyMap)
- undeployedPolicies := map[string]string{
- "policy4": "v1",
- }
-
- mockPolicy := map[string]interface{}{
- "policyID": "policy4",
- "policyVersion": "v1",
- }
-
- mockPolicyMap.On("UnmarshalLastDeployedPolicies", mock.Anything).Return([]map[string]interface{}{mockPolicy}, nil)
- mockPolicyMap.On("RemoveUndeployedPoliciesfromMap", mockPolicy).Return("", errors.New("removal error"))
-
- // Run function
- failureMessages, successPolicies := processPoliciesTobeUndeployed(undeployedPolicies)
-
- // Assertions
- assert.Empty(t, failureMessages)
- assert.Empty(t, successPolicies)
-}
-
func TestRemoveDataDirectory(t *testing.T) {
// Backup original values
originalDataPath := consts.Data
assert.Equal(t, expectedError, err.Error())
}
-// Test function for removeDataFromSdkandDir
-func TestRemoveDataFromSdkandDir(t *testing.T) {
- // Backup original functions
- originalRemoveDataDirectory := removeDataDirectoryFunc
- originalDeleteData := deleteDataSdkFunc
- defer func() {
- removeDataDirectoryFunc = originalRemoveDataDirectory // Restore after test
- deleteDataSdkFunc = originalDeleteData // Restore after test
- }()
-
- // Mock removeDataDirectoryFunc and deleteDataFunc to return errors for testing
- opasdkGetData = func(ctx context.Context, dataPath string) (data *oapicodegen.OPADataResponse_Data, err error) {
- // Mock JSON data
- mockedData := `{"mocked": {"success": "value", "error": "value"}}`
- // Create an instance of OPADataResponse_Data
- var response oapicodegen.OPADataResponse_Data
- // Unmarshal into the OPADataResponse_Data struct
- err = json.Unmarshal([]byte(mockedData), &response)
- if err != nil {
- return nil, errors.New("Error unmarshalling")
- }
- return &response, nil //
- }
- removeDataDirectoryFunc = func(dataKey string) error {
- if dataKey == "/mocked/error" {
- return errors.New("mocked remove data directory error")
- }
- return nil
- }
-
- deleteDataSdkFunc = func(ctx context.Context, keyPath string) error {
- if keyPath == "/mocked/error" {
- return errors.New("mocked delete data error")
- }
- return nil
- }
-
- policy := map[string]interface{}{
- "data": []interface{}{"mocked.success", "mocked.error"},
- }
-
- failures := removeDataFromSdkandDir(policy)
-
- assert.Len(t, failures, 1) // We expect two errors
- assert.Contains(t, failures[0], "mocked delete data error")
-}
-
func TestRemovePolicyFromSdkandDir(t *testing.T) {
// Backup original functions
originalRemovePolicyDirectory := removePolicyDirectoryFunc
t.Run(tt.name, func(t *testing.T) {
// Set mock behavior
removePolicyFromSdkandDirFunc = func(policy map[string]interface{}) []string {
- return tt.mockPolicyErrors
+ return tt.mockPolicyErrors
}
removeDataFromSdkandDirFunc = func(policy map[string]interface{}) []string {
- return tt.mockDataErrors
+ return tt.mockDataErrors
}
// Call the function under test
})
}
}
+
+func TestProcessPoliciesTobeUndeployed_FailureInUndeployment(t *testing.T) {
+
+ // Create a mock policy map
+ mockPolicyMap := new(MockPolicyMap)
+
+ // Define undeployed policies
+ undeployedPolicies := map[string]string{"policy2": "1.0.0"}
+
+ policymap.LastDeployedPolicies = `{"deployed_policies_dict": [{"policy-id": "policy2","policy-version": "1.0.0"}]}`
+
+ // Override policyUndeploymentActionFunc to return a failure
+ policyUndeploymentActionVar = func(policy map[string]interface{}) []string {
+ return []string{"Failed to undeploy"}
+ }
+
+ // Run the function
+ failureMessages, successPolicies := processPoliciesTobeUndeployed(undeployedPolicies)
+
+ // Assertions
+ assert.Equal(t, []string{"Failed to undeploy"}, failureMessages, "Expected failure message for undeployment failure")
+ assert.Empty(t, successPolicies, "No policies should be successfully undeployed")
+
+ // Ensure all expectations on the mock were met
+ mockPolicyMap.AssertExpectations(t)
+}
+
+func TestProcessPoliciesTobeUndeployed_ErrorInRemoveFromMap(t *testing.T) {
+ // Backup original function
+ policyUndeploymentActionVar = func(policy map[string]interface{}) []string {
+ return nil
+ }
+
+ undeployedPolicies := map[string]string{
+ "policy4": "v1",
+ }
+
+ policymap.LastDeployedPolicies = `{"deployed_policies_dict": [{"policy-id": "policy4","policy-version": "v1"}]}`
+ removeUndeployedPoliciesfromMapVar = func(undeployedPolicies map[string]interface{}) (string, error) {
+ return "", errors.New("removal error")
+ }
+
+ // Run function
+ failureMessages, successPolicies := processPoliciesTobeUndeployed(undeployedPolicies)
+
+ // Assertions
+ assert.Equal(t, []string{"Error in removing from LastDeployedPolicies"}, failureMessages, "Expected failure message for undeployment failure")
+ assert.NotEmpty(t, successPolicies)
+}
+
+// Test cases for countChildKeysFromJSON
+func TestCountChildKeysFromJSON(t *testing.T) {
+ tests := []struct {
+ name string
+ input map[string]interface{}
+ expected map[string]int
+ }{
+ {
+ name: "Empty JSON",
+ input: map[string]interface{}{},
+ expected: map[string]int{
+ // No child nodes
+ },
+ },
+ {
+ name: "Single Level JSON",
+ input: map[string]interface{}{
+ "key1": map[string]interface{}{
+ "child1": "value1",
+ "child2": "value2",
+ },
+ "key2": map[string]interface{}{
+ "childA": "valueA",
+ },
+ },
+ expected: map[string]int{
+ "node/key1": 2, // key1 has 2 children
+ "node/key2": 1, // key2 has 1 child
+ },
+ },
+ {
+ name: "Nested JSON",
+ input: map[string]interface{}{
+ "root": map[string]interface{}{
+ "level1": map[string]interface{}{
+ "level2": map[string]interface{}{
+ "child1": "value1",
+ "child2": "value2",
+ },
+ },
+ },
+ },
+ expected: map[string]int{
+ "node/root": 1, // root has 1 child (level1)
+ "node/root/level1": 1, // level1 has 1 child (level2)
+ "node/root/level1/level2": 2, // level2 has 2 children
+ },
+ },
+ {
+ name: "Mixed Data Types",
+ input: map[string]interface{}{
+ "parent": map[string]interface{}{
+ "child1": "string",
+ "child2": 42,
+ "child3": map[string]interface{}{
+ "subchild1": true,
+ "subchild2": nil,
+ },
+ },
+ },
+ expected: map[string]int{
+ "node/parent": 3, // parent has 3 children
+ "node/parent/child3": 2, // child3 has 2 children
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := countChildKeysFromJSON(tt.input)
+ if !reflect.DeepEqual(got, tt.expected) {
+ t.Errorf("countChildKeysFromJSON() = %v, expected %v", got, tt.expected)
+ }
+ })
+ }
+}
+
+func TestAnalyzeHierarchy(t *testing.T) {
+ tests := []struct {
+ name string
+ parentDataJson json.RawMessage
+ dataPath string
+ expectedPath string
+ expectedErr bool
+ }{
+ {
+ name: "Valid hierarchy with multiple children",
+ parentDataJson: json.RawMessage(`{
+"root": {
+"parent1": {
+"child1": {},
+"child2": {}
+},
+"parent2": {
+"child3": {}
+}
+}
+}`),
+ dataPath: "/root/parent1/child1",
+ expectedPath: "/root/parent1/child1",
+ expectedErr: false,
+ },
+ {
+ name: "Hierarchy with only one child, eligible parent",
+ parentDataJson: json.RawMessage(`{
+"root": {
+"parent1": {
+"child1": {}
+}
+}
+}`),
+ dataPath: "/root/parent1/child1",
+ expectedPath: "/root/parent1/child1",
+ expectedErr: false,
+ },
+ {
+ name: "Invalid JSON structure",
+ parentDataJson: json.RawMessage(`{
+"root": { "parent1": "child1" `), // Malformed JSON
+ dataPath: "/root/parent1/child1",
+ expectedPath: "",
+ expectedErr: true,
+ },
+ {
+ name: "Path does not exist in JSON",
+ parentDataJson: json.RawMessage(`{
+"root": {
+"parent1": {
+"child1": {}
+}
+}
+}`),
+ dataPath: "/root/parent2/child3",
+ expectedPath: "/root/parent2/child3",
+ expectedErr: false,
+ },
+ {
+ name: "Root path case",
+ parentDataJson: json.RawMessage(`{
+"root": {}
+}`),
+ dataPath: "/root",
+ expectedPath: "/root",
+ expectedErr: false,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ result, err := analyzeHierarchy(tt.parentDataJson, tt.dataPath)
+
+ if tt.expectedErr {
+ assert.Error(t, err)
+ } else {
+ assert.NoError(t, err)
+ assert.Equal(t, tt.expectedPath, result)
+ }
+ })
+ }
+}
+
+// Mock function variable for opasdkGetData
+var mockGetData func(ctx context.Context, dataPath string) (*oapicodegen.OPADataResponse_Data, error)
+
+func TestAnalyseEmptyParentNodes(t *testing.T) {
+ // Backup the original function
+ originalOpaSDKGetData := opasdkGetData
+ opasdkGetData = func(ctx context.Context, dataPath string) (*oapicodegen.OPADataResponse_Data, error) {
+ return mockGetData(ctx, dataPath)
+ }
+ defer func() {
+ opasdkGetData = originalOpaSDKGetData // Restore after test
+ }()
+
+ tests := []struct {
+ name string
+ inputPath string
+ mockResponse interface{}
+ mockError error
+ expectedOutput string
+ expectError bool
+ }{
+ // Case 1: Leaf node (no parent hierarchy)
+ {
+ name: "Leaf Node - No Parent",
+ inputPath: "/singleSegment",
+ mockResponse: nil,
+ mockError: nil,
+ expectedOutput: "/singleSegment",
+ expectError: false,
+ },
+ // Case 2: Parent exists with valid data
+ {
+ name: "Success - Valid Parent Data Exists",
+ inputPath: "/parent/child",
+ mockResponse: map[string]interface{}{
+ "child": "data",
+ },
+ mockError: nil,
+ expectedOutput: "/parent/child",
+ expectError: false,
+ },
+ // Case 3: Parent exists but is empty
+ {
+ name: "Parent Exists but is Empty",
+ inputPath: "/parent/child",
+ mockResponse: map[string]interface{}{},
+ mockError: nil,
+ expectedOutput: "/parent/child",
+ expectError: false,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ // Mock function behavior
+ opasdkGetData = func(ctx context.Context, dataPath string) (*oapicodegen.OPADataResponse_Data, error) {
+ if tt.mockResponse != nil {
+ jsonData, _ := json.Marshal(tt.mockResponse)
+ var resData oapicodegen.OPADataResponse_Data
+ _ = json.Unmarshal(jsonData, &resData)
+ return &resData, tt.mockError
+ }
+ return nil, tt.mockError
+ }
+
+ // Call function
+ output, err := analyseEmptyParentNodes(tt.inputPath)
+
+ // Validate results
+ if tt.expectError {
+ assert.Error(t, err, "Expected error but got none")
+ } else {
+ assert.NoError(t, err, "Expected no error but got one")
+ assert.Equal(t, tt.expectedOutput, output, "Unexpected output")
+ }
+ })
+ }
+}
+
+func TestProcessDataDeletionFromSdkAndDir(t *testing.T) {
+ tests := []struct {
+ name string
+ inputKeyPath string
+ mockAnalyseErr error
+ mockDeleteErr error
+ mockRemoveErr error
+ expectedFailures []string
+ }{
+ {
+ name: "Success - No errors",
+ inputKeyPath: "/valid/path",
+ mockAnalyseErr: nil,
+ mockDeleteErr: nil,
+ mockRemoveErr: nil,
+ expectedFailures: []string{},
+ },
+ {
+ name: "Failure - analyseEmptyParentNodes error",
+ inputKeyPath: "/error/path",
+ mockAnalyseErr: errors.New("failed to analyze"),
+ mockDeleteErr: nil,
+ mockRemoveErr: nil,
+ expectedFailures: []string{"failed to analyze"},
+ },
+ {
+ name: "Failure - deleteDataSdkFunc error",
+ inputKeyPath: "/delete/error",
+ mockAnalyseErr: nil,
+ mockDeleteErr: errors.New("delete failed"),
+ mockRemoveErr: nil,
+ expectedFailures: []string{"delete failed"},
+ },
+ {
+ name: "Failure - removeDataDirectoryFunc error",
+ inputKeyPath: "/remove/error",
+ mockAnalyseErr: nil,
+ mockDeleteErr: nil,
+ mockRemoveErr: errors.New("remove failed"),
+ expectedFailures: []string{"remove failed"},
+ },
+ {
+ name: "Failure - Multiple errors",
+ inputKeyPath: "/multiple/errors",
+ mockAnalyseErr: errors.New("analyse failed"),
+ mockDeleteErr: errors.New("delete failed"),
+ mockRemoveErr: errors.New("remove failed"),
+ expectedFailures: []string{"analyse failed", "delete failed", "remove failed"},
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ // Mock function variables
+ analyseEmptyParentNodesFunc = func(dataPath string) (string, error) {
+ return dataPath, tt.mockAnalyseErr
+ }
+ deleteDataSdkFunc = func(ctx context.Context, dataPath string) error {
+ return tt.mockDeleteErr
+ }
+ removeDataDirectoryFunc = func(keyPath string) error {
+ return tt.mockRemoveErr
+ }
+
+ // Call function
+ failureMessages := processDataDeletionFromSdkAndDir(tt.inputKeyPath)
+
+ // Normalize nil vs empty slice
+ if failureMessages == nil {
+ failureMessages = []string{}
+ }
+
+ // Validate results
+ assert.Equal(t, tt.expectedFailures, failureMessages, "Unexpected failure messages")
+ })
+ }
+}
+
+// Mock function for testing
+func mockProcessDataDeletion(keyPath string) []string {
+ if keyPath == "/invalid/path" {
+ return []string{"Failed to delete: " + keyPath}
+ }
+ return nil // Simulate successful deletion
+}
+
+func TestRemoveDataFromSdkandDir(t *testing.T) {
+ // Mock the function globally
+ originalProcessDataDeletion := processDataDeletionFromSdkAndDirFunc
+ processDataDeletionFromSdkAndDirFunc = mockProcessDataDeletion
+ defer func() { processDataDeletionFromSdkAndDirFunc = originalProcessDataDeletion }() // Restore after test
+
+ tests := []struct {
+ name string
+ policy map[string]interface{}
+ expectedFailures []string
+ }{
+ {
+ name: "Valid data keys",
+ policy: map[string]interface{}{
+ "data": []interface{}{"policy.rule1", "policy.rule2"},
+ },
+ expectedFailures: nil,
+ },
+ {
+ name: "Invalid data key type",
+ policy: map[string]interface{}{
+ "data": []interface{}{"policy.rule1", 123}, // Invalid integer key
+ },
+ expectedFailures: []string{"Invalid Key :123"},
+ },
+ {
+ name: "Invalid JSON structure",
+ policy: map[string]interface{}{
+ "policyId": "test-policy",
+ "policyVersion": "1.0",
+ },
+ expectedFailures: []string{": Invalid JSON structure: 'data' is missing or not an array"},
+ },
+
+ {
+ name: "Deletion failure",
+ policy: map[string]interface{}{
+ "data": []interface{}{"invalid.path"},
+ },
+ expectedFailures: []string{"Failed to delete: /invalid/path"},
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ result := removeDataFromSdkandDir(tt.policy)
+ assert.ElementsMatch(t, tt.expectedFailures, result)
+ })
+ }
+}
// It configures the Kafka producer with the given bootstrap servers and topic.
// If SASL authentication is enabled via the configuration, the necessary credentials
// are set in the producer configuration.
+//
+//nolint:gosec
func GetKafkaProducer(bootstrapServers, topic string) (*KafkaProducer, error) {
var err error
once.Do(func() {
mockProducer.AssertExpectations(t)
}
+func TestKafkaProducer_Produce_NilTopic(t *testing.T) {
+ // Arrange
+ mockProducer := new(mocks.KafkaProducerInterface)
+ topic := "test-topic"
+ kp := &KafkaProducer{
+ producer: mockProducer,
+ topic: topic,
+ }
+
+ msg := &kafka.Message{
+ TopicPartition: kafka.TopicPartition{
+ Topic: nil,
+ Partition: kafka.PartitionAny,
+ },
+ }
+
+ mockProducer.On("Produce", mock.Anything, mock.Anything).Return(nil)
+
+ err := kp.Produce(msg, nil)
+ assert.NoError(t, err)
+ assert.NotNil(t, msg.TopicPartition.Topic)
+ assert.Equal(t, topic, *msg.TopicPartition.Topic)
+ mockProducer.AssertExpectations(t)
+}
+
func TestKafkaProducer_Close(t *testing.T) {
// Arrange
mockProducer := new(mocks.KafkaProducerInterface)
m.Called()
}
+func (m *MockKafkaProducer) Flush(timeout int) int {
+
+ args := m.Called(timeout)
+ return args.Int(0)
+}
+
func mockKafkaNewProducer(conf *kafka.ConfigMap) (*kafka.Producer, error) {
// Return a mock *kafka.Producer (it doesn't have to be functional)
mockProducer := new(MockKafkaProducer)
logOutput := buf.String()
assert.Contains(t, logOutput, "KafkaProducer or producer is nil, skipping Close.")
}
+
+func TestKafkaProducer_Flush(t *testing.T) {
+ // Arrange
+ mockProducer := new(mocks.KafkaProducerInterface)
+ kp := &KafkaProducer{
+ producer: mockProducer,
+ }
+
+ mockProducer.On("Flush", 15*1000).Return(1)
+
+ // Act
+ result := kp.Flush(15 * 1000)
+
+ // Assert
+ assert.Equal(t, 1, result, "Flush should return expected value")
+ mockProducer.AssertExpectations(t)
+}
// SPDX-License-Identifier: Apache-2.0
// ========================LICENSE_END===================================
//
-
package publisher
-
import (
"errors"
"policy-opa-pdp/pkg/kafkacomm/publisher/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
-
/*
Success Case 1
TestStartHeartbeatIntervalTimer_ValidInterval
Expected Output: The ticker starts with an interval of 1000 milliseconds, and heartbeat messages are sent at this interval.
*/
func TestStartHeartbeatIntervalTimer_ValidInterval(t *testing.T) {
-
intervalMs := int64(1000)
mockSender := new(mocks.PdpStatusSender)
mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
-
StartHeartbeatIntervalTimer(intervalMs, mockSender)
mu.Lock()
defer mu.Unlock()
t.Errorf("Expected currentInterval to be %d, got %d", intervalMs, currentInterval)
}
}
-
/*
Failure Case 1
TestStartHeartbeatIntervalTimer_InvalidInterval
intervalMs := int64(-1000)
mockSender := new(mocks.PdpStatusSender)
mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
-
StartHeartbeatIntervalTimer(intervalMs, mockSender)
mu.Lock()
defer mu.Unlock()
-
if ticker != nil {
t.Log("Expected ticker to be nil for invalid interval")
}
}
-
/*
TestSendPDPHeartBeat_Success 2
Description: Test sending a heartbeat successfully.
Expected Output: Heartbeat message is sent successfully, and a debug log "Message sent successfully" is generated.
*/
func TestSendPDPHeartBeat_Success(t *testing.T) {
-
mockSender := new(mocks.PdpStatusSender)
mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
err := sendPDPHeartBeat(mockSender)
assert.NoError(t, err)
}
-
/*
TestSendPDPHeartBeat_Failure 2
Description: Test failing to send a heartbeat.
err := sendPDPHeartBeat(mockSender)
assert.Error(t, err)
}
-
/*
TestsendPDPHeartBeat_Success 3
Description: Test sending a heartbeat successfully with some deployed policies.
func TestSendPDPHeartBeat_SuccessSomeDeployedPolicies(t *testing.T) {
// Setup mock Policymap
mockPolicymap := new(MockPolicymap)
-
mockSender := new(mocks.PdpStatusSender)
mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
-
policymap.LastDeployedPolicies = "some-policies"
// Set mock behavior for policymap
mockPolicymap.On("ExtractDeployedPolicies", mock.Anything).Return(nil)
err := sendPDPHeartBeat(mockSender)
assert.NoError(t, err)
}
-
/*
TestsendPDPHeartBeat_Success 4
Description: Test sending a heartbeat successfully with no deployed policies.
func TestSendPDPHeartBeat_SuccessNoDeployedPolicies(t *testing.T) {
// Setup mock Policymap
mockPolicymap := new(MockPolicymap)
-
mockSender := new(mocks.PdpStatusSender)
mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
-
policymap.LastDeployedPolicies = ""
// Set mock behavior for policymap
mockPolicymap.On("ExtractDeployedPolicies", mock.Anything).Return(nil)
err := sendPDPHeartBeat(mockSender)
assert.NoError(t, err)
}
-
/*
TestStopTicker_Success 3
Description: Test stopping the ticker.
t.Errorf("Expected ticker to be nil")
}
}
-
/*
TestStopTicker_NotRunning 3
Description: Test stopping the ticker when it is not running.
mu.Lock()
defer mu.Unlock()
}
-
func TestStartHeartbeatIntervalTimer_TickerAlreadyRunning(t *testing.T) {
intervalMs := int64(1000)
-
mockSender := new(mocks.PdpStatusSender)
mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
-
// Start the ticker for the first time
StartHeartbeatIntervalTimer(intervalMs, mockSender)
-
StartHeartbeatIntervalTimer(intervalMs, mockSender)
-
if currentInterval != intervalMs {
t.Errorf("Expected ticker to not restart, currentInterval is %d, expected %d", currentInterval, intervalMs)
}
-
assert.NotNil(t, ticker, "Expected ticker to be running but it is nil")
}
-
func TestStartHeartbeatIntervalTimer_TickerAlreadyRunning_Case2(t *testing.T) {
intervalMs := int64(1000)
-
mockSender := new(mocks.PdpStatusSender)
mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
-
// Start the ticker for the first time
StartHeartbeatIntervalTimer(intervalMs, mockSender)
-
// Start it again
StartHeartbeatIntervalTimer(int64(201), mockSender)
-
assert.NotNil(t, ticker, "Expected ticker to be running but it is nil")
}
"github.com/confluentinc/confluent-kafka-go/v2/kafka"
"github.com/google/uuid"
"policy-opa-pdp/cfg"
- "policy-opa-pdp/consts"
"policy-opa-pdp/pkg/kafkacomm"
"policy-opa-pdp/pkg/log"
"policy-opa-pdp/pkg/model"
- "policy-opa-pdp/pkg/pdpattributes"
"time"
)
return nil
}
-
-// sends the registartion message to topic using SendPdpStatus(pdpStatus)
-func SendPdpPapRegistration(s PdpStatusSender) error {
-
- var pdpStatus = model.PdpStatus{
- MessageType: model.PDP_STATUS,
- PdpType: consts.PdpType,
- State: model.Passive,
- Healthy: model.Healthy,
- Policies: nil,
- PdpResponse: nil,
- Name: pdpattributes.PdpName,
- Description: "Pdp Status Registration Message",
- PdpGroup: consts.PdpGroup,
- }
-
- log.Debugf("Sending PDP PAP Registration Message")
-
- err := s.SendPdpStatus(pdpStatus)
- if err != nil {
- log.Warnf("Error producing message: %v\n", err)
- return err
- }
- return nil
-
-}
"fmt"
"github.com/confluentinc/confluent-kafka-go/v2/kafka"
"github.com/google/uuid"
- "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
- "policy-opa-pdp/pkg/kafkacomm/publisher/mocks"
"policy-opa-pdp/pkg/model"
"testing"
"time"
}
-func TestSendPdpPapRegistration_Success(t *testing.T) {
- mockSender := new(mocks.PdpStatusSender)
-
- mockSender.On("SendPdpStatus", mock.AnythingOfType("model.PdpStatus")).Return(nil)
-
- err := SendPdpPapRegistration(mockSender)
- assert.NoError(t, err)
- mockSender.AssertCalled(t, "SendPdpStatus", mock.AnythingOfType("model.PdpStatus"))
-}
-
-func TestSendPdpPapRegistration_Failure(t *testing.T) {
- mockSender := new(mocks.PdpStatusSender)
-
- mockSender.On("SendPdpStatus", mock.AnythingOfType("model.PdpStatus")).Return(errors.New("failed To Send"))
-
- err := SendPdpPapRegistration(mockSender)
- assert.Error(t, err, "Expected an error for failure")
- assert.EqualError(t, err, "failed To Send", "Error messages should match")
- mockSender.AssertCalled(t, "SendPdpStatus", mock.AnythingOfType("model.PdpStatus"))
-}
-
// New
type MockKafkaProducer struct {
"github.com/google/uuid"
)
+type(
+ SendPdpUpdateResponseFunc func(s PdpStatusSender, pdpUpdate *model.PdpUpdate, resMessage string) error
+)
+
+var (
+ SendPdpUpdateResponseVar SendPdpUpdateResponseFunc = SendPdpUpdateResponse
+)
+
// Sends a PDP_STATUS message to indicate the successful processing of a PDP_UPDATE request
// received from the Policy Administration Point (PAP).
func SendPdpUpdateResponse(s PdpStatusSender, pdpUpdate *model.PdpUpdate, resMessage string) error {
err = s.SendPdpStatus(pdpStatus)
if err != nil {
- log.Warnf("Failed to send PDP Update Message : %v", err)
+ log.Warnf("Failed to send PDP Update Error Message : %v", err)
return err
}
err := s.SendPdpStatus(pdpStatus)
if err != nil {
- log.Warnf("Failed to send PDP Update Message : %v", err)
+ log.Warnf("Failed to send PDP State Change Message : %v", err)
return err
}
"policy-opa-pdp/pkg/log"
"policy-opa-pdp/pkg/model/oapicodegen"
"policy-opa-pdp/pkg/utils"
-
+ "policy-opa-pdp/consts"
"github.com/google/uuid"
openapi_types "github.com/oapi-codegen/runtime/types"
)
func FetchCurrentStatistics(res http.ResponseWriter, req *http.Request) {
- requestId := req.Header.Get("X-ONAP-RequestID")
+ requestId := req.Header.Get(consts.RequestId)
var parsedUUID *uuid.UUID
var statisticsParams *oapicodegen.StatisticsParams
statisticsParams = &oapicodegen.StatisticsParams{
XONAPRequestID: (*openapi_types.UUID)(parsedUUID),
}
- res.Header().Set("X-ONAP-RequestID", statisticsParams.XONAPRequestID.String())
+ res.Header().Set(consts.RequestId, statisticsParams.XONAPRequestID.String())
}
} else {
log.Warnf("Invalid or Missing Request ID")
requestId = "000000000000"
- res.Header().Set("X-ONAP-RequestID", requestId)
+ res.Header().Set(consts.RequestId, requestId)
}
var statReport oapicodegen.StatisticsReport
import (
"encoding/json"
+ "fmt"
"net/http"
"net/http/httptest"
"policy-opa-pdp/pkg/model/oapicodegen"
assert.Equal(t, http.StatusOK, res.Code)
}
+
+type FailingResponseWriter struct {
+ http.ResponseWriter
+}
+
+func (w *FailingResponseWriter) Write(b []byte) (int, error) {
+ return 0, fmt.Errorf("forced encoding failure")
+}
+
+func TestFetchCurrentStatistics_JSONEncodingFailure(t *testing.T) {
+ req := httptest.NewRequest("GET", "/statistics", nil)
+ w := httptest.NewRecorder()
+
+ // Wrap the ResponseWriter to force an error
+ failingWriter := &FailingResponseWriter{w}
+
+ FetchCurrentStatistics(failingWriter, req)
+ resp := w.Result()
+ defer resp.Body.Close()
+
+ assert.Equal(t, http.StatusOK, resp.StatusCode)
+}
func UpsertPolicy(ctx context.Context, policyID string, policyContent []byte) error {
txn, err := memStore.NewTransaction(ctx, storage.WriteParams)
if err != nil {
- log.Warnf("Error creating transaction: %s", err)
+ log.Warnf("Error creating transaction While Upsert Policy: %s", err)
memStore.Abort(ctx, txn)
return err
}
}
err = memStore.Commit(ctx, txn)
if err != nil {
- log.Warnf("Error commiting the transaction: %s", err)
+ log.Warnf("Error commiting the transaction while upsert policy: %s", err)
memStore.Abort(ctx, txn)
return err
}
func DeletePolicy(ctx context.Context, policyID string) error {
txn, err := memStore.NewTransaction(ctx, storage.WriteParams)
if err != nil {
- log.Warnf("Error creating transaction: %s", err)
+ log.Warnf("Error creating transaction while delete policy: %s", err)
memStore.Abort(ctx, txn)
return err
}
}
err = memStore.Commit(ctx, txn)
if err != nil {
- log.Warnf("Error commiting the transaction: %s", err)
+ log.Warnf("Error commiting the transaction while delete policy: %s", err)
memStore.Abort(ctx, txn)
return err
}
func WriteData(ctx context.Context, dataPath string, data interface{}) error {
txn, err := memStore.NewTransaction(ctx, storage.WriteParams)
if err != nil {
- log.Warnf("Error creating transaction: %s", err)
+ log.Warnf("Error creating transaction while write data: %s", err)
memStore.Abort(ctx, txn)
return err
}
}
err = memStore.Commit(ctx, txn)
if err != nil {
- log.Warnf("Error commiting the transaction: %s", err)
+ log.Warnf("Error commiting the transaction while write data: %s", err)
memStore.Abort(ctx, txn)
return err
}
func DeleteData(ctx context.Context, dataPath string) error {
txn, err := memStore.NewTransaction(ctx, storage.WriteParams)
if err != nil {
- log.Warnf("Error creating transaction: %s", err)
+ log.Warnf("Error creating transaction while Delete Data: %s", err)
memStore.Abort(ctx, txn)
return err
}
}
err = memStore.Commit(ctx, txn)
if err != nil {
- log.Warnf("Error commiting the transaction: %s", err)
+ log.Warnf("Error commiting the transaction while Delete Data: %s", err)
memStore.Abort(ctx, txn)
return err
}
ctx := context.Background()
rtxn, err := memStore.NewTransaction(ctx, storage.TransactionParams{Write: false})
if err != nil {
- log.Warnf("Error creating transaction %s", err)
+ log.Warnf("Error creating transaction while listing policies: %s", err)
memStore.Abort(ctx, rtxn)
http.Error(res, err.Error(), http.StatusInternalServerError)
return
func PatchData(ctx context.Context, patches []PatchImpl) error {
txn, err := memStore.NewTransaction(ctx, storage.WriteParams)
if err != nil {
- log.Warnf("Error in creating transaction: %s", err)
+ log.Warnf("Error in creating transaction while Patch Data: %s", err)
memStore.Abort(ctx, txn)
return err
}
txn := new(storage.Transaction)
mockMemStore.On("NewTransaction", ctx, mock.Anything).Return(txn, nil)
- mockMemStore.On("ListPolicies", ctx, mock.AnythingOfType("*opasdk.MockTransaction")).Return([]string{}, errors.New("GetPolicy error"))
+ mockMemStore.On("ListPolicies", ctx, mock.AnythingOfType("*opasdk.MockTransaction")).Return([]string{"policyId"}, nil)
+ mockMemStore.On("GetPolicy", ctx, mock.AnythingOfType("*opasdk.MockTransaction"), "policyId").Return([]byte{}, errors.New("GetPolicy error"))
mockMemStore.On("Abort", ctx, mock.AnythingOfType("*opasdk.MockTransaction")).Return(nil)
req := httptest.NewRequest("GET", "/opa/listpolicies", nil)
import (
"encoding/json"
"fmt"
+ "policy-opa-pdp/consts"
"policy-opa-pdp/pkg/log"
"policy-opa-pdp/pkg/model"
)
+type (
+ FormatMapOfAnyTypeFunc[T any] func(mapOfAnyType T) (string, error)
+)
+
var (
- LastDeployedPolicies string
+ LastDeployedPolicies string
+ FormatMapOfAnyTypeVar FormatMapOfAnyTypeFunc[interface{}] = FormatMapofAnyType
)
func formatPolicyAndDataMap(deployedPolicies []map[string]interface{}) (string, error) {
}
// Marshal the final map into JSON
- policyDataJSON, err := FormatMapofAnyType(finalMap)
+ policyDataJSON, err := FormatMapOfAnyTypeVar(finalMap)
if err != nil {
return "", fmt.Errorf("failed to format json: %v", err)
}
// Unmarshal the last known policies
deployedPolicies, err := UnmarshalLastDeployedPolicies(LastDeployedPolicies)
if err != nil {
- log.Warnf("Failed to unmarshal LastDeployedPolicies: %v", err)
+ log.Warnf("Failed to unmarshal LastDeployedPolicies While Updating Deployed Policies: %v", err)
}
dataKeys := make([]string, 0, len(policy.Properties.Data))
}
directoryMap := map[string]interface{}{
- "policy-id": policy.Metadata.PolicyID,
- "policy-version": policy.Metadata.PolicyVersion,
- "data": dataKeys,
- "policy": policyKeys,
+ consts.PolicyId: policy.Metadata.PolicyID,
+ consts.PolicyVersion: policy.Metadata.PolicyVersion,
+ "data": dataKeys,
+ "policy": policyKeys,
}
deployedPolicies = append(deployedPolicies, directoryMap)
return formatPolicyAndDataMap(deployedPolicies)
// Unmarshal the last known policies
deployedPolicies, err := UnmarshalLastDeployedPolicies(LastDeployedPolicies)
if err != nil {
- log.Warnf("Failed to unmarshal LastDeployedPolicies: %v", err)
+ log.Warnf("Failed to unmarshal LastDeployedPolicies While Removing Undeployed Policies From Map: %v", err)
}
remainingPolicies := []map[string]interface{}{}
for _, policy := range deployedPolicies {
shouldRetain := true
- if policy["policy-id"] == undeployedPolicy["policy-id"] && policy["policy-version"] == undeployedPolicy["policy-version"] {
+ if policy[consts.PolicyId] == undeployedPolicy[consts.PolicyId] && policy[consts.PolicyVersion] == undeployedPolicy[consts.PolicyVersion] {
shouldRetain = false
}
if shouldRetain {
var policiesMap PoliciesMap
err := json.Unmarshal([]byte(lastdeployedPoliciesMap), &policiesMap)
if err != nil {
- log.Warnf("Failed to unmarshal LastDeployedPolicies: %v", err)
+ log.Warnf("Failed to unmarshal LastDeployedPolicies While Verifying Policies to be deployed: %v", err)
return pdpUpdate.PoliciesToBeDeployed
}
for _, deployingPolicy := range pdpUpdate.PoliciesToBeDeployed {
shouldDeploy := true
for _, deployedPolicy := range deployedPolicies {
- if deployedPolicy["policy-id"] == deployingPolicy.Name && deployedPolicy["policy-version"] == deployingPolicy.Version {
+ if deployedPolicy[consts.PolicyId] == deployingPolicy.Name && deployedPolicy[consts.PolicyVersion] == deployingPolicy.Version {
log.Infof("Policy Previously deployed: %v %v, skipping", deployingPolicy.Name, deployingPolicy.Version)
shouldDeploy = false
break
// Unmarshal the last known policies
deployedPolicies, err := UnmarshalLastDeployedPolicies(policiesMap)
if err != nil {
- log.Warnf("Failed to unmarshal LastDeployedPolicies: %v", err)
+ log.Warnf("Failed to unmarshal LastDeployedPolicies While Extracting Deployed Policies: %v", err)
}
pdpstatus := model.PdpStatus{
for _, policy := range deployedPolicies {
// Extract policy-id and policy-version
- policyID, idOk := policy["policy-id"].(string)
- policyVersion, versionOk := policy["policy-version"].(string)
+ policyID, idOk := policy[consts.PolicyId].(string)
+ policyVersion, versionOk := policy[consts.PolicyVersion].(string)
if !idOk || !versionOk {
log.Warnf("Missing or invalid policy-id or policy-version")
return nil
// Unmarshal the last known policies
deployedPolicies, err := UnmarshalLastDeployedPolicies(LastDeployedPolicies)
if err != nil {
- log.Warnf("Failed to unmarshal LastDeployedPolicies: %v", err)
+ log.Warnf("Failed to unmarshal LastDeployedPolicies While Checking if Policy Already Exists: %v", err)
}
log.Debugf("deployedPolicies %s", deployedPolicies)
for _, policy := range deployedPolicies {
- if policy["policy-id"] == policyId {
+ if policy[consts.PolicyId] == policyId {
return true
}
}
func GetTotalDeployedPoliciesCountFromMap() int {
deployedPolicies, err := UnmarshalLastDeployedPolicies(LastDeployedPolicies)
if err != nil {
- log.Warnf("Failed to unmarshal LastDeployedPolicies: %v", err)
+ log.Warnf("Failed to unmarshal LastDeployedPolicies While Getting TotalDeployedPoliciesCountFromMap: %v", err)
return 0
}
return len(deployedPolicies)
--- /dev/null
+// -
+// ========================LICENSE_START=================================
+// Copyright (C) 2025: Deutsche Telekom
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// SPDX-License-Identifier: Apache-2.0
+// ========================LICENSE_END===================================
+
+// Package provides sorting functionalities.
+
+package utils
+
+import (
+ "sort"
+ "testing"
+)
+
+// Test sorting in ascending order by dot count
+func TestByDotCountAscending(t *testing.T) {
+ keys := []string{"a.b.c", "a.b", "a.b.c.d", "a"}
+ expected := []string{"a", "a.b", "a.b.c", "a.b.c.d"}
+
+ sort.Sort(ByDotCount{Keys: keys, Ascend: true})
+
+ for i, v := range keys {
+ if v != expected[i] {
+ t.Errorf("Ascending sort failed. Expected %s, got %s", expected[i], v)
+ }
+ }
+}
+
+// Test sorting in descending order by dot count
+func TestByDotCountDescending(t *testing.T) {
+ keys := []string{"a.b.c", "a.b", "a.b.c.d", "a"}
+ expected := []string{"a.b.c.d", "a.b.c", "a.b", "a"}
+
+ sort.Sort(ByDotCount{Keys: keys, Ascend: false})
+
+ for i, v := range keys {
+ if v != expected[i] {
+ t.Errorf("Descending sort failed. Expected %s, got %s", expected[i], v)
+ }
+ }
+}
+
+// Test sorting with equal dot counts
+func TestByDotCountEqualDots(t *testing.T) {
+ keys := []string{"a.b.c", "x.y.z", "m.n.o"}
+ expected := []string{"a.b.c", "x.y.z", "m.n.o"} // Order should be preserved as all have same dots
+
+ sort.Sort(ByDotCount{Keys: keys, Ascend: true})
+
+ for i, v := range keys {
+ if v != expected[i] {
+ t.Errorf("Equal dot count sorting failed. Expected %s, got %s", expected[i], v)
+ }
+ }
+}
type (
CreateDirectoryFunc func(dirPath string) error
+ ValidateFieldsStructsFunc func(pdpUpdate model.PdpUpdate) error
)
var (
CreateDirectoryVar CreateDirectoryFunc = CreateDirectory
removeAll = os.RemoveAll
+ ValidateFieldsStructsVar ValidateFieldsStructsFunc = ValidateFieldsStructs
)
// validates if the given request is in valid uuid form
}
if policy.Properties.Data != nil {
- // 2. Validate that Name is a suffix for keys in Properties.Data and Properties.Policy.
- keySeen := make(map[string]bool)
- for key := range policy.Properties.Data {
- if keySeen[key] {
- return fmt.Errorf("duplicate data key '%s' found, '%s'", key, emphasize)
- }
- keySeen[key] = true
- if !strings.HasPrefix(key, "node."+policy.Name) {
- return fmt.Errorf("data key '%s' does not have name node.'%s' as a prefix, '%s'", key, policy.Name, emphasize)
- }
+ log.Debugf("Validating properties data for policy: %s", policy.Name)
+ if err := validateDataKeys(policy.Properties.Data, "node."+policy.Name, "data", emphasize); err != nil {
+ return err
}
}
+
+ log.Debugf("Validating properties policy for policy: %s", policy.Name)
+ if err := validatePolicyKeys(policy.Properties.Policy, policy.Name, "policy", emphasize); err != nil {
+ return err
+ }
+
+ log.Infof("Validation successful for policy: %s", policy.Name)
+ return nil
+}
+
+func validatePolicyKeys(policy map[string]string, prefix, propertyType, emphasize string) error {
keySeen := make(map[string]bool)
- for key := range policy.Properties.Policy {
+ for key := range policy {
if keySeen[key] {
- return fmt.Errorf("duplicate policy key '%s' found, '%s'", key, emphasize)
+ return fmt.Errorf("duplicate %s key '%s' found, '%s'", propertyType, key, emphasize)
}
keySeen[key] = true
- if !strings.HasPrefix(key, policy.Name) {
- return fmt.Errorf("policy key '%s' does not have name '%s' as a prefix, '%s'", key, policy.Name, emphasize)
+ if !strings.HasPrefix(key, prefix) {
+ return fmt.Errorf("%s key '%s' does not have name '%s' as a prefix, '%s'", propertyType, key, prefix, emphasize)
}
}
+ return nil
+}
+func validateDataKeys(data map[string]string, prefix, propertyType, emphasize string) error {
+ keySeen := make(map[string]bool)
+ for key := range data {
+ if keySeen[key] {
+ return fmt.Errorf("duplicate %s key '%s' found, '%s'", propertyType, key, emphasize)
+ }
+ keySeen[key] = true
+ if !strings.HasPrefix(key, prefix) {
+ return fmt.Errorf("data key '%s' does not have name '%s' as a prefix", key, prefix)
+ }
+ }
return nil
}
return string(output), nil
}
-// Validation function
-func ValidateOPADataRequest(request interface{}) []string {
- var validationErrors []string
- if updateRequest, ok := request.(*oapicodegen.OPADataUpdateRequest); ok {
- if updateRequest == nil { // Check if updateRequest is nil
- validationErrors = append(validationErrors, "OPADataUpdateRequest is nil")
- return validationErrors // Return if the request is nil
- }
- // Check if required fields are populated
- if updateRequest.CurrentDate != nil {
- dateString := updateRequest.CurrentDate.String()
- if !IsValidCurrentDate(&dateString) {
- validationErrors = append(validationErrors, "CurrentDate is invalid")
- }
- } else {
- validationErrors = append(validationErrors, "CurrentDate is required")
- }
-
- // Validate CurrentDateTime format
- if !(IsValidTime(updateRequest.CurrentDateTime)) {
- validationErrors = append(validationErrors, "CurrentDateTime is invalid or missing")
- }
- // Validate CurrentTime format
- if !(IsValidCurrentTime(updateRequest.CurrentTime)) {
- validationErrors = append(validationErrors, "CurrentTime is invalid or missing")
- }
+type CommonFields struct {
+ CurrentDate *string
+ CurrentDateTime *time.Time
+ CurrentTime *string
+ TimeOffset *string
+ TimeZone *string
+ OnapComponent *string
+ OnapInstance *string
+ OnapName *string
+ PolicyName string
+}
- // Validate TimeOffset format (e.g., +02:00 or -05:00)
- if !(IsValidTimeOffset(updateRequest.TimeOffset)) {
- validationErrors = append(validationErrors, "TimeOffset is invalid or missing")
- }
+func ValidateOPADataRequest(request interface{}) []string {
+ // var validationErrors []string
- // Validate TimeZone format (e.g., 'America/New_York')
- if !(IsValidTimeZone(updateRequest.TimeZone)) {
- validationErrors = append(validationErrors, "TimeZone is invalid or missing")
- }
+ if request == nil {
+ return []string{"Request is nil"}
+ }
- // Optionally, check if 'OnapComponent', 'OnapInstance', 'OnapName', and 'PolicyName' are provided
- if !(IsValidString(updateRequest.OnapComponent)) {
- validationErrors = append(validationErrors, "OnapComponent is required")
+ // Handle OPADataUpdateRequest validation
+ if updateReq, ok := request.(*oapicodegen.OPADataUpdateRequest); ok {
+ currentDate := ""
+ if updateReq.CurrentDate != nil {
+ currentDate = updateReq.CurrentDate.String()
}
- if !(IsValidString(updateRequest.OnapInstance)) {
- validationErrors = append(validationErrors, "OnapInstance is required")
- }
+ commonFields := CommonFields{
+ CurrentDate: ¤tDate,
+ CurrentDateTime: updateReq.CurrentDateTime,
+ CurrentTime: updateReq.CurrentTime,
+ TimeOffset: updateReq.TimeOffset,
+ TimeZone: updateReq.TimeZone,
+ OnapComponent: updateReq.OnapComponent,
+ OnapInstance: updateReq.OnapInstance,
+ OnapName: updateReq.OnapName,
+ PolicyName: convertPtrToString(updateReq.PolicyName),
- if !(IsValidString(updateRequest.OnapName)) {
- validationErrors = append(validationErrors, "OnapName is required")
}
+ return validateCommonFields(commonFields)
- if !(IsValidString(updateRequest.PolicyName)) {
- validationErrors = append(validationErrors, "PolicyName is required and cannot be empty")
- }
}
- if decisionRequest, ok := request.(*oapicodegen.OPADecisionRequest); ok {
-
- if decisionRequest == nil { // Check if decisionRequest is nil
- validationErrors = append(validationErrors, "OPADecisionRequest is nil")
- return validationErrors // Return if the request is nil
- }
- // Check if required fields are populated
- if decisionRequest.CurrentDate != nil {
- dateString := decisionRequest.CurrentDate.String()
- if !IsValidCurrentDate(&dateString) {
- validationErrors = append(validationErrors, "CurrentDate is invalid")
- }
+ // Handle OPADecisionRequest validation
+ if decisionReq, ok := request.(*oapicodegen.OPADecisionRequest); ok {
+ currentDate := ""
+ if decisionReq.CurrentDate != nil {
+ currentDate = decisionReq.CurrentDate.String()
}
- // Validate CurrentDateTime format
- if (decisionRequest.CurrentDateTime != nil) && !(IsValidTime(decisionRequest.CurrentDateTime)) {
- validationErrors = append(validationErrors, "CurrentDateTime is invalid or missing")
+ commonFields := CommonFields{
+ CurrentDate: ¤tDate,
+ CurrentDateTime: decisionReq.CurrentDateTime,
+ CurrentTime: decisionReq.CurrentTime,
+ TimeOffset: decisionReq.TimeOffset,
+ TimeZone: decisionReq.TimeZone,
+ OnapComponent: decisionReq.OnapComponent,
+ OnapInstance: decisionReq.OnapInstance,
+ OnapName: decisionReq.OnapName,
+ PolicyName: decisionReq.PolicyName,
}
+ return validateCommonFields(commonFields)
- // Validate CurrentTime format
- if (decisionRequest.CurrentTime != nil) && !(IsValidCurrentTime(decisionRequest.CurrentTime)) {
- validationErrors = append(validationErrors, "CurrentTime is invalid or missing")
- }
-
- // Validate TimeOffset format (e.g., +02:00 or -05:00)
- if (decisionRequest.TimeOffset != nil) && !(IsValidTimeOffset(decisionRequest.TimeOffset)) {
- validationErrors = append(validationErrors, "TimeOffset is invalid or missing")
- }
+ }
+ return []string{"Invalid request type"}
+}
- // Validate TimeZone format (e.g., 'America/New_York')
- if (decisionRequest.TimeZone != nil) && !(IsValidTimeZone(decisionRequest.TimeZone)) {
- validationErrors = append(validationErrors, "TimeZone is invalid or missing")
- }
+func convertPtrToString(stringPtr *string) string {
+ if stringPtr != nil {
+ return *stringPtr
+ }
+ return ""
- // Optionally, check if 'OnapComponent', 'OnapInstance', 'OnapName', and 'PolicyName' are provided
- if (decisionRequest.OnapComponent != nil) && !(IsValidString(decisionRequest.OnapComponent)) {
- validationErrors = append(validationErrors, "OnapComponent is required")
- }
+}
- if (decisionRequest.OnapInstance != nil) && !(IsValidString(decisionRequest.OnapInstance)) {
- validationErrors = append(validationErrors, "OnapInstance is required")
- }
+// Helper function to validate common fields
+func validateCommonFields(fields CommonFields) []string {
- if (decisionRequest.OnapName != nil) && !(IsValidString(decisionRequest.OnapName)) {
- validationErrors = append(validationErrors, "OnapName is required")
- }
+ var validationErrors []string
- if !(IsValidString(decisionRequest.PolicyName)) {
- validationErrors = append(validationErrors, "PolicyName is required and cannot be empty")
- }
+ if fields.CurrentDate == nil || !IsValidCurrentDate(fields.CurrentDate) {
+ validationErrors = append(validationErrors, "CurrentDate is invalid or missing")
+ }
+ if fields.CurrentDateTime == nil || !IsValidTime(fields.CurrentDateTime) {
+ validationErrors = append(validationErrors, "CurrentDateTime is invalid or missing")
+ }
+ if fields.CurrentTime == nil || !IsValidCurrentTime(fields.CurrentTime) {
+ validationErrors = append(validationErrors, "CurrentTime is invalid or missing")
}
+ if fields.TimeOffset == nil || !IsValidTimeOffset(fields.TimeOffset) {
+ validationErrors = append(validationErrors, "TimeOffset is invalid or missing")
+ }
+ if fields.TimeZone == nil || !IsValidTimeZone(fields.TimeZone) {
+ validationErrors = append(validationErrors, "TimeZone is invalid or missing")
+ }
+ if !IsValidString(fields.OnapComponent) {
+ validationErrors = append(validationErrors, "OnapComponent is required")
+ }
+ if !IsValidString(fields.OnapInstance) {
+ validationErrors = append(validationErrors, "OnapInstance is required")
+ }
+ if !IsValidString(fields.OnapName) {
+ validationErrors = append(validationErrors, "OnapName is required")
+ }
+ if !IsValidString(fields.PolicyName) {
+ validationErrors = append(validationErrors, "PolicyName is required and cannot be empty")
+ }
+
return validationErrors
}
assert.Error(t, err)
}
-func TestCreateDirectory_InvalidPath(t *testing.T) {
- tempDir := "/invalid///path"
- defer os.RemoveAll(tempDir)
- err := CreateDirectory(tempDir)
- assert.Error(t, err)
-}
-
func TestRemoveDirectory_Positive(t *testing.T) {
tempDir, err := os.MkdirTemp("", "testdir")
assert.NoError(t, err)
err := ValidateToscaPolicyJsonFields(policy)
assert.Error(t, err, "Expected error due to invalid data key prefix")
- assert.Contains(t, err.Error(), "data key 'invalid-key' does not have name node.'test-policy' as a prefix")
+ assert.Contains(t, err.Error(), "data key 'invalid-key' does not have name 'node.test-policy' as a prefix")
}
func TestIsValidTime(t *testing.T) {
})
}
-func TestValidateOPADataRequest(t *testing.T) {
- ctime := "08:26:41.857Z"
- onapComp := "COMPONENT"
- onapIns := "INSTANCE"
- onapName := "ONAP"
- policyName := "s3"
+// Helper function to create string pointers
+func strPtr(s string) *string {
+ return &s
+}
+
+// Helper function to create time pointers
+func timePtr(t time.Time) *time.Time {
+ return &t
+}
+
+func TestValidateOPADataRequest_UpdateRequest_Valid(t *testing.T) {
+
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")
}
+ ctime := "08:26:41.857Z"
- inValidDecisionRequest := &oapicodegen.OPADecisionRequest{
+ updateReq := &oapicodegen.OPADataUpdateRequest{
CurrentDate: ¤tDate,
CurrentDateTime: ¤tDateTime,
+ CurrentTime: &ctime,
+ TimeOffset: strPtr("+00:00"),
+ TimeZone: strPtr("UTC"),
+ OnapComponent: strPtr("Component"),
+ OnapInstance: strPtr("Instance"),
+ OnapName: strPtr("Onap"),
+ PolicyName: strPtr("Policy1"),
}
- var data []map[string]interface{}
+ errors := ValidateOPADataRequest(updateReq)
+ assert.Empty(t, errors, "Expected no validation errors")
+}
+
+func TestValidateOPADataRequest_UpdateRequest_MissingFields(t *testing.T) {
+ updateReq := &oapicodegen.OPADataUpdateRequest{}
+
+ errors := ValidateOPADataRequest(updateReq)
+ assert.NotEmpty(t, errors, "Expected validation errors for missing fields")
+}
- data = nil
+func TestValidateOPADataRequest_DecisionRequest_Valid(t *testing.T) {
+ parsedDate, err := time.Parse("2006-01-02", "2024-02-12")
+ if err != nil {
+ fmt.Println("error in parsedDate")
+ }
- inValidRequest := &oapicodegen.OPADataUpdateRequest{
+ 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")
+ }
+ ctime := "08:26:41.857Z"
+
+ decisionReq := &oapicodegen.OPADecisionRequest{
CurrentDate: ¤tDate,
CurrentDateTime: ¤tDateTime,
CurrentTime: &ctime,
- OnapComponent: &onapComp,
- OnapInstance: &onapIns,
- OnapName: &onapName,
- PolicyName: &policyName,
- Data: &data,
+ TimeOffset: strPtr("+00:00"),
+ TimeZone: strPtr("UTC"),
+ OnapComponent: strPtr("Component"),
+ OnapInstance: strPtr("Instance"),
+ OnapName: strPtr("Onap"),
+ PolicyName: "Policy2",
+ }
+
+ errors := ValidateOPADataRequest(decisionReq)
+ assert.Empty(t, errors, "Expected no validation errors")
+}
+
+func TestValidateOPADataRequest_DecisionRequest_MissingFields(t *testing.T) {
+ decisionReq := &oapicodegen.OPADecisionRequest{}
+
+ errors := ValidateOPADataRequest(decisionReq)
+ assert.NotEmpty(t, errors, "Expected validation errors for missing fields")
+}
+
+func TestValidateOPADataRequest_InvalidRequestType(t *testing.T) {
+ invalidReq := struct{}{}
+
+ errors := ValidateOPADataRequest(invalidReq)
+ assert.Equal(t, []string{"Invalid request type"}, errors, "Expected 'Invalid request type' error")
+}
+
+func TestConvertPtrToString(t *testing.T) {
+ str := "test"
+ assert.Equal(t, "test", convertPtrToString(&str), "Expected 'test' as output")
+ assert.Equal(t, "", convertPtrToString(nil), "Expected empty string as output")
+}
+
+// Test validatePolicyKeys
+func TestValidatePolicyKeys(t *testing.T) {
+ tests := []struct {
+ name string
+ policy map[string]string
+ prefix string
+ propertyType string
+ emphasize string
+ wantErr string
+ }{
+ {
+ name: "Valid policy keys",
+ policy: map[string]string{
+ "policy_1": "value1",
+ "policy_2": "value2",
+ },
+ prefix: "policy_",
+ propertyType: "policy",
+ emphasize: "important",
+ wantErr: "",
+ },
+ {
+ name: "Policy key without proper prefix",
+ policy: map[string]string{
+ "invalid_1": "value1",
+ },
+ prefix: "policy_",
+ propertyType: "policy",
+ emphasize: "important",
+ wantErr: "policy key 'invalid_1' does not have name 'policy_' as a prefix, 'important'",
+ },
+ {
+ name: "Empty policy map",
+ policy: map[string]string{},
+ prefix: "policy_",
+ propertyType: "policy",
+ emphasize: "important",
+ wantErr: "",
+ },
}
- inValidErr := []string{"TimeOffset is invalid or missing", "TimeZone is invalid or missing"}
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ err := validatePolicyKeys(tt.policy, tt.prefix, tt.propertyType, tt.emphasize)
+ if err != nil {
+ if err.Error() != tt.wantErr {
+ t.Errorf("Expected error: '%s', got: '%s'", tt.wantErr, err.Error())
+ }
+ } else if tt.wantErr != "" {
+ t.Errorf("Expected error: '%s', got nil", tt.wantErr)
+ }
+ })
+ }
+}
- inValidDecisionErrs := []string{"PolicyName is required and cannot be empty"}
+// Test validateDataKeys
+func TestValidateDataKeys(t *testing.T) {
tests := []struct {
- name string
- request interface{}
- expectedErr []string
+ name string
+ data map[string]string
+ prefix string
+ propertyType string
+ emphasize string
+ wantErr string
}{
- {"Valid Request", inValidRequest, inValidErr},
- {"Invalid OPADecisionRequest", inValidDecisionRequest, inValidDecisionErrs},
+ {
+ name: "Valid data keys",
+ data: map[string]string{
+ "data_1": "value1",
+ "data_2": "value2",
+ },
+ prefix: "data_",
+ propertyType: "data",
+ emphasize: "critical",
+ wantErr: "",
+ },
+ {
+ name: "Data key without proper prefix",
+ data: map[string]string{
+ "invalid_1": "value1",
+ },
+ prefix: "data_",
+ propertyType: "data",
+ emphasize: "critical",
+ wantErr: "data key 'invalid_1' does not have name 'data_' as a prefix",
+ },
+ {
+ name: "Empty data map",
+ data: map[string]string{},
+ prefix: "data_",
+ propertyType: "data",
+ emphasize: "critical",
+ wantErr: "",
+ },
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- errors := ValidateOPADataRequest(tt.request)
- fmt.Printf("error : %s", errors)
- fmt.Printf("error len : %d", len(errors))
- assert.Equal(t, tt.expectedErr, errors)
+ err := validateDataKeys(tt.data, tt.prefix, tt.propertyType, tt.emphasize)
+ if err != nil {
+ if err.Error() != tt.wantErr {
+ t.Errorf("Expected error: '%s', got: '%s'", tt.wantErr, err.Error())
+ }
+ } else if tt.wantErr != "" {
+ t.Errorf("Expected error: '%s', got nil", tt.wantErr)
+ }
})
}
}