Skip to content

Commit

Permalink
Edit scenario validation to include sanction check config.
Browse files Browse the repository at this point in the history
  • Loading branch information
apognu committed Jan 30, 2025
1 parent a454d68 commit 0a74a7b
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 7 deletions.
22 changes: 19 additions & 3 deletions dto/scenario_validation_dto.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,16 @@ type decisionValidationDto struct {
Errors []ScenarioValidationErrorDto `json:"errors"`
}

type sanctionCheckConfigValidationDto struct {
Trigger triggerValidationDto `json:"trigger"`
NameFilter ruleValidationDto `json:"name_filter"`
}

type ScenarioValidationDto struct {
Trigger triggerValidationDto `json:"trigger"`
Rules rulesValidationDto `json:"rules"`
Decision decisionValidationDto `json:"decision"`
Trigger triggerValidationDto `json:"trigger"`
Rules rulesValidationDto `json:"rules"`
SanctionCheckConfig sanctionCheckConfigValidationDto `json:"sanction_check_config"`
Decision decisionValidationDto `json:"decision"`
}

func AdaptScenarioValidationDto(s models.ScenarioValidation) ScenarioValidationDto {
Expand All @@ -58,6 +64,16 @@ func AdaptScenarioValidationDto(s models.ScenarioValidation) ScenarioValidationD
}
}),
},
SanctionCheckConfig: sanctionCheckConfigValidationDto{
Trigger: triggerValidationDto{
Errors: pure_utils.Map(s.SanctionCheck.TriggerRule.Errors, AdaptScenarioValidationErrorDto),
TriggerEvaluation: ast.AdaptNodeEvaluationDto(s.SanctionCheck.TriggerRule.TriggerEvaluation),
},
NameFilter: ruleValidationDto{
Errors: pure_utils.Map(s.SanctionCheck.NameFilter.Errors, AdaptScenarioValidationErrorDto),
RuleEvaluation: ast.AdaptNodeEvaluationDto(s.SanctionCheck.NameFilter.RuleEvaluation),
},
},
Decision: decisionValidationDto{
Errors: pure_utils.Map(s.Decision.Errors, AdaptScenarioValidationErrorDto),
},
Expand Down
22 changes: 18 additions & 4 deletions models/scenario_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const (
RuleFormulaRequired
// Ast output
FormulaMustReturnBoolean
FormulaMustReturnString
// Decision
ScoreThresholdMissing
ScoreThresholdsMismatch
Expand All @@ -32,6 +33,8 @@ func (e ScenarioValidationErrorCode) String() string {
return "RULE_FORMULA_REQUIRED"
case FormulaMustReturnBoolean:
return "FORMULA_MUST_RETURN_BOOLEAN"
case FormulaMustReturnString:
return "FORMULA_MUST_RETURN_STRING"
case ScoreThresholdMissing:
return "SCORE_THRESHOLD_MISSING"
case ScoreThresholdsMismatch:
Expand Down Expand Up @@ -71,11 +74,17 @@ type decisionValidation struct {
Errors []ScenarioValidationError
}

type sanctionCheckConfigValidation struct {
TriggerRule triggerValidation
NameFilter RuleValidation
}

type ScenarioValidation struct {
Errors []ScenarioValidationError
Trigger triggerValidation
Rules rulesValidation
Decision decisionValidation
Errors []ScenarioValidationError
Trigger triggerValidation
Rules rulesValidation
SanctionCheck sanctionCheckConfigValidation
Decision decisionValidation
}

func NewScenarioValidation() ScenarioValidation {
Expand All @@ -88,6 +97,11 @@ func NewScenarioValidation() ScenarioValidation {
Errors: make([]ScenarioValidationError, 0),
Rules: make(map[string]RuleValidation),
},
SanctionCheck: sanctionCheckConfigValidation{
TriggerRule: triggerValidation{
Errors: make([]ScenarioValidationError, 0),
},
},
Decision: decisionValidation{
Errors: make([]ScenarioValidationError, 0),
},
Expand Down
10 changes: 10 additions & 0 deletions usecases/scenarios/scenario_and_iteration.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package scenarios

import (
"context"
"errors"

"github.com/checkmarble/marble-backend/models"
"github.com/checkmarble/marble-backend/repositories"
Expand All @@ -12,6 +13,7 @@ type ScenarioFetcherRepository interface {
GetScenarioIteration(ctx context.Context, exec repositories.Executor, scenarioIterationId string) (
models.ScenarioIteration, error,
)
GetSanctionCheckConfig(ctx context.Context, exec repositories.Executor, scenarioIterationId string) (models.SanctionCheckConfig, error)
}

type ScenarioFetcher struct {
Expand All @@ -26,6 +28,14 @@ func (fetcher ScenarioFetcher) FetchScenarioAndIteration(ctx context.Context,
return models.ScenarioAndIteration{}, err
}

sanctionCheckConfig, err := fetcher.Repository.GetSanctionCheckConfig(ctx, exec, iterationId)
switch {
case err == nil:
result.Iteration.SanctionCheckConfig = &sanctionCheckConfig
case !errors.Is(err, models.NotFoundError):
return models.ScenarioAndIteration{}, err
}

result.Scenario, err = fetcher.Repository.GetScenarioById(ctx, exec, result.Iteration.ScenarioId)
if err != nil {
return models.ScenarioAndIteration{}, err
Expand Down
11 changes: 11 additions & 0 deletions usecases/scenarios/scenario_and_iteration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ func (s *ScenarioFetcherRepositoryMock) GetScenarioIteration(ctx context.Context
return args.Get(0).(models.ScenarioIteration), args.Error(1)
}

func (s *ScenarioFetcherRepositoryMock) GetSanctionCheckConfig(ctx context.Context,
exec repositories.Executor, scenarioIterationId string,
) (models.SanctionCheckConfig, error) {
args := s.Called(exec, scenarioIterationId)
return args.Get(0).(models.SanctionCheckConfig), args.Error(1)
}

func TestScenarioFetcher_FetchScenarioAndIteration(t *testing.T) {
scenario := models.Scenario{
Id: "scenario_id",
Expand All @@ -45,6 +52,8 @@ func TestScenarioFetcher_FetchScenarioAndIteration(t *testing.T) {
repo := new(ScenarioFetcherRepositoryMock)
repo.On("GetScenarioIteration", mt, scenarioIteration.Id).Return(scenarioIteration, nil)
repo.On("GetScenarioById", mt, scenario.Id).Return(scenario, nil)
repo.On("GetSanctionCheckConfig", mt, scenarioIteration.Id).Return(
models.SanctionCheckConfig{}, models.NotFoundError)

fetcher := ScenarioFetcher{
Repository: repo,
Expand Down Expand Up @@ -94,6 +103,8 @@ func TestScenarioFetcher_FetchScenarioAndIteration_GetScenarioById_error(t *test
repo := new(ScenarioFetcherRepositoryMock)
repo.On("GetScenarioIteration", mt, scenarioIteration.Id).Return(scenarioIteration, nil)
repo.On("GetScenarioById", mt, scenario.Id).Return(scenario, assert.AnError)
repo.On("GetSanctionCheckConfig", mt, scenarioIteration.Id).Return(
models.SanctionCheckConfig{}, models.NotFoundError)

fetcher := ScenarioFetcher{
Repository: repo,
Expand Down
31 changes: 31 additions & 0 deletions usecases/scenarios/scenario_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,37 @@ func (self *ValidateScenarioIterationImpl) Validate(ctx context.Context,
result.Rules.Rules[rule.Id] = ruleValidation
}
}

// Validate sanction check trigger and rule
if iteration.SanctionCheckConfig != nil {
ruleValidation := models.NewRuleValidation()

triggerRuleEvaluation, _ := ast_eval.EvaluateAst(ctx, dryRunEnvironment,
iteration.SanctionCheckConfig.TriggerRule)
if _, ok := triggerRuleEvaluation.ReturnValue.(bool); !ok {
result.SanctionCheck.TriggerRule.Errors = append(ruleValidation.Errors, models.ScenarioValidationError{
Error: errors.Wrap(models.BadParameterError,
"sanction check trigger formula does not return a boolean"),
Code: models.FormulaMustReturnBoolean,
})
}

queryValidation := models.NewRuleValidation()
queryValidation.RuleEvaluation, _ = ast_eval.EvaluateAst(ctx, dryRunEnvironment,
iteration.SanctionCheckConfig.Query.Name)

if _, ok := queryValidation.RuleEvaluation.ReturnValue.(bool); !ok {
queryValidation.Errors = append(
queryValidation.Errors, models.ScenarioValidationError{
Error: errors.Wrap(models.BadParameterError,
"sanction check name filter does not return a string"),
Code: models.FormulaMustReturnString,
})
}

result.SanctionCheck.NameFilter = queryValidation
}

return result
}

Expand Down

0 comments on commit 0a74a7b

Please sign in to comment.