update and merged with latest master
This commit is contained in:
18
pkg/plugin/definition/transport.go
Normal file
18
pkg/plugin/definition/transport.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package definition
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// TransportWrapper is a plugin that wraps an http.RoundTripper,
|
||||
// allowing modification of outbound requests (like adding auth).
|
||||
type TransportWrapper interface {
|
||||
// Wrap takes a base transport and returns a new transport that wraps it.
|
||||
Wrap(base http.RoundTripper) http.RoundTripper
|
||||
}
|
||||
|
||||
// TransportWrapperProvider defines the factory for a TransportWrapper.
|
||||
type TransportWrapperProvider interface {
|
||||
New(ctx context.Context, config map[string]any) (TransportWrapper, func(), error)
|
||||
}
|
||||
23
pkg/plugin/implementation/reqmapper/cmd/plugin.go
Normal file
23
pkg/plugin/implementation/reqmapper/cmd/plugin.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/beckn-one/beckn-onix/pkg/plugin/implementation/reqmapper"
|
||||
)
|
||||
|
||||
type provider struct{}
|
||||
|
||||
func (p provider) New(ctx context.Context, c map[string]string) (func(http.Handler) http.Handler, error) {
|
||||
config := &reqmapper.Config{}
|
||||
if role, ok := c["role"]; ok {
|
||||
config.Role = role
|
||||
}
|
||||
if mappingsFile, ok := c["mappingsFile"]; ok {
|
||||
config.MappingsFile = mappingsFile
|
||||
}
|
||||
return reqmapper.NewReqMapper(config)
|
||||
}
|
||||
|
||||
var Provider = provider{}
|
||||
84
pkg/plugin/implementation/reqmapper/cmd/plugin_test.go
Normal file
84
pkg/plugin/implementation/reqmapper/cmd/plugin_test.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestProviderNewSuccess(t *testing.T) {
|
||||
p := provider{}
|
||||
middleware, err := p.New(context.Background(), map[string]string{"role": "bap"})
|
||||
if err != nil {
|
||||
t.Fatalf("provider.New returned unexpected error: %v", err)
|
||||
}
|
||||
if middleware == nil {
|
||||
t.Fatalf("provider.New returned nil middleware")
|
||||
}
|
||||
|
||||
payload := map[string]interface{}{
|
||||
"context": map[string]interface{}{
|
||||
"action": "search",
|
||||
"domain": "retail",
|
||||
"version": "1.1.0",
|
||||
"bap_id": "bap.example",
|
||||
"bap_uri": "https://bap.example/api",
|
||||
"transaction_id": "txn-1",
|
||||
"message_id": "msg-1",
|
||||
"timestamp": "2023-01-01T10:00:00Z",
|
||||
},
|
||||
"message": map[string]interface{}{
|
||||
"intent": map[string]interface{}{
|
||||
"fulfillment": map[string]interface{}{
|
||||
"start": map[string]interface{}{
|
||||
"location": map[string]interface{}{"gps": "0,0"},
|
||||
},
|
||||
"end": map[string]interface{}{
|
||||
"location": map[string]interface{}{"gps": "1,1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
body, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal payload: %v", err)
|
||||
}
|
||||
|
||||
called := false
|
||||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
})
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/", bytes.NewReader(body))
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
middleware(next).ServeHTTP(rec, req)
|
||||
|
||||
if !called {
|
||||
t.Fatalf("expected downstream handler to be invoked")
|
||||
}
|
||||
if rec.Code != http.StatusNoContent {
|
||||
t.Fatalf("unexpected response code: got %d want %d", rec.Code, http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProviderNewMissingRole(t *testing.T) {
|
||||
p := provider{}
|
||||
if _, err := p.New(context.Background(), map[string]string{}); err == nil {
|
||||
t.Fatalf("expected error when role is missing")
|
||||
}
|
||||
}
|
||||
|
||||
func TestProviderNewInvalidRole(t *testing.T) {
|
||||
p := provider{}
|
||||
_, err := p.New(context.Background(), map[string]string{"role": "invalid"})
|
||||
if err == nil {
|
||||
t.Fatalf("expected error for invalid role")
|
||||
}
|
||||
}
|
||||
287
pkg/plugin/implementation/reqmapper/reqmapper.go
Normal file
287
pkg/plugin/implementation/reqmapper/reqmapper.go
Normal file
@@ -0,0 +1,287 @@
|
||||
package reqmapper
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/beckn-one/beckn-onix/pkg/log"
|
||||
"github.com/jsonata-go/jsonata"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Config represents the configuration for the request mapper middleware.
|
||||
type Config struct {
|
||||
Role string `yaml:"role"` // "bap" or "bpp"
|
||||
MappingsFile string `yaml:"mappingsFile"` // required path to mappings YAML
|
||||
}
|
||||
|
||||
// MappingEngine handles JSONata-based transformations
|
||||
type MappingEngine struct {
|
||||
config *Config
|
||||
jsonataInstance jsonata.JSONataInstance
|
||||
bapMaps map[string]jsonata.Expression
|
||||
bppMaps map[string]jsonata.Expression
|
||||
mappings map[string]builtinMapping
|
||||
mappingSource string
|
||||
mutex sync.RWMutex
|
||||
initialized bool
|
||||
}
|
||||
|
||||
type builtinMapping struct {
|
||||
BAP string `yaml:"bapMappings"`
|
||||
BPP string `yaml:"bppMappings"`
|
||||
}
|
||||
|
||||
type mappingFile struct {
|
||||
Mappings map[string]builtinMapping `yaml:"mappings"`
|
||||
}
|
||||
|
||||
var (
|
||||
engineInstance *MappingEngine
|
||||
engineOnce sync.Once
|
||||
)
|
||||
|
||||
// NewReqMapper returns a middleware that maps requests using JSONata expressions
|
||||
func NewReqMapper(cfg *Config) (func(http.Handler) http.Handler, error) {
|
||||
if err := validateConfig(cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Initialize the mapping engine
|
||||
engine, err := initMappingEngine(cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize mapping engine: %w", err)
|
||||
}
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to read request body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var req map[string]interface{}
|
||||
ctx := r.Context()
|
||||
|
||||
if err := json.Unmarshal(body, &req); err != nil {
|
||||
http.Error(w, "Failed to decode request body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
reqContext, ok := req["context"].(map[string]interface{})
|
||||
if !ok {
|
||||
http.Error(w, "context field not found or invalid", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
action, ok := reqContext["action"].(string)
|
||||
if !ok {
|
||||
http.Error(w, "action field not found or invalid", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Apply transformation
|
||||
mappedBody, err := engine.Transform(ctx, action, req, cfg.Role)
|
||||
if err != nil {
|
||||
log.Errorf(ctx, err, "Transformation failed for action %s", action)
|
||||
// Fall back to original body on error
|
||||
mappedBody = body
|
||||
}
|
||||
|
||||
r.Body = io.NopCloser(bytes.NewBuffer(mappedBody))
|
||||
r.ContentLength = int64(len(mappedBody))
|
||||
r = r.WithContext(ctx)
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}, nil
|
||||
}
|
||||
|
||||
// initMappingEngine initializes or returns existing mapping engine
|
||||
func initMappingEngine(cfg *Config) (*MappingEngine, error) {
|
||||
var initErr error
|
||||
|
||||
engineOnce.Do(func() {
|
||||
engineInstance = &MappingEngine{
|
||||
config: cfg,
|
||||
bapMaps: make(map[string]jsonata.Expression),
|
||||
bppMaps: make(map[string]jsonata.Expression),
|
||||
}
|
||||
|
||||
instance, err := jsonata.OpenLatest()
|
||||
if err != nil {
|
||||
initErr = fmt.Errorf("failed to initialize jsonata: %w", err)
|
||||
return
|
||||
}
|
||||
engineInstance.jsonataInstance = instance
|
||||
|
||||
if err := engineInstance.loadBuiltinMappings(); err != nil {
|
||||
initErr = err
|
||||
return
|
||||
}
|
||||
|
||||
engineInstance.initialized = true
|
||||
})
|
||||
|
||||
if initErr != nil {
|
||||
return nil, initErr
|
||||
}
|
||||
|
||||
if !engineInstance.initialized {
|
||||
return nil, errors.New("mapping engine failed to initialize")
|
||||
}
|
||||
|
||||
return engineInstance, nil
|
||||
}
|
||||
|
||||
func (e *MappingEngine) loadMappingsFromConfig() (map[string]builtinMapping, string, error) {
|
||||
if e.config == nil || e.config.MappingsFile == "" {
|
||||
return nil, "", errors.New("mappingsFile must be provided in config")
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(e.config.MappingsFile)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("failed to read mappings file %s: %w", e.config.MappingsFile, err)
|
||||
}
|
||||
source := e.config.MappingsFile
|
||||
|
||||
var parsed mappingFile
|
||||
if err := yaml.Unmarshal(data, &parsed); err != nil {
|
||||
return nil, "", fmt.Errorf("failed to parse mappings from %s: %w", source, err)
|
||||
}
|
||||
|
||||
if len(parsed.Mappings) == 0 {
|
||||
return nil, "", fmt.Errorf("no mappings found in %s", source)
|
||||
}
|
||||
|
||||
return parsed.Mappings, source, nil
|
||||
}
|
||||
|
||||
// loadBuiltinMappings compiles JSONata expressions for every action/direction pair from the configured mappings file.
|
||||
func (e *MappingEngine) loadBuiltinMappings() error {
|
||||
mappings, source, err := e.loadMappingsFromConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
e.bapMaps = make(map[string]jsonata.Expression, len(mappings))
|
||||
e.bppMaps = make(map[string]jsonata.Expression, len(mappings))
|
||||
|
||||
for action, mapping := range mappings {
|
||||
bapExpr, err := e.jsonataInstance.Compile(mapping.BAP, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to compile BAP mapping for action %s: %w", action, err)
|
||||
}
|
||||
bppExpr, err := e.jsonataInstance.Compile(mapping.BPP, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to compile BPP mapping for action %s: %w", action, err)
|
||||
}
|
||||
|
||||
e.bapMaps[action] = bapExpr
|
||||
e.bppMaps[action] = bppExpr
|
||||
}
|
||||
|
||||
e.mappings = mappings
|
||||
e.mappingSource = source
|
||||
|
||||
log.Infof(
|
||||
context.Background(),
|
||||
"Loaded %d BAP mappings and %d BPP mappings from %s",
|
||||
len(e.bapMaps),
|
||||
len(e.bppMaps),
|
||||
source,
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Transform applies the appropriate mapping based on role and action
|
||||
func (e *MappingEngine) Transform(ctx context.Context, action string, req map[string]interface{}, role string) ([]byte, error) {
|
||||
e.mutex.RLock()
|
||||
defer e.mutex.RUnlock()
|
||||
|
||||
var expr jsonata.Expression
|
||||
var found bool
|
||||
|
||||
// Select appropriate mapping based on role
|
||||
switch role {
|
||||
case "bap":
|
||||
expr, found = e.bapMaps[action]
|
||||
case "bpp":
|
||||
expr, found = e.bppMaps[action]
|
||||
default:
|
||||
return json.Marshal(req)
|
||||
}
|
||||
|
||||
// If no mapping found, return original request
|
||||
if !found || expr == nil {
|
||||
log.Debugf(ctx, "No mapping found for action: %s, role: %s", action, role)
|
||||
return json.Marshal(req)
|
||||
}
|
||||
|
||||
// Marshal request for JSONata evaluation
|
||||
input, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal request for mapping: %w", err)
|
||||
}
|
||||
|
||||
// Apply JSONata transformation
|
||||
result, err := expr.Evaluate(input, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("JSONata evaluation failed: %w", err)
|
||||
}
|
||||
|
||||
log.Debugf(ctx, "Successfully transformed %s request using %s mapping, %s", action, role, result)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ReloadMappings reloads all mapping files (useful for hot-reload scenarios)
|
||||
func (e *MappingEngine) ReloadMappings() error {
|
||||
e.mutex.Lock()
|
||||
defer e.mutex.Unlock()
|
||||
|
||||
return e.loadBuiltinMappings()
|
||||
}
|
||||
|
||||
// GetMappingInfo returns information about loaded mappings
|
||||
func (e *MappingEngine) GetMappingInfo() map[string]interface{} {
|
||||
e.mutex.RLock()
|
||||
defer e.mutex.RUnlock()
|
||||
|
||||
bapActions := make([]string, 0, len(e.bapMaps))
|
||||
for action := range e.bapMaps {
|
||||
bapActions = append(bapActions, action)
|
||||
}
|
||||
|
||||
bppActions := make([]string, 0, len(e.bppMaps))
|
||||
for action := range e.bppMaps {
|
||||
bppActions = append(bppActions, action)
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"bap_mappings": bapActions,
|
||||
"bpp_mappings": bppActions,
|
||||
"mappings_source": e.mappingSource,
|
||||
"action_count": len(e.mappings),
|
||||
}
|
||||
}
|
||||
|
||||
func validateConfig(cfg *Config) error {
|
||||
if cfg == nil {
|
||||
return errors.New("config cannot be nil")
|
||||
}
|
||||
if cfg.Role != "bap" && cfg.Role != "bpp" {
|
||||
return errors.New("role must be either 'bap' or 'bpp'")
|
||||
}
|
||||
if cfg.MappingsFile == "" {
|
||||
return errors.New("mappingsFile is required")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
240
pkg/plugin/implementation/reqmapper/reqmapper_test.go
Normal file
240
pkg/plugin/implementation/reqmapper/reqmapper_test.go
Normal file
@@ -0,0 +1,240 @@
|
||||
package reqmapper
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func resetEngineState(t *testing.T) {
|
||||
t.Helper()
|
||||
engineInstance = nil
|
||||
engineOnce = sync.Once{}
|
||||
}
|
||||
|
||||
func testMappingsFile(t *testing.T) string {
|
||||
t.Helper()
|
||||
path := filepath.Join("testdata", "mappings.yaml")
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
t.Fatalf("test mappings file missing: %v", err)
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func initTestEngine(t *testing.T) *MappingEngine {
|
||||
t.Helper()
|
||||
resetEngineState(t)
|
||||
engine, err := initMappingEngine(&Config{
|
||||
Role: "bap",
|
||||
MappingsFile: testMappingsFile(t),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to init mapping engine: %v", err)
|
||||
}
|
||||
return engine
|
||||
}
|
||||
|
||||
func TestNewReqMapper_InvalidConfig(t *testing.T) {
|
||||
t.Run("nil config", func(t *testing.T) {
|
||||
if _, err := NewReqMapper(nil); err == nil {
|
||||
t.Fatalf("expected error for nil config")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("invalid role", func(t *testing.T) {
|
||||
if _, err := NewReqMapper(&Config{Role: "invalid"}); err == nil {
|
||||
t.Fatalf("expected error for invalid role")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewReqMapper_MiddlewareTransformsRequest(t *testing.T) {
|
||||
resetEngineState(t)
|
||||
mw, err := NewReqMapper(&Config{
|
||||
Role: "bap",
|
||||
MappingsFile: testMappingsFile(t),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("NewReqMapper returned error: %v", err)
|
||||
}
|
||||
|
||||
startLocation := map[string]interface{}{
|
||||
"gps": "12.9716,77.5946",
|
||||
"city": "Bengaluru",
|
||||
}
|
||||
endLocation := map[string]interface{}{
|
||||
"gps": "13.0827,80.2707",
|
||||
"city": "Chennai",
|
||||
}
|
||||
|
||||
requestPayload := map[string]interface{}{
|
||||
"context": map[string]interface{}{
|
||||
"domain": "retail",
|
||||
"action": "search",
|
||||
"version": "1.1.0",
|
||||
"bap_id": "bap.example",
|
||||
"bap_uri": "https://bap.example/api",
|
||||
"transaction_id": "txn-1",
|
||||
"message_id": "msg-1",
|
||||
"timestamp": "2023-01-01T10:00:00Z",
|
||||
},
|
||||
"message": map[string]interface{}{
|
||||
"intent": map[string]interface{}{
|
||||
"item": map[string]interface{}{
|
||||
"id": "item-1",
|
||||
},
|
||||
"provider": map[string]interface{}{
|
||||
"id": "provider-1",
|
||||
},
|
||||
"fulfillment": map[string]interface{}{
|
||||
"start": map[string]interface{}{
|
||||
"location": startLocation,
|
||||
},
|
||||
"end": map[string]interface{}{
|
||||
"location": endLocation,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
body, err := json.Marshal(requestPayload)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal request payload: %v", err)
|
||||
}
|
||||
|
||||
var captured map[string]interface{}
|
||||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
data, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read request in handler: %v", err)
|
||||
}
|
||||
if err := json.Unmarshal(data, &captured); err != nil {
|
||||
t.Fatalf("failed to unmarshal transformed payload: %v", err)
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/", bytes.NewReader(body))
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
mw(next).ServeHTTP(rec, req)
|
||||
|
||||
if captured == nil {
|
||||
t.Fatalf("middleware did not forward request to next handler")
|
||||
}
|
||||
|
||||
message, ok := captured["message"].(map[string]interface{})
|
||||
if !ok {
|
||||
t.Fatalf("expected message field in transformed payload")
|
||||
}
|
||||
|
||||
filters, ok := message["filters"].(map[string]interface{})
|
||||
if !ok {
|
||||
t.Fatalf("expected filters in transformed payload")
|
||||
}
|
||||
|
||||
if pickup := filters["pickup"]; !reflect.DeepEqual(pickup, startLocation) {
|
||||
t.Fatalf("pickup location mismatch\ngot: %#v\nwant: %#v", pickup, startLocation)
|
||||
}
|
||||
if drop := filters["drop"]; !reflect.DeepEqual(drop, endLocation) {
|
||||
t.Fatalf("drop location mismatch\ngot: %#v\nwant: %#v", drop, endLocation)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMappingEngine_TransformFallbackForUnknownAction(t *testing.T) {
|
||||
engine := initTestEngine(t)
|
||||
req := map[string]interface{}{
|
||||
"context": map[string]interface{}{
|
||||
"action": "unknown_action",
|
||||
},
|
||||
"message": map[string]interface{}{},
|
||||
}
|
||||
|
||||
expected, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal expected payload: %v", err)
|
||||
}
|
||||
|
||||
result, err := engine.Transform(context.Background(), "unknown_action", req, "bap")
|
||||
if err != nil {
|
||||
t.Fatalf("Transform returned error: %v", err)
|
||||
}
|
||||
if !bytes.Equal(result, expected) {
|
||||
t.Fatalf("expected Transform to return original payload")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMappingEngine_TransformFallbackForUnknownRole(t *testing.T) {
|
||||
engine := initTestEngine(t)
|
||||
req := map[string]interface{}{
|
||||
"context": map[string]interface{}{
|
||||
"action": "search",
|
||||
},
|
||||
"message": map[string]interface{}{},
|
||||
}
|
||||
|
||||
expected, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal expected payload: %v", err)
|
||||
}
|
||||
|
||||
result, err := engine.Transform(context.Background(), "search", req, "unknown-role")
|
||||
if err != nil {
|
||||
t.Fatalf("Transform returned error: %v", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(result, expected) {
|
||||
t.Fatalf("expected Transform to return original payload when role is unknown")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMappingEngine_ReloadMappings(t *testing.T) {
|
||||
engine := initTestEngine(t)
|
||||
|
||||
engine.mutex.RLock()
|
||||
originalBAP := len(engine.bapMaps)
|
||||
originalBPP := len(engine.bppMaps)
|
||||
engine.mutex.RUnlock()
|
||||
|
||||
if originalBAP == 0 || originalBPP == 0 {
|
||||
t.Fatalf("expected test mappings to be loaded")
|
||||
}
|
||||
|
||||
engine.mutex.Lock()
|
||||
for action := range engine.bapMaps {
|
||||
delete(engine.bapMaps, action)
|
||||
break
|
||||
}
|
||||
engine.mutex.Unlock()
|
||||
|
||||
engine.mutex.RLock()
|
||||
if len(engine.bapMaps) == originalBAP {
|
||||
engine.mutex.RUnlock()
|
||||
t.Fatalf("expected BAP map to be altered before reload")
|
||||
}
|
||||
engine.mutex.RUnlock()
|
||||
|
||||
if err := engine.ReloadMappings(); err != nil {
|
||||
t.Fatalf("ReloadMappings returned error: %v", err)
|
||||
}
|
||||
|
||||
engine.mutex.RLock()
|
||||
defer engine.mutex.RUnlock()
|
||||
|
||||
if len(engine.bapMaps) != originalBAP {
|
||||
t.Fatalf("expected BAP mappings to be reloaded, got %d want %d", len(engine.bapMaps), originalBAP)
|
||||
}
|
||||
if len(engine.bppMaps) != originalBPP {
|
||||
t.Fatalf("expected BPP mappings to be reloaded, got %d want %d", len(engine.bppMaps), originalBPP)
|
||||
}
|
||||
}
|
||||
17
pkg/plugin/implementation/reqmapper/testdata/mappings.yaml
vendored
Normal file
17
pkg/plugin/implementation/reqmapper/testdata/mappings.yaml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
mappings:
|
||||
search:
|
||||
bapMappings: |
|
||||
{
|
||||
"context": $.context,
|
||||
"message": {
|
||||
"filters": {
|
||||
"pickup": $.message.intent.fulfillment.start.location,
|
||||
"drop": $.message.intent.fulfillment.end.location
|
||||
}
|
||||
}
|
||||
}
|
||||
bppMappings: |
|
||||
{
|
||||
"context": $.context,
|
||||
"message": $.message
|
||||
}
|
||||
@@ -217,13 +217,35 @@ func (m *Manager) OtelSetup(ctx context.Context, cfg *Config) (*telemetry.Provid
|
||||
if closer != nil {
|
||||
m.closers = append(m.closers, func() {
|
||||
if err := closer(); err != nil {
|
||||
panic(err)
|
||||
log.Errorf(context.Background(), err, "Failed to shutdown telemetry provider")
|
||||
}
|
||||
})
|
||||
}
|
||||
return provider, nil
|
||||
}
|
||||
|
||||
// TransportWrapper returns a TransportWrapper instance based on the provided configuration.
|
||||
func (m *Manager) TransportWrapper(ctx context.Context, cfg *Config) (definition.TransportWrapper, error) {
|
||||
twp, err := provider[definition.TransportWrapperProvider](m.plugins, cfg.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load provider for %s: %w", cfg.ID, err)
|
||||
}
|
||||
|
||||
config := make(map[string]any, len(cfg.Config))
|
||||
for k, v := range cfg.Config {
|
||||
config[k] = v
|
||||
}
|
||||
|
||||
wrapper, closer, err := twp.New(ctx, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if closer != nil {
|
||||
m.closers = append(m.closers, closer)
|
||||
}
|
||||
return wrapper, nil
|
||||
}
|
||||
|
||||
// Step returns a Step instance based on the provided configuration.
|
||||
func (m *Manager) Step(ctx context.Context, cfg *Config) (definition.Step, error) {
|
||||
sp, err := provider[definition.StepProvider](m.plugins, cfg.ID)
|
||||
|
||||
Reference in New Issue
Block a user