-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added example simple usecase test, mocking enforcers and repositories.
- Loading branch information
Antoine Popineau
committed
Jan 22, 2025
1 parent
fecfc7b
commit 28879a3
Showing
7 changed files
with
217 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package executor_factory | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/checkmarble/marble-backend/models" | ||
"github.com/checkmarble/marble-backend/repositories" | ||
"github.com/pashagolub/pgxmock/v4" | ||
) | ||
|
||
type ExecutorFactoryStub struct { | ||
Mock pgxmock.PgxPoolIface | ||
} | ||
|
||
func NewExecutorFactoryStub() ExecutorFactoryStub { | ||
pool, _ := pgxmock.NewPool() | ||
|
||
return ExecutorFactoryStub{ | ||
Mock: pool, | ||
} | ||
} | ||
|
||
type PgExecutorStub struct { | ||
pgxmock.PgxPoolIface | ||
} | ||
|
||
func (stub ExecutorFactoryStub) NewClientDbExecutor(ctx context.Context, organizationId string) (repositories.Executor, error) { | ||
return nil, nil | ||
} | ||
|
||
func (stub ExecutorFactoryStub) NewExecutor() repositories.Executor { | ||
return PgExecutorStub{ | ||
stub.Mock, | ||
} | ||
} | ||
|
||
func (stub PgExecutorStub) DatabaseSchema() models.DatabaseSchema { | ||
return models.DatabaseSchema{} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package usecases | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/checkmarble/marble-backend/models" | ||
"github.com/checkmarble/marble-backend/repositories" | ||
"github.com/checkmarble/marble-backend/utils" | ||
) | ||
|
||
type sanctionCheckEnforcerMock struct{} | ||
|
||
func (sanctionCheckEnforcerMock) ReadDecision(models.Decision) error { | ||
return nil | ||
} | ||
|
||
func (sanctionCheckEnforcerMock) ReadOrUpdateCase(models.Case, []string) error { | ||
return nil | ||
} | ||
|
||
type sanctionCheckRepositoryMock struct{} | ||
|
||
func (sanctionCheckRepositoryMock) GetOrganizationById(ctx context.Context, | ||
exec repositories.Executor, organizationId string, | ||
) (models.Organization, error) { | ||
return models.Organization{ | ||
Id: "orgid", | ||
Name: "ACME Inc.", | ||
OpenSanctionsConfig: models.OrganizationOpenSanctionsConfig{ | ||
Datasets: []string{"ds1", "ds2"}, | ||
MatchThreshold: utils.Ptr(42), | ||
MatchLimit: utils.Ptr(10), | ||
}, | ||
}, nil | ||
} | ||
|
||
func (sanctionCheckRepositoryMock) DecisionsById(ctx context.Context, exec repositories.Executor, decisionIds []string) ([]models.Decision, error) { | ||
decisions := []models.Decision{ | ||
{ | ||
DecisionId: "decisionid", | ||
}, | ||
} | ||
|
||
return decisions, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package usecases | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/checkmarble/marble-backend/repositories" | ||
"github.com/checkmarble/marble-backend/repositories/dbmodels" | ||
"github.com/checkmarble/marble-backend/usecases/executor_factory" | ||
"github.com/checkmarble/marble-backend/utils" | ||
"github.com/pashagolub/pgxmock/v4" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func buildUsecase() (SanctionCheckUsecase, executor_factory.ExecutorFactoryStub) { | ||
enforceSecurity := sanctionCheckEnforcerMock{} | ||
mock := sanctionCheckRepositoryMock{} | ||
exec := executor_factory.NewExecutorFactoryStub() | ||
|
||
uc := SanctionCheckUsecase{ | ||
enforceSecurityDecision: enforceSecurity, | ||
enforceSecurityCase: enforceSecurity, | ||
organizationRepository: mock, | ||
decisionRepository: mock, | ||
repository: &repositories.MarbleDbRepository{}, | ||
executorFactory: exec, | ||
} | ||
|
||
return uc, exec | ||
} | ||
|
||
func TestGetSanctionCheckOnDecision(t *testing.T) { | ||
uc, exec := buildUsecase() | ||
mockSc, mockScRow := utils.FakeStruct[dbmodels.DBSanctionCheck]() | ||
mockScMatch, mockScMatchRow := utils.FakeStruct[dbmodels.DBSanctionCheckMatchWithComments]() | ||
|
||
exec.Mock.ExpectQuery(`SELECT .* FROM sanction_checks WHERE decision_id = \$1`). | ||
WithArgs("decisionid"). | ||
WillReturnRows( | ||
pgxmock.NewRows(dbmodels.SelectSanctionChecksColumn). | ||
AddRow(mockScRow...), | ||
) | ||
|
||
exec.Mock.ExpectQuery(`SELECT .* FROM sanction_check_matches matches LEFT JOIN sanction_check_match_comments comments ON matches.id = comments.sanction_check_match_id WHERE sanction_check_id = \$1 GROUP BY matches.id`). | ||
WithArgs(mockSc.Id). | ||
WillReturnRows( | ||
pgxmock.NewRows(utils.ColumnList[dbmodels.DBSanctionCheckMatchWithComments]()). | ||
AddRow(mockScMatchRow...). | ||
AddRow(utils.FakeStructRow[dbmodels.DBSanctionCheckMatchWithComments]()...). | ||
AddRow(utils.FakeStructRow[dbmodels.DBSanctionCheckMatchWithComments]()...), | ||
) | ||
|
||
scs, err := uc.ListSanctionChecks(context.TODO(), "decisionid") | ||
|
||
assert.NoError(t, exec.Mock.ExpectationsWereMet()) | ||
assert.NoError(t, err) | ||
assert.Len(t, scs, 1) | ||
assert.Equal(t, mockSc.Status, scs[0].Status) | ||
assert.Len(t, scs[0].Matches, 3) | ||
assert.Equal(t, mockScMatch.Status, scs[0].Matches[0].Status) | ||
assert.Equal(t, mockScMatch.CommentCount, scs[0].Matches[0].CommentCount) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package utils | ||
|
||
import ( | ||
"reflect" | ||
|
||
"github.com/go-faker/faker/v4" | ||
) | ||
|
||
func FakeStruct[T any]() (T, []any) { | ||
var object T | ||
|
||
_ = faker.FakeData(&object) | ||
|
||
return object, StructToMockRow(object) | ||
} | ||
|
||
func FakeStructRow[T any]() []any { | ||
_, row := FakeStruct[T]() | ||
|
||
return row | ||
} | ||
|
||
func StructToMockRow[T any](object T) []any { | ||
f := reflect.ValueOf(object) | ||
t := reflect.TypeOf(object) | ||
|
||
if f.Kind() != reflect.Struct { | ||
panic("StructToMockRow should only be used on structs") | ||
} | ||
|
||
slice := make([]any, 0) | ||
|
||
for i := 0; i < f.NumField(); i++ { | ||
sf := f.Field(i) | ||
|
||
switch sf.Kind() { | ||
case reflect.Struct: | ||
switch t.Field(i).Anonymous { | ||
case true: | ||
slice = append(slice, StructToMockRow(sf.Interface())...) | ||
default: | ||
slice = append(slice, sf.Interface()) | ||
} | ||
default: | ||
slice = append(slice, sf.Interface()) | ||
} | ||
} | ||
|
||
return slice | ||
} |