From 78f486d130575e01d6e99bceb806d2ebe68a3a7b Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Tue, 2 Apr 2024 21:19:30 -0700 Subject: [PATCH] Adding core handler --- Makefile | 13 ++++ README.md | 11 +--- src/core/core_test.go | 59 +++++++++++++++++ src/core/handler.go | 35 +++++++++++ src/core/handler_test.go | 20 ++++++ src/repository/account.go | 21 +++++++ src/repository/account_test.go | 101 ++++++++++++++++++++++++++++++ src/repository/repository_test.go | 57 +++++++++++++++++ 8 files changed, 307 insertions(+), 10 deletions(-) create mode 100644 Makefile create mode 100644 src/core/core_test.go create mode 100644 src/core/handler.go create mode 100644 src/core/handler_test.go create mode 100644 src/repository/account_test.go create mode 100644 src/repository/repository_test.go diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..806300a --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +build: + go build -o ./bin/app ./src/cmd/app/main.go + +run: + GOOS=windows $env:GO_ENV="test"; go run ./src/cmd/app/main.go + GOOS=linux GO_ENV=test go run ./src/cmd/app/main.go + +test: + go test -p 1 -coverpkg=./... -v + +cover: + go test -p 1 -coverprofile="coverage.out" ./... + go tool cover -html="coverage.out" diff --git a/README.md b/README.md index 9a83ff8..66d9075 100644 --- a/README.md +++ b/README.md @@ -24,13 +24,4 @@ GitOps Domain Snapshot Orchestrator for Switcher API # Features - Manage Switchers in a GitOps manner - Multiple and Independent Environments -- Two-way Sync allow you to use the Switcher API Management, Slack App and GitOps at the same time - -## Run Project - -- Running
- Windows: `$env:GO_ENV="test"; go run ./src/cmd/app/main.go`
- Unit: `GO_ENV=test go run ./src/cmd/app/main.go` -- Testing `go test -coverpkg=./... -v` -- Coverage `go test -coverprofile="coverage.out" ./... && go tool cover -html="coverage.out"` -- Building `go build -o ./bin/app ./src/cmd/app/main.go` \ No newline at end of file +- Two-way Sync allow you to use the Switcher API Management, Slack App and GitOps at the same time \ No newline at end of file diff --git a/src/core/core_test.go b/src/core/core_test.go new file mode 100644 index 0000000..3b13276 --- /dev/null +++ b/src/core/core_test.go @@ -0,0 +1,59 @@ +package core + +import ( + "context" + "os" + "testing" + + "github.com/switcherapi/switcher-gitops/src/config" + "github.com/switcherapi/switcher-gitops/src/db" + "github.com/switcherapi/switcher-gitops/src/model" + "github.com/switcherapi/switcher-gitops/src/repository" + "go.mongodb.org/mongo-driver/mongo" +) + +var mongoDb *mongo.Database +var coreHandler *CoreHandler + +func TestMain(m *testing.M) { + setup() + code := m.Run() + shutdown() + os.Exit(code) +} + +func setup() { + os.Setenv("GO_ENV", "test") + config.InitEnv() + mongoDb = db.InitDb() + + accountRepository := repository.NewAccountRepositoryMongo(mongoDb) + coreHandler = NewCoreHandler(accountRepository) +} + +func shutdown() { + mongoDb.Drop(context.Background()) + mongoDb.Client().Disconnect(context.Background()) +} + +// Fixtures + +func givenAccount() model.Account { + return model.Account{ + Repository: "switcherapi/switcher-gitops", + Branch: "master", + Domain: model.DomainDetails{ + ID: "123", + Name: "Switcher GitOps", + Version: "123", + LastCommit: "123", + Status: "active", + Message: "Synced successfully", + }, + Settings: model.Settings{ + Active: true, + Window: "10m", + ForcePrune: false, + }, + } +} diff --git a/src/core/handler.go b/src/core/handler.go new file mode 100644 index 0000000..6936b63 --- /dev/null +++ b/src/core/handler.go @@ -0,0 +1,35 @@ +package core + +import ( + "github.com/switcherapi/switcher-gitops/src/model" + "github.com/switcherapi/switcher-gitops/src/repository" +) + +type CoreHandler struct { + AccountRepository repository.AccountRepository + status int +} + +func NewCoreHandler(repo repository.AccountRepository) *CoreHandler { + return &CoreHandler{ + AccountRepository: repo, + } +} + +func (c *CoreHandler) InitCoreHandlerCoroutine() (int, error) { + // Load all accounts + accounts, _ := c.AccountRepository.FetchAllActiveAccounts() + + // Iterate over accounts and start a new account handler + for _, account := range accounts { + c.startNewAccountHandler(account) + } + + // Update core handler status + c.status = 1 + return c.status, nil +} + +func (c *CoreHandler) startNewAccountHandler(account model.Account) { + c.AccountRepository.FetchByDomainId(account.Domain.ID) +} diff --git a/src/core/handler_test.go b/src/core/handler_test.go new file mode 100644 index 0000000..2e42044 --- /dev/null +++ b/src/core/handler_test.go @@ -0,0 +1,20 @@ +package core + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestInitCoreHandlerCoroutine(t *testing.T) { + // Given + account1 := givenAccount() + coreHandler.AccountRepository.Create(&account1) + + // Test + status, err := coreHandler.InitCoreHandlerCoroutine() + + // Assert + assert.Nil(t, err) + assert.Equal(t, 1, status) +} diff --git a/src/repository/account.go b/src/repository/account.go index c4be9e3..7f760ea 100644 --- a/src/repository/account.go +++ b/src/repository/account.go @@ -15,6 +15,7 @@ import ( type AccountRepository interface { Create(account *model.Account) (*model.Account, error) FetchByDomainId(domainId string) (*model.Account, error) + FetchAllActiveAccounts() ([]model.Account, error) Update(account *model.Account) (*model.Account, error) DeleteByDomainId(domainId string) error } @@ -32,6 +33,7 @@ func (err ErrAccountNotFound) Error() string { } const domainIdFilter = "domain.id" +const settingsActiveFilter = "settings.active" func NewAccountRepositoryMongo(db *mongo.Database) *AccountRepositoryMongo { registerAccountRepositoryValidators(db) @@ -65,6 +67,25 @@ func (repo *AccountRepositoryMongo) FetchByDomainId(domainId string) (*model.Acc return &account, nil } +func (repo *AccountRepositoryMongo) FetchAllActiveAccounts() ([]model.Account, error) { + collection, ctx, cancel := getDbContext(repo) + defer cancel() + + filter := primitive.M{settingsActiveFilter: true} + cursor, _ := collection.Find(ctx, filter) + + var accounts []model.Account + for cursor.Next(ctx) { + var account model.Account + err := cursor.Decode(&account) + if err == nil { + accounts = append(accounts, account) + } + } + + return accounts, nil +} + func (repo *AccountRepositoryMongo) Update(account *model.Account) (*model.Account, error) { collection, ctx, cancel := getDbContext(repo) defer cancel() diff --git a/src/repository/account_test.go b/src/repository/account_test.go new file mode 100644 index 0000000..a33b7c6 --- /dev/null +++ b/src/repository/account_test.go @@ -0,0 +1,101 @@ +package repository + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCreateAccount(t *testing.T) { + // Given + account := givenAccount(true) + + // Test + createdAccount, err := accountRepository.Create(&account) + + // Assert + assert.Nil(t, err) + assert.NotNil(t, createdAccount.ID) +} + +func TestFetchAccountByDomainId(t *testing.T) { + // Given + account := givenAccount(true) + accountRepository.Create(&account) + + // Test + fetchedAccount, err := accountRepository.FetchByDomainId(account.Domain.ID) + + // Assert + assert.Nil(t, err) + assert.NotNil(t, fetchedAccount.ID) +} + +func TestFetchAccountByDomainIdNotFound(t *testing.T) { + // Test + _, err := accountRepository.FetchByDomainId("non_existent_domain_id") + + // Assert + assert.NotNil(t, err) +} + +func TestFetchAllActiveAccounts(t *testing.T) { + // Given + account1 := givenAccount(true) + account2 := givenAccount(false) + accountRepository.Create(&account1) + accountRepository.Create(&account2) + + // Test + accounts, err := accountRepository.FetchAllActiveAccounts() + + // Assert + assert.Nil(t, err) + assert.Equal(t, 1, len(accounts)) +} + +func TestUpdateAccount(t *testing.T) { + // Given + account := givenAccount(true) + accountRepository.Create(&account) + + // Test + account.Branch = "new_branch" + updatedAccount, err := accountRepository.Update(&account) + + // Assert + assert.Nil(t, err) + assert.Equal(t, "new_branch", updatedAccount.Branch) +} + +func TestUpdateAccountNotFound(t *testing.T) { + // Given + account := givenAccount(true) + account.Domain.ID = "non_existent_domain_id" + + // Test + _, err := accountRepository.Update(&account) + + // Assert + assert.NotNil(t, err) +} + +func TestDeleteAccount(t *testing.T) { + // Given + account := givenAccount(true) + accountRepository.Create(&account) + + // Test + err := accountRepository.DeleteByDomainId(account.Domain.ID) + + // Assert + assert.Nil(t, err) +} + +func TestDeleteAccountNotFound(t *testing.T) { + // Test + err := accountRepository.DeleteByDomainId("non_existent_domain_id") + + // Assert + assert.NotNil(t, err) +} diff --git a/src/repository/repository_test.go b/src/repository/repository_test.go new file mode 100644 index 0000000..f5fee84 --- /dev/null +++ b/src/repository/repository_test.go @@ -0,0 +1,57 @@ +package repository + +import ( + "context" + "os" + "testing" + + "github.com/switcherapi/switcher-gitops/src/config" + "github.com/switcherapi/switcher-gitops/src/db" + "github.com/switcherapi/switcher-gitops/src/model" + "go.mongodb.org/mongo-driver/mongo" +) + +var mongoDb *mongo.Database +var accountRepository *AccountRepositoryMongo + +func TestMain(m *testing.M) { + setup() + code := m.Run() + shutdown() + os.Exit(code) +} + +func setup() { + os.Setenv("GO_ENV", "test") + config.InitEnv() + mongoDb = db.InitDb() + + accountRepository = NewAccountRepositoryMongo(mongoDb) +} + +func shutdown() { + mongoDb.Drop(context.Background()) + mongoDb.Client().Disconnect(context.Background()) +} + +// Fixtures + +func givenAccount(active bool) model.Account { + return model.Account{ + Repository: "switcherapi/switcher-gitops", + Branch: "master", + Domain: model.DomainDetails{ + ID: "123", + Name: "Switcher GitOps", + Version: "123", + LastCommit: "123", + Status: "active", + Message: "Synced successfully", + }, + Settings: model.Settings{ + Active: active, + Window: "10m", + ForcePrune: false, + }, + } +}