Skip to content

Commit

Permalink
Feat/add integration test (#54)
Browse files Browse the repository at this point in the history
* expose docker manager and fix testing suite name

* add apply up integration test

* add test driver

* implement more of apply integration test

* finish apply integration test

* add automatic config file creation on tests

* remove unnecessary mysql connection

* remove error assessment

* fix mock config file creation error

* separate integration tests

* attempt to add coverage reports to github actions

* Update Makefile

Co-authored-by: Alexandre Maranhão <[email protected]>

* change codecov reports

Co-authored-by: Alexandre Maranhão <[email protected]>
  • Loading branch information
kenji-yamane and alexandremr01 authored Jul 10, 2022
1 parent 467e8a7 commit c2255e9
Show file tree
Hide file tree
Showing 11 changed files with 514 additions and 22 deletions.
8 changes: 6 additions & 2 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ jobs:
- name: Build
run: make build
- name: Run tests
run: make test
run: make check
- name: Upload coverage reports to Codecov with GitHub Action
run: curl -Os https://uploader.codecov.io/latest/linux/codecov && chmod +x codecov && ./codecov -t ${CODECOV_TOKEN}
run: |
curl -Os https://uploader.codecov.io/latest/linux/codecov
chmod +x codecov
./codecov -t ${CODECOV_TOKEN} -f coverage.txt -F unit
./codecov -t ${CODECOV_TOKEN} -f integration_coverage.txt -F integration
8 changes: 6 additions & 2 deletions .github/workflows/tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@ jobs:
- name: Build
run: make build
- name: Run tests
run: make test
run: make check
- name: Upload coverage reports to Codecov with GitHub Action
run: curl -Os https://uploader.codecov.io/latest/linux/codecov && chmod +x codecov && ./codecov -t ${CODECOV_TOKEN}
run: |
curl -Os https://uploader.codecov.io/latest/linux/codecov
chmod +x codecov
./codecov -t ${CODECOV_TOKEN} -f coverage.txt -F unit
./codecov -t ${CODECOV_TOKEN} -f integration_coverage.txt -F integration
tag:
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ bin/
.idea
.vscode
coverage.txt
integration_coverage.txt

dist
.release-env
Expand Down
19 changes: 18 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ install-tools:

.PHONY: test
test:
go test ./... -coverprofile=coverage.txt
go test --short ./... -coverprofile=coverage.txt

.PHONY: coverage-report
coverage-report:
Expand All @@ -22,6 +22,23 @@ UNIT_COVERAGE:= $(shell go tool cover -func=coverage.txt | tail -n 1 | cut -d '
display-coverage:
@echo "Unit Coverage: $(UNIT_COVERAGE)"

.PHONY: integration-test
integration-test:
go test -run Integration ./... -coverprofile=integration_coverage.txt

.PHONY: integration-coverage-report
integration-coverage-report:
go tool cover -html=integration_coverage.txt

INTEGRATION_COVERAGE:= $(shell go tool cover -func=integration_coverage.txt | tail -n 1 | cut -d ' ' -f 3 | rev | cut -c 1-5 | rev)

.PHONY: integration-display-coverage
integration-display-coverage:
@echo "Integration Coverage: $(INTEGRATION_COVERAGE)"

.PHONY: check
check: test integration-test

.PHONY: release
release:
@if [ ! -f ".release-env" ]; then \
Expand Down
111 changes: 111 additions & 0 deletions cmd/apply_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package cmd

import (
"github.com/migratemgr8/mgr8/global"
"github.com/migratemgr8/mgr8/infrastructure"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("Apply integration test", func() {
var (
subject CommandExecutor = &apply{}
)

executeApply := func(args []string) {
err := subject.execute(
args,
dm.GetConnectionString(global.Postgres),
testMigrationsFolder,
postgresDriver,
infrastructure.CriticalLogLevel,
)
Expect(err).To(BeNil())
}

Context("execute", func() {
When("up with 3", func() {
It("executes all three files that increase migration in folder", func() {
AssertStateBeforeAllMigrations()
executeApply([]string{"up", "3"})
AssertStateAfterAllMigrations()
})
})
When("down with no number specified", func() {
It("decreases one", func() {
executeApply([]string{"down"})
AssertStateAfterMigration0002AndBefore0003()
executeApply([]string{"down"})
AssertStateAfterMigration0001AndBefore0002()
executeApply([]string{"down"})
AssertStateBeforeAllMigrations()
})
})
When("different commands are executed sequentially", func() {
It("should work as expected", func() {
executeApply([]string{"up", "2"})
AssertStateAfterMigration0002AndBefore0003()
executeApply([]string{"down", "1"})
AssertStateAfterMigration0001AndBefore0002()
executeApply([]string{"up"})
AssertStateAfterMigration0002AndBefore0003()
executeApply([]string{"down", "2"})
AssertStateBeforeAllMigrations()
})
})
})
})

func AssertStateBeforeAllMigrations() {
exists, err := postgresTestDriver.AssertTableExistence(userFixture0001.TableName)
Expect(err).To(BeNil())
Expect(exists).To(BeFalse())
exists, err = postgresTestDriver.AssertViewExistence(userViewFixture0002.ViewName)
Expect(err).To(BeNil())
Expect(exists).To(BeFalse())
}

func AssertStateAfterMigration0001AndBefore0002() {
exists, err := postgresTestDriver.AssertFixtureExistence(userFixture0001)
Expect(err).To(BeNil())
Expect(exists).To(BeTrue())
exists, err = postgresTestDriver.AssertVarcharExistence(userFixture0001.TableName, firstNewColumnFixture0002)
Expect(err).To(BeNil())
Expect(exists).To(BeFalse())
exists, err = postgresTestDriver.AssertViewExistence(userViewFixture0002.ViewName)
Expect(err).To(BeNil())
Expect(exists).To(BeFalse())
exists, err = postgresTestDriver.AssertVarcharExistence(userFixture0001.TableName, secondNewColumnFixture0003)
Expect(err).To(BeNil())
Expect(exists).To(BeFalse())
}

func AssertStateAfterMigration0002AndBefore0003() {
exists, err := postgresTestDriver.AssertFixtureExistence(userFixture0001)
Expect(err).To(BeNil())
Expect(exists).To(BeTrue())
exists, err = postgresTestDriver.AssertVarcharExistence(userFixture0001.TableName, firstNewColumnFixture0002)
Expect(err).To(BeNil())
Expect(exists).To(BeTrue())
exists, err = postgresTestDriver.AssertViewFixtureExistence(userViewFixture0002)
Expect(err).To(BeNil())
Expect(exists).To(BeTrue())
exists, err = postgresTestDriver.AssertVarcharExistence(userFixture0001.TableName, secondNewColumnFixture0003)
Expect(err).To(BeNil())
Expect(exists).To(BeFalse())
}

func AssertStateAfterAllMigrations() {
exists, err := postgresTestDriver.AssertFixtureExistence(userFixture0001)
Expect(err).To(BeNil())
Expect(exists).To(BeTrue())
exists, err = postgresTestDriver.AssertVarcharExistence(userFixture0001.TableName, firstNewColumnFixture0002)
Expect(err).To(BeNil())
Expect(exists).To(BeTrue())
exists, err = postgresTestDriver.AssertViewFixtureExistence(userViewFixture0002)
Expect(err).To(BeNil())
Expect(exists).To(BeTrue())
exists, err = postgresTestDriver.AssertVarcharExistence(userFixture0001.TableName, secondNewColumnFixture0003)
Expect(err).To(BeNil())
Expect(exists).To(BeTrue())
}
89 changes: 89 additions & 0 deletions cmd/command_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package cmd

import (
"github.com/migratemgr8/mgr8/applications"
"github.com/migratemgr8/mgr8/infrastructure"
"github.com/migratemgr8/mgr8/testing/fixtures"
"os"
"testing"

"github.com/migratemgr8/mgr8/domain"
"github.com/migratemgr8/mgr8/drivers"
"github.com/migratemgr8/mgr8/global"
mgr8testing "github.com/migratemgr8/mgr8/testing"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _t *testing.T
var dm *mgr8testing.DockerManager

var (
postgresTestDriver mgr8testing.TestDriver
postgresDriver domain.Driver
postgresMigrations fixtures.MigrationsFixture
userFixture0001 fixtures.Fixture
firstNewColumnFixture0002 fixtures.VarcharFixture
userViewFixture0002 fixtures.ViewFixture
secondNewColumnFixture0003 fixtures.VarcharFixture
)

var (
testMigrationsFolder = "apply-test-migrations"
mockUser = "mock-user"
)

func TestCommandIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration tests")
}
_t = t
RegisterFailHandler(Fail)
RunSpecs(t, "Command Test Suite")
}

var _ = BeforeSuite(func() {
createConfigFileIfNotExists()
dm = mgr8testing.NewDockerManager()

postgresTestDriver = mgr8testing.NewTestDriver(global.Postgres)
postgresDriver = getDriverSuccessfully(global.Postgres)
postgresMigrations = fixtures.NewMigrationsFixture(testMigrationsFolder,
infrastructure.NewFileService(),
postgresDriver.Deparser(),
)
userFixture0001 = postgresMigrations.AddMigration0001()
firstNewColumnFixture0002, userViewFixture0002 = postgresMigrations.AddMigration0002()
secondNewColumnFixture0003 = postgresMigrations.AddMigration0003()
})

var _ = AfterSuite(func() {
err := dm.CloseAll()
Expect(err).To(BeNil())
postgresMigrations.TearDown()
})

func createConfigFileIfNotExists() {
configPath, err := applications.GetConfigFilePath()
Expect(err).To(BeNil())
config, err := os.Open(configPath)
if err == nil {
return
}
config, err = os.Create(configPath)
Expect(err).To(BeNil())
username := mockUser
hostname, err := os.Hostname()
Expect(err).To(BeNil())
err = applications.InsertUserDetails(username, hostname, config)
Expect(err).To(BeNil())
err = config.Close()
Expect(err).To(BeNil())
}

func getDriverSuccessfully(d global.Database) domain.Driver {
driver, err := drivers.GetDriver(d)
Expect(err).To(BeNil())
return driver
}
24 changes: 9 additions & 15 deletions testing/dockermanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"database/sql"
"log"
"sync"
"sync/atomic"
"time"

_ "github.com/go-sql-driver/mysql"
Expand All @@ -16,25 +15,23 @@ import (
"github.com/migratemgr8/mgr8/testing/databaseconfigs"
)

type dockerManager struct {
type DockerManager struct {
pool *dockertest.Pool
configs map[global.Database]DatabaseConfig
resources map[global.Database]*dockertest.Resource
calls int64
}

var m *dockerManager
var m *DockerManager

var initializeDockerManagerOnce sync.Once

func NewDockerManager() *dockerManager {
func NewDockerManager() *DockerManager {
initializeDockerManagerOnce.Do(initializeDockerManager)
atomic.AddInt64(&m.calls, 1)
return m
}

func initializeDockerManager() {
m = &dockerManager{calls: 0}
m = &DockerManager{}
var err error
m.pool, err = dockertest.NewPool("")
if err != nil {
Expand Down Expand Up @@ -77,17 +74,14 @@ func initializeDockerManager() {
}
}

func (m *dockerManager) GetConnectionString(d global.Database) string {
func (m *DockerManager) GetConnectionString(d global.Database) string {
return m.configs[d].DatabaseUrl(m.resources[d])
}

func (m *dockerManager) CloseAll() error {
atomic.AddInt64(&m.calls, -1)
if m.calls == 0 {
for _, r := range m.resources {
if err := m.pool.Purge(r); err != nil {
return err
}
func (m *DockerManager) CloseAll() error {
for _, r := range m.resources {
if err := m.pool.Purge(r); err != nil {
return err
}
}
return nil
Expand Down
7 changes: 5 additions & 2 deletions testing/dockermanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,18 @@ import (

var _t *testing.T

func TestApplication(t *testing.T) {
func TestTestingIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration tests")
}
_t = t
RegisterFailHandler(Fail)
RunSpecs(t, "Testing Test Suite")
}

var _ = Describe("Check Command", func() {
var (
subject *dockerManager
subject *DockerManager
)

BeforeSuite(func() {
Expand Down
41 changes: 41 additions & 0 deletions testing/fixtures/fixtures.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package fixtures

import "github.com/migratemgr8/mgr8/domain"

type VarcharFixture struct {
Name string
Cap int64
}

func (f *VarcharFixture) ToDomainColumn() *domain.Column {
return &domain.Column{
Parameters: map[string]interface{}{
"size": f.Cap,
},
Datatype: "varchar",
}
}

type Fixture struct {
TableName string
VarcharColumns []VarcharFixture
TextColumns []string
}

func (f *Fixture) ToDomainTable() *domain.Table {
t := domain.NewTable(f.TableName, map[string]*domain.Column{})
for _, varchar := range f.VarcharColumns {
t.Columns[varchar.Name] = varchar.ToDomainColumn()
}
for _, text := range f.TextColumns {
t.Columns[text] = &domain.Column{Datatype: "text"}
}
return t
}

type ViewFixture struct {
ViewName string
TextColumns []string
VarcharColumns []VarcharFixture
Statement string
}
Loading

0 comments on commit c2255e9

Please sign in to comment.