Resolving merge conflicts

This commit is contained in:
tanyamadaan
2025-03-27 17:25:00 +05:30
10 changed files with 823 additions and 14 deletions

74
.github/workflows/beckn_ci_test.yml vendored Normal file
View File

@@ -0,0 +1,74 @@
name: CI/CD Test Pipeline
on:
pull_request:
branches:
- beckn-onix-v1.0-develop
env:
APP_DIRECTORY: "shared/plugin" # Root directory to start searching from
jobs:
lint_and_test:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
timeout-minutes: 10 # Increased timeout due to additional steps
steps:
# 1. Checkout the code from the test branch (triggered by PR)
- name: Checkout code
uses: actions/checkout@v4
# 2. Set up Go environment
- name: Set up Go 1.24.0
uses: actions/setup-go@v4
with:
go-version: '1.24.0'
# 3. Install golangci-lint
- name: Install golangci-lint
run: |
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
# 4. Run golangci-lint on the entire repo, starting from the root directory
- name: Run golangci-lint
run: |
golangci-lint run ./... # This will lint all Go files in the repo and subdirectories
# 5. Run unit tests with coverage in the entire repository
- name: Run unit tests with coverage
run: |
# Create a directory to store coverage files
mkdir -p $GITHUB_WORKSPACE/coverage_files
# Find all *_test.go files
test_files=$(find ./ -type f -name '*_test.go')
# Check if there are any test files
if [ -z "$test_files" ]; then
echo "No test cases found in the repository. Skipping test execution."
exit 0
fi
# Run tests and store coverage for each test directory
for test_file in $test_files; do
test_dir=$(dirname "$test_file")
go_file="${test_file/_test.go/.go}"
echo "Running tests in $test_dir for $go_file"
go test -v -coverprofile=$GITHUB_WORKSPACE/coverage_files/coverage_$(basename "$go_file" .go).out $test_dir || echo "Tests failed, but continuing."
done
# 6. Check coverage for each generated coverage file
- name: Check coverage for each test file
run: |
coverage_files=$(find $GITHUB_WORKSPACE/coverage_files -name "coverage_*.out")
# If no coverage files were generated, exit without failure
if [ -z "$coverage_files" ]; then
echo "No coverage files found. Skipping coverage check."
exit 0
fi
for coverage_file in $coverage_files; do
echo "Checking coverage for $coverage_file"
coverage=$(go tool cover -func=$coverage_file | grep total | awk '{print $3}' | sed 's/%//')
echo "Coverage for $coverage_file: $coverage%"
if (( $(echo "$coverage < 90" | bc -l) )); then
echo "Coverage for $coverage_file is below 90%. Failing the job."
exit 1
fi
done

16
go.mod
View File

@@ -1,18 +1,20 @@
module github.com/beckn/beckn-onix
go 1.24
require golang.org/x/crypto v0.36.0
go 1.24.1
require (
github.com/kr/pretty v0.3.1 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1
golang.org/x/crypto v0.36.0
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
)
require github.com/zenazn/pkcs7pad v0.0.0-20170308005700-253a5b1f0e03
require (
golang.org/x/sys v0.31.0 // indirect
gopkg.in/yaml.v3 v3.0.1
github.com/zenazn/pkcs7pad v0.0.0-20170308005700-253a5b1f0e03
golang.org/x/text v0.23.0 // indirect
)
require gopkg.in/yaml.v3 v3.0.1
require golang.org/x/sys v0.31.0 // indirect

6
go.sum
View File

@@ -1,4 +1,6 @@
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -10,12 +12,16 @@ github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsK
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
github.com/zenazn/pkcs7pad v0.0.0-20170308005700-253a5b1f0e03 h1:m1h+vudopHsI67FPT9MOncyndWhTcdUoBtI1R1uajGY=
github.com/zenazn/pkcs7pad v0.0.0-20170308005700-253a5b1f0e03/go.mod h1:8sheVFH84v3PCyFY/O02mIgSQY9I6wMYPWsq7mDnEZY=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

View File

@@ -7,7 +7,7 @@ import (
// Route defines the structure for the Route returned.
type Route struct {
TargetType string // "url" or "msgq"
TargetType string // "url" or "msgq" or "bap" or "bpp"
PublisherID string // For message queues
URL string // For API calls
}

View File

@@ -0,0 +1,33 @@
package main
import (
"context"
"errors"
definition "github.com/beckn/beckn-onix/pkg/plugin/definition"
schemaValidator "github.com/beckn/beckn-onix/pkg/plugin/implementation/schemaValidator"
)
// schemaValidatorProvider provides instances of schemaValidator.
type schemaValidatorProvider struct{}
// New initializes a new Verifier instance.
func (vp schemaValidatorProvider) New(ctx context.Context, config map[string]string) (definition.SchemaValidator, func() error, error) {
if ctx == nil {
return nil, nil, errors.New("context cannot be nil")
}
// Extract schemaDir from the config map
schemaDir, ok := config["schemaDir"]
if !ok || schemaDir == "" {
return nil, nil, errors.New("config must contain 'schemaDir'")
}
// Create a new schemaValidator instance with the provided configuration
return schemaValidator.New(ctx, &schemaValidator.Config{
SchemaDir: schemaDir,
})
}
// Provider is the exported symbol that the plugin manager will look for.
var Provider definition.SchemaValidatorProvider = schemaValidatorProvider{}

View File

@@ -0,0 +1,150 @@
package main
import (
"context"
"os"
"path/filepath"
"strings"
"testing"
)
// setupTestSchema creates a temporary directory and writes a sample schema file.
func setupTestSchema(t *testing.T) string {
t.Helper()
// Create a temporary directory for the schema
schemaDir, err := os.MkdirTemp("", "schemas")
if err != nil {
t.Fatalf("Failed to create temp directory: %v", err)
}
// Create the directory structure for the schema file
schemaFilePath := filepath.Join(schemaDir, "example", "1.0", "test_schema.json")
if err := os.MkdirAll(filepath.Dir(schemaFilePath), 0755); err != nil {
t.Fatalf("Failed to create schema directory structure: %v", err)
}
// Define a sample schema
schemaContent := `{
"type": "object",
"properties": {
"context": {
"type": "object",
"properties": {
"domain": {"type": "string"},
"version": {"type": "string"}
},
"required": ["domain", "version"]
}
},
"required": ["context"]
}`
// Write the schema to the file
if err := os.WriteFile(schemaFilePath, []byte(schemaContent), 0644); err != nil {
t.Fatalf("Failed to write schema file: %v", err)
}
return schemaDir
}
// TestValidatorProviderSuccess tests successful ValidatorProvider implementation.
func TestValidatorProviderSuccess(t *testing.T) {
schemaDir := setupTestSchema(t)
defer os.RemoveAll(schemaDir)
// Define test cases.
tests := []struct {
name string
ctx context.Context
config map[string]string
expectedError string
}{
{
name: "Valid schema directory",
ctx: context.Background(), // Valid context
config: map[string]string{"schemaDir": schemaDir},
expectedError: "",
},
}
// Test using table-driven tests
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
vp := schemaValidatorProvider{}
schemaValidator, _, err := vp.New(tt.ctx, tt.config)
// Ensure no error occurred
if err != nil {
t.Errorf("unexpected error: %v", err)
return
}
// Ensure the schemaValidator is not nil
if schemaValidator == nil {
t.Error("expected a non-nil schemaValidator, got nil")
}
})
}
}
// TestValidatorProviderSuccess tests cases where ValidatorProvider creation should fail.
func TestValidatorProviderFailure(t *testing.T) {
schemaDir := setupTestSchema(t)
defer os.RemoveAll(schemaDir)
// Define test cases.
tests := []struct {
name string
ctx context.Context
config map[string]string
expectedError string
}{
{
name: "Config is empty",
ctx: context.Background(),
config: map[string]string{},
expectedError: "config must contain 'schemaDir'",
},
{
name: "schemaDir is empty",
ctx: context.Background(),
config: map[string]string{"schemaDir": ""},
expectedError: "config must contain 'schemaDir'",
},
{
name: "Invalid schema directory",
ctx: context.Background(), // Valid context
config: map[string]string{"schemaDir": "/invalid/dir"},
expectedError: "failed to initialise schemaValidator: schema directory does not exist: /invalid/dir",
},
{
name: "Nil context",
ctx: nil, // Nil context
config: map[string]string{"schemaDir": schemaDir},
expectedError: "context cannot be nil",
},
}
// Test using table-driven tests
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
vp := schemaValidatorProvider{}
_, _, err := vp.New(tt.ctx, tt.config)
// Check for expected error
if tt.expectedError != "" {
if err == nil || !strings.Contains(err.Error(), tt.expectedError) {
t.Errorf("expected error %q, got %v", tt.expectedError, err)
}
return
}
// Ensure no error occurred
if err != nil {
t.Errorf("unexpected error: %v", err)
return
}
})
}
}

View File

@@ -0,0 +1,197 @@
package schemaValidator
import (
"context"
"encoding/json"
"fmt"
"net/url"
"os"
"path"
"path/filepath"
"strings"
response "github.com/beckn/beckn-onix/pkg/response"
"github.com/santhosh-tekuri/jsonschema/v6"
)
// Payload represents the structure of the data payload with context information.
type payload struct {
Context struct {
Domain string `json:"domain"`
Version string `json:"version"`
} `json:"context"`
}
// SchemaValidator implements the Validator interface.
type SchemaValidator struct {
config *Config
schemaCache map[string]*jsonschema.Schema
}
// Config struct for SchemaValidator.
type Config struct {
SchemaDir string
}
// New creates a new ValidatorProvider instance.
func New(ctx context.Context, config *Config) (*SchemaValidator, func() error, error) {
// Check if config is nil
if config == nil {
return nil, nil, fmt.Errorf("config cannot be nil")
}
v := &SchemaValidator{
config: config,
schemaCache: make(map[string]*jsonschema.Schema),
}
// Call Initialise function to load schemas and get validators
if err := v.initialise(); err != nil {
return nil, nil, fmt.Errorf("failed to initialise schemaValidator: %v", err)
}
return v, nil, nil
}
// Validate validates the given data against the schema.
func (v *SchemaValidator) Validate(ctx context.Context, url *url.URL, data []byte) error {
var payloadData payload
err := json.Unmarshal(data, &payloadData)
if err != nil {
return fmt.Errorf("failed to parse JSON payload: %v", err)
}
// Extract domain, version, and endpoint from the payload and uri.
cxt_domain := payloadData.Context.Domain
version := payloadData.Context.Version
version = fmt.Sprintf("v%s", version)
endpoint := path.Base(url.String())
// ToDo Add debug log here
fmt.Println("Handling request for endpoint:", endpoint)
domain := strings.ToLower(cxt_domain)
domain = strings.ReplaceAll(domain, ":", "_")
// Construct the schema file name.
schemaFileName := fmt.Sprintf("%s_%s_%s", domain, version, endpoint)
// Retrieve the schema from the cache.
schema, exists := v.schemaCache[schemaFileName]
if !exists {
return fmt.Errorf("schema not found for domain: %s", schemaFileName)
}
var jsonData any
if err := json.Unmarshal(data, &jsonData); err != nil {
return fmt.Errorf("failed to parse JSON data: %v", err)
}
err = schema.Validate(jsonData)
if err != nil {
// Handle schema validation errors
if validationErr, ok := err.(*jsonschema.ValidationError); ok {
// Convert validation errors into an array of SchemaValError
var schemaErrors []response.Error
for _, cause := range validationErr.Causes {
// Extract the path and message from the validation error
path := strings.Join(cause.InstanceLocation, ".") // JSON path to the invalid field
message := cause.Error() // Validation error message
// Append the error to the schemaErrors array
schemaErrors = append(schemaErrors, response.Error{
Paths: path,
Message: message,
})
}
// Return the array of schema validation errors
return &response.SchemaValidationErr{Errors: schemaErrors}
}
// Return a generic error for non-validation errors
return fmt.Errorf("validation failed: %v", err)
}
// Return nil if validation succeeds
return nil
}
// ValidatorProvider provides instances of Validator.
type ValidatorProvider struct{}
// Initialise initialises the validator provider by compiling all the JSON schema files
// from the specified directory and storing them in a cache indexed by their schema filenames.
func (v *SchemaValidator) initialise() error {
schemaDir := v.config.SchemaDir
// Check if the directory exists and is accessible.
info, err := os.Stat(schemaDir)
if err != nil {
if os.IsNotExist(err) {
return fmt.Errorf("schema directory does not exist: %s", schemaDir)
}
return fmt.Errorf("failed to access schema directory: %v", err)
}
if !info.IsDir() {
return fmt.Errorf("provided schema path is not a directory: %s", schemaDir)
}
compiler := jsonschema.NewCompiler()
// Helper function to process directories recursively.
var processDir func(dir string) error
processDir = func(dir string) error {
entries, err := os.ReadDir(dir)
if err != nil {
return fmt.Errorf("failed to read directory: %v", err)
}
for _, entry := range entries {
path := filepath.Join(dir, entry.Name())
if entry.IsDir() {
// Recursively process subdirectories.
if err := processDir(path); err != nil {
return err
}
} else if filepath.Ext(entry.Name()) == ".json" {
// Process JSON files.
compiledSchema, err := compiler.Compile(path)
if err != nil {
return fmt.Errorf("failed to compile JSON schema from file %s: %v", entry.Name(), err)
}
// Use relative path from schemaDir to avoid absolute paths and make schema keys domain/version specific.
relativePath, err := filepath.Rel(schemaDir, path)
if err != nil {
return fmt.Errorf("failed to get relative path for file %s: %v", entry.Name(), err)
}
// Split the relative path to get domain, version, and schema.
parts := strings.Split(relativePath, string(os.PathSeparator))
// Ensure that the file path has at least 3 parts: domain, version, and schema file.
if len(parts) < 3 {
return fmt.Errorf("invalid schema file structure, expected domain/version/schema.json but got: %s", relativePath)
}
// Extract domain, version, and schema filename from the parts.
// Validate that the extracted parts are non-empty.
domain := strings.TrimSpace(parts[0])
version := strings.TrimSpace(parts[1])
schemaFileName := strings.TrimSpace(parts[2])
schemaFileName = strings.TrimSuffix(schemaFileName, ".json")
if domain == "" || version == "" || schemaFileName == "" {
return fmt.Errorf("invalid schema file structure, one or more components are empty. Relative path: %s", relativePath)
}
// Construct a unique key combining domain, version, and schema name (e.g., ondc_trv10_v2.0.0_schema).
uniqueKey := fmt.Sprintf("%s_%s_%s", domain, version, schemaFileName)
// Store the compiled schema in the SchemaCache using the unique key.
v.schemaCache[uniqueKey] = compiledSchema
}
}
return nil
}
// Start processing from the root schema directory.
if err := processDir(schemaDir); err != nil {
return fmt.Errorf("failed to read schema directory: %v", err)
}
return nil
}

View File

@@ -0,0 +1,353 @@
package schemaValidator
import (
"context"
"net/url"
"os"
"path/filepath"
"strings"
"testing"
"github.com/santhosh-tekuri/jsonschema/v6"
)
// setupTestSchema creates a temporary directory and writes a sample schema file.
func setupTestSchema(t *testing.T) string {
t.Helper()
// Create a temporary directory for the schema
schemaDir, err := os.MkdirTemp("", "schemas")
if err != nil {
t.Fatalf("Failed to create temp directory: %v", err)
}
// Create the directory structure for the schema file
schemaFilePath := filepath.Join(schemaDir, "example", "v1.0", "endpoint.json")
if err := os.MkdirAll(filepath.Dir(schemaFilePath), 0755); err != nil {
t.Fatalf("Failed to create schema directory structure: %v", err)
}
// Define a sample schema
schemaContent := `{
"type": "object",
"properties": {
"context": {
"type": "object",
"properties": {
"domain": {"type": "string"},
"version": {"type": "string"},
"action": {"type": "string"}
},
"required": ["domain", "version", "action"]
}
},
"required": ["context"]
}`
// Write the schema to the file
if err := os.WriteFile(schemaFilePath, []byte(schemaContent), 0644); err != nil {
t.Fatalf("Failed to write schema file: %v", err)
}
return schemaDir
}
func TestValidator_Validate_Success(t *testing.T) {
tests := []struct {
name string
url string
payload string
wantErr bool
}{
{
name: "Valid payload",
url: "http://example.com/endpoint",
payload: `{"context": {"domain": "example", "version": "1.0", "action": "endpoint"}}`,
wantErr: false,
},
}
// Setup a temporary schema directory for testing
schemaDir := setupTestSchema(t)
defer os.RemoveAll(schemaDir)
config := &Config{SchemaDir: schemaDir}
v, _, err := New(context.Background(), config)
if err != nil {
t.Fatalf("Failed to create validator: %v", err)
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
u, _ := url.Parse(tt.url)
err := v.Validate(context.Background(), u, []byte(tt.payload))
if err != nil {
t.Errorf("Unexpected error: %v", err)
} else {
t.Logf("Test %s passed with no errors", tt.name)
}
})
}
}
func TestValidator_Validate_Failure(t *testing.T) {
tests := []struct {
name string
url string
payload string
wantErr string
}{
{
name: "Invalid JSON payload",
url: "http://example.com/endpoint",
payload: `{"context": {"domain": "example", "version": "1.0"`,
wantErr: "failed to parse JSON payload",
},
{
name: "Schema validation failure",
url: "http://example.com/endpoint",
payload: `{"context": {"domain": "example", "version": "1.0"}}`,
wantErr: "context: at '/context': missing property 'action'",
},
{
name: "Schema not found",
url: "http://example.com/unknown_endpoint",
payload: `{"context": {"domain": "example", "version": "1.0"}}`,
wantErr: "schema not found for domain",
},
}
// Setup a temporary schema directory for testing
schemaDir := setupTestSchema(t)
defer os.RemoveAll(schemaDir)
config := &Config{SchemaDir: schemaDir}
v, _, err := New(context.Background(), config)
if err != nil {
t.Fatalf("Failed to create validator: %v", err)
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
u, _ := url.Parse(tt.url)
err := v.Validate(context.Background(), u, []byte(tt.payload))
if tt.wantErr != "" {
if err == nil {
t.Errorf("Expected error containing '%s', but got nil", tt.wantErr)
} else if !strings.Contains(err.Error(), tt.wantErr) {
t.Errorf("Expected error containing '%s', but got '%v'", tt.wantErr, err)
} else {
t.Logf("Test %s passed with expected error: %v", tt.name, err)
}
} else {
if err != nil {
t.Errorf("Unexpected error: %v", err)
} else {
t.Logf("Test %s passed with no errors", tt.name)
}
}
})
}
}
func TestValidator_Initialise(t *testing.T) {
tests := []struct {
name string
setupFunc func(schemaDir string) error
wantErr string
}{
{
name: "Schema directory does not exist",
setupFunc: func(schemaDir string) error {
// Do not create the schema directory
return nil
},
wantErr: "schema directory does not exist",
},
{
name: "Schema path is not a directory",
setupFunc: func(schemaDir string) error {
// Create a file instead of a directory
return os.WriteFile(schemaDir, []byte{}, 0644)
},
wantErr: "provided schema path is not a directory",
},
{
name: "Invalid schema file structure",
setupFunc: func(schemaDir string) error {
// Create an invalid schema file structure
invalidSchemaFile := filepath.Join(schemaDir, "invalid_schema.json")
if err := os.MkdirAll(filepath.Dir(invalidSchemaFile), 0755); err != nil {
t.Fatalf("Failed to create directory: %v", err)
}
return os.WriteFile(invalidSchemaFile, []byte(`{}`), 0644)
},
wantErr: "invalid schema file structure",
},
{
name: "Failed to compile JSON schema",
setupFunc: func(schemaDir string) error {
// Create a schema file with invalid JSON
invalidSchemaFile := filepath.Join(schemaDir, "example", "1.0", "endpoint.json")
if err := os.MkdirAll(filepath.Dir(invalidSchemaFile), 0755); err != nil {
t.Fatalf("Failed to create directory: %v", err)
}
return os.WriteFile(invalidSchemaFile, []byte(`{invalid json}`), 0644)
},
wantErr: "failed to compile JSON schema",
},
{
name: "Invalid schema file structure with empty components",
setupFunc: func(schemaDir string) error {
// Create a schema file with empty domain, version, or schema name
invalidSchemaFile := filepath.Join(schemaDir, "", "1.0", "endpoint.json")
if err := os.MkdirAll(filepath.Dir(invalidSchemaFile), 0755); err != nil {
t.Fatalf("Failed to create directory: %v", err)
}
return os.WriteFile(invalidSchemaFile, []byte(`{
"type": "object",
"properties": {
"context": {
"type": "object",
"properties": {
"domain": {"type": "string"},
"version": {"type": "string"}
},
"required": ["domain", "version"]
}
},
"required": ["context"]
}`), 0644)
},
wantErr: "failed to read schema directory: invalid schema file structure, expected domain/version/schema.json but got: 1.0/endpoint.json",
},
{
name: "Failed to read directory",
setupFunc: func(schemaDir string) error {
// Create a directory and remove read permissions
if err := os.MkdirAll(schemaDir, 0000); err != nil {
t.Fatalf("Failed to create directory: %v", err)
}
return nil
},
wantErr: "failed to read directory",
},
{
name: "Valid schema directory",
setupFunc: func(schemaDir string) error {
// Create a valid schema file
validSchemaFile := filepath.Join(schemaDir, "example", "1.0", "endpoint.json")
if err := os.MkdirAll(filepath.Dir(validSchemaFile), 0755); err != nil {
t.Fatalf("Failed to create directory: %v", err)
}
return os.WriteFile(validSchemaFile, []byte(`{
"type": "object",
"properties": {
"context": {
"type": "object",
"properties": {
"domain": {"type": "string"},
"version": {"type": "string"}
},
"required": ["domain", "version"]
}
},
"required": ["context"]
}`), 0644)
},
wantErr: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Setup a temporary schema directory for testing
schemaDir := filepath.Join(os.TempDir(), "schemas")
defer os.RemoveAll(schemaDir)
// Run the setup function to prepare the test case
if err := tt.setupFunc(schemaDir); err != nil {
t.Fatalf("setupFunc() error = %v", err)
}
config := &Config{SchemaDir: schemaDir}
v := &SchemaValidator{
config: config,
schemaCache: make(map[string]*jsonschema.Schema),
}
err := v.initialise()
if (err != nil && !strings.Contains(err.Error(), tt.wantErr)) || (err == nil && tt.wantErr != "") {
t.Errorf("Error: initialise() returned error = %v, expected error = %v", err, tt.wantErr)
} else if err == nil {
t.Logf("Test %s passed: validator initialized successfully", tt.name)
} else {
t.Logf("Test %s passed with expected error: %v", tt.name, err)
}
})
}
}
func TestValidatorNew_Success(t *testing.T) {
schemaDir := setupTestSchema(t)
defer os.RemoveAll(schemaDir)
config := &Config{SchemaDir: schemaDir}
_, _, err := New(context.Background(), config)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
}
func TestValidatorNewFailure(t *testing.T) {
tests := []struct {
name string
config *Config
setupFunc func(schemaDir string) error
wantErr string
}{
{
name: "Config is nil",
config: nil,
setupFunc: func(schemaDir string) error {
return nil
},
wantErr: "config cannot be nil",
},
{
name: "Failed to initialise validators",
config: &Config{
SchemaDir: "/invalid/path",
},
setupFunc: func(schemaDir string) error {
// Do not create the schema directory
return nil
},
wantErr: "ailed to initialise schemaValidator: schema directory does not exist: /invalid/path",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Run the setup function if provided
if tt.setupFunc != nil {
schemaDir := ""
if tt.config != nil {
schemaDir = tt.config.SchemaDir
}
if err := tt.setupFunc(schemaDir); err != nil {
t.Fatalf("Setup function failed: %v", err)
}
}
// Call the New function with the test config
_, _, err := New(context.Background(), tt.config)
if (err != nil && !strings.Contains(err.Error(), tt.wantErr)) || (err == nil && tt.wantErr != "") {
t.Errorf("Error: New() returned error = %v, expected error = %v", err, tt.wantErr)
} else {
t.Logf("Test %s passed with expected error: %v", tt.name, err)
}
})
}
}

View File

@@ -1,6 +0,0 @@
root: pkg/plugin/implementation/
schema_validator:
id: schemaValidator
config:
schema_dir: schemas #Directory where the schema files are stored
plugin_path: pkg/plugin/implementations/

BIN
schemas.zip Normal file

Binary file not shown.