mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-11-27 04:11:03 +00:00
Merge pull request #254 from fudanchii/migration-test
Add database & migration test using mysql
This commit is contained in:
commit
dd670f413a
7 changed files with 838 additions and 600 deletions
|
@ -5,7 +5,7 @@ env:
|
|||
- PATH=$PWD/Godeps/_workspace/bin:/var/cache/drone/bin:$PATH
|
||||
script:
|
||||
- sudo apt-get -y install libsqlite3-dev sqlite3 1> /dev/null 2> /dev/null
|
||||
- make
|
||||
- make build-dist
|
||||
- make test
|
||||
- make dpkg
|
||||
notify:
|
||||
|
|
31
Makefile
31
Makefile
|
@ -1,3 +1,5 @@
|
|||
SELFPKG := github.com/drone/drone
|
||||
VERSION := 0.2
|
||||
SHA := $(shell git rev-parse --short HEAD)
|
||||
BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
|
||||
PKGS := \
|
||||
|
@ -11,7 +13,7 @@ build/script \
|
|||
channel \
|
||||
database \
|
||||
database/encrypt \
|
||||
database/migrate \
|
||||
database/migrate/testing \
|
||||
database/testing \
|
||||
mail \
|
||||
model \
|
||||
|
@ -22,10 +24,25 @@ PKGS := $(addprefix github.com/drone/drone/pkg/,$(PKGS))
|
|||
|
||||
all: embed build
|
||||
|
||||
build:
|
||||
go build -o bin/drone -ldflags "-X main.version $(VERSION)dev-$(SHA)" $(SELFPKG)/cmd/drone
|
||||
go build -o bin/droned -ldflags "-X main.version $(VERSION)dev-$(SHA)" $(SELFPKG)/cmd/droned
|
||||
|
||||
build-dist: godep
|
||||
godep go build -o bin/drone -ldflags "-X main.version $(VERSION)-$(SHA)" $(SELFPKG)/cmd/drone
|
||||
godep go build -o bin/droned -ldflags "-X main.version $(VERSION)-$(SHA)" $(SELFPKG)/cmd/droned
|
||||
|
||||
bump-deps: deps vendor
|
||||
|
||||
deps:
|
||||
go get -u -t -v ./...
|
||||
|
||||
vendor: godep
|
||||
git submodule update --init --recursive
|
||||
godep save ./...
|
||||
|
||||
|
||||
# Embed static assets
|
||||
embed: js rice
|
||||
cd cmd/droned && rice embed
|
||||
cd pkg/template && rice embed
|
||||
|
@ -33,14 +50,10 @@ embed: js rice
|
|||
js:
|
||||
cd cmd/droned/assets && find js -name "*.js" ! -name '.*' ! -name "main.js" -exec cat {} \; > js/main.js
|
||||
|
||||
build:
|
||||
cd cmd/drone && go build -ldflags "-X main.version $(SHA)" -o ../../bin/drone
|
||||
cd cmd/droned && go build -ldflags "-X main.version $(SHA)" -o ../../bin/droned
|
||||
|
||||
test: $(PKGS)
|
||||
|
||||
$(PKGS):
|
||||
go test -v $@
|
||||
$(PKGS): godep
|
||||
godep go test -v $@
|
||||
|
||||
install:
|
||||
cp deb/drone/etc/init/drone.conf /etc/init/drone.conf
|
||||
|
@ -76,10 +89,6 @@ dpkg:
|
|||
run:
|
||||
bin/droned --port=":8080" --datasource="drone.sqlite"
|
||||
|
||||
go-gitlab-client:
|
||||
rm -rf $$GOPATH/src/github.com/plouc/go-gitlab-client
|
||||
git clone -b raw-request https://github.com/fudanchii/go-gitlab-client $$GOPATH/src/github.com/plouc/go-gitlab-client
|
||||
|
||||
godep:
|
||||
go get github.com/tools/godep
|
||||
|
||||
|
|
|
@ -1,575 +0,0 @@
|
|||
package migrate_test
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
. "github.com/drone/drone/pkg/database/migrate"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/russross/meddler"
|
||||
)
|
||||
|
||||
type Sample struct {
|
||||
ID int64 `meddler:"id,pk"`
|
||||
Imel string `meddler:"imel"`
|
||||
Name string `meddler:"name"`
|
||||
}
|
||||
|
||||
type RenameSample struct {
|
||||
ID int64 `meddler:"id,pk"`
|
||||
Email string `meddler:"email"`
|
||||
Name string `meddler:"name"`
|
||||
}
|
||||
|
||||
type AddColumnSample struct {
|
||||
ID int64 `meddler:"id,pk"`
|
||||
Imel string `meddler:"imel"`
|
||||
Name string `meddler:"name"`
|
||||
Url string `meddler:"url"`
|
||||
Num int64 `meddler:"num"`
|
||||
}
|
||||
|
||||
// ---------- revision 1
|
||||
|
||||
type revision1 struct{}
|
||||
|
||||
func (r *revision1) Up(mg *MigrationDriver) error {
|
||||
_, err := mg.CreateTable("samples", []string{
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT",
|
||||
"imel VARCHAR(255) UNIQUE",
|
||||
"name VARCHAR(255)",
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision1) Down(mg *MigrationDriver) error {
|
||||
_, err := mg.DropTable("samples")
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision1) Revision() int64 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// ---------- end of revision 1
|
||||
|
||||
// ---------- revision 2
|
||||
|
||||
type revision2 struct{}
|
||||
|
||||
func (r *revision2) Up(mg *MigrationDriver) error {
|
||||
_, err := mg.RenameTable("samples", "examples")
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision2) Down(mg *MigrationDriver) error {
|
||||
_, err := mg.RenameTable("examples", "samples")
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision2) Revision() int64 {
|
||||
return 2
|
||||
}
|
||||
|
||||
// ---------- end of revision 2
|
||||
|
||||
// ---------- revision 3
|
||||
|
||||
type revision3 struct{}
|
||||
|
||||
func (r *revision3) Up(mg *MigrationDriver) error {
|
||||
if _, err := mg.AddColumn("samples", "url VARCHAR(255)"); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := mg.AddColumn("samples", "num INTEGER")
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision3) Down(mg *MigrationDriver) error {
|
||||
_, err := mg.DropColumns("samples", "num", "url")
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision3) Revision() int64 {
|
||||
return 3
|
||||
}
|
||||
|
||||
// ---------- end of revision 3
|
||||
|
||||
// ---------- revision 4
|
||||
|
||||
type revision4 struct{}
|
||||
|
||||
func (r *revision4) Up(mg *MigrationDriver) error {
|
||||
_, err := mg.RenameColumns("samples", map[string]string{
|
||||
"imel": "email",
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision4) Down(mg *MigrationDriver) error {
|
||||
_, err := mg.RenameColumns("samples", map[string]string{
|
||||
"email": "imel",
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision4) Revision() int64 {
|
||||
return 4
|
||||
}
|
||||
|
||||
// ---------- end of revision 4
|
||||
|
||||
// ---------- revision 5
|
||||
|
||||
type revision5 struct{}
|
||||
|
||||
func (r *revision5) Up(mg *MigrationDriver) error {
|
||||
_, err := mg.AddIndex("samples", []string{"url", "name"})
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision5) Down(mg *MigrationDriver) error {
|
||||
_, err := mg.DropIndex("samples", []string{"url", "name"})
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision5) Revision() int64 {
|
||||
return 5
|
||||
}
|
||||
|
||||
// ---------- end of revision 5
|
||||
|
||||
// ---------- revision 6
|
||||
type revision6 struct{}
|
||||
|
||||
func (r *revision6) Up(mg *MigrationDriver) error {
|
||||
_, err := mg.RenameColumns("samples", map[string]string{
|
||||
"url": "host",
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision6) Down(mg *MigrationDriver) error {
|
||||
_, err := mg.RenameColumns("samples", map[string]string{
|
||||
"host": "url",
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision6) Revision() int64 {
|
||||
return 6
|
||||
}
|
||||
|
||||
// ---------- end of revision 6
|
||||
|
||||
// ---------- revision 7
|
||||
type revision7 struct{}
|
||||
|
||||
func (r *revision7) Up(mg *MigrationDriver) error {
|
||||
_, err := mg.DropColumns("samples", "host", "num")
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision7) Down(mg *MigrationDriver) error {
|
||||
if _, err := mg.AddColumn("samples", "host VARCHAR(255)"); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := mg.AddColumn("samples", "num INSTEGER")
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision7) Revision() int64 {
|
||||
return 7
|
||||
}
|
||||
|
||||
// ---------- end of revision 7
|
||||
|
||||
// ---------- revision 8
|
||||
type revision8 struct{}
|
||||
|
||||
func (r *revision8) Up(mg *MigrationDriver) error {
|
||||
if _, err := mg.AddColumn("samples", "repo_id INTEGER"); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := mg.AddColumn("samples", "repo VARCHAR(255)")
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision8) Down(mg *MigrationDriver) error {
|
||||
_, err := mg.DropColumns("samples", "repo", "repo_id")
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision8) Revision() int64 {
|
||||
return 8
|
||||
}
|
||||
|
||||
// ---------- end of revision 8
|
||||
|
||||
// ---------- revision 9
|
||||
type revision9 struct{}
|
||||
|
||||
func (r *revision9) Up(mg *MigrationDriver) error {
|
||||
_, err := mg.RenameColumns("samples", map[string]string{
|
||||
"repo": "repository",
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision9) Down(mg *MigrationDriver) error {
|
||||
_, err := mg.RenameColumns("samples", map[string]string{
|
||||
"repository": "repo",
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision9) Revision() int64 {
|
||||
return 9
|
||||
}
|
||||
|
||||
// ---------- end of revision 9
|
||||
|
||||
// ---------- revision 10
|
||||
|
||||
type revision10 struct{}
|
||||
|
||||
func (r *revision10) Revision() int64 {
|
||||
return 10
|
||||
}
|
||||
|
||||
func (r *revision10) Up(mg *MigrationDriver) error {
|
||||
_, err := mg.ChangeColumn("samples", "email", "varchar(512) UNIQUE")
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision10) Down(mg *MigrationDriver) error {
|
||||
_, err := mg.ChangeColumn("samples", "email", "varchar(255) unique")
|
||||
return err
|
||||
}
|
||||
|
||||
// ---------- end of revision 10
|
||||
|
||||
var db *sql.DB
|
||||
|
||||
var testSchema = `
|
||||
CREATE TABLE samples (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
imel VARCHAR(255) UNIQUE,
|
||||
name VARCHAR(255)
|
||||
);
|
||||
`
|
||||
|
||||
var dataDump = []string{
|
||||
`INSERT INTO samples (imel, name) VALUES ('test@example.com', 'Test Tester');`,
|
||||
`INSERT INTO samples (imel, name) VALUES ('foo@bar.com', 'Foo Bar');`,
|
||||
`INSERT INTO samples (imel, name) VALUES ('crash@bandicoot.io', 'Crash Bandicoot');`,
|
||||
}
|
||||
|
||||
func TestMigrateCreateTable(t *testing.T) {
|
||||
defer tearDown()
|
||||
if err := setUp(); err != nil {
|
||||
t.Fatalf("Error preparing database: %q", err)
|
||||
}
|
||||
|
||||
mgr := New(db)
|
||||
if err := mgr.Add(&revision1{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
sample := Sample{
|
||||
ID: 1,
|
||||
Imel: "test@example.com",
|
||||
Name: "Test Tester",
|
||||
}
|
||||
if err := meddler.Save(db, "samples", &sample); err != nil {
|
||||
t.Fatalf("Can not save data: %q", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrateExistingCreateTable(t *testing.T) {
|
||||
defer tearDown()
|
||||
if err := setUp(); err != nil {
|
||||
t.Fatalf("Error preparing database: %q", err)
|
||||
}
|
||||
|
||||
if _, err := db.Exec(testSchema); err != nil {
|
||||
t.Fatalf("Can not create database: %q", err)
|
||||
}
|
||||
|
||||
mgr := New(db)
|
||||
rev := &revision1{}
|
||||
if err := mgr.Add(rev).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
var current int64
|
||||
db.QueryRow("SELECT max(revision) FROM migration").Scan(¤t)
|
||||
if current != rev.Revision() {
|
||||
t.Fatalf("Did not successfully migrate")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrateRenameTable(t *testing.T) {
|
||||
defer tearDown()
|
||||
if err := setUp(); err != nil {
|
||||
t.Fatalf("Error preparing database: %q", err)
|
||||
}
|
||||
|
||||
mgr := New(db)
|
||||
if err := mgr.Add(&revision1{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
loadFixture(t)
|
||||
|
||||
if err := mgr.Add(&revision2{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
sample := Sample{}
|
||||
if err := meddler.QueryRow(db, &sample, `SELECT * FROM examples WHERE id = ?`, 2); err != nil {
|
||||
t.Fatalf("Can not fetch data: %q", err)
|
||||
}
|
||||
|
||||
if sample.Imel != "foo@bar.com" {
|
||||
t.Errorf("Column doesn't match. Expect: %s, got: %s", "foo@bar.com", sample.Imel)
|
||||
}
|
||||
}
|
||||
|
||||
type TableInfo struct {
|
||||
CID int64 `meddler:"cid,pk"`
|
||||
Name string `meddler:"name"`
|
||||
Type string `meddler:"type"`
|
||||
Notnull bool `meddler:"notnull"`
|
||||
DfltValue interface{} `meddler:"dflt_value"`
|
||||
PK bool `meddler:"pk"`
|
||||
}
|
||||
|
||||
func TestMigrateAddRemoveColumns(t *testing.T) {
|
||||
defer tearDown()
|
||||
if err := setUp(); err != nil {
|
||||
t.Fatalf("Error preparing database: %q", err)
|
||||
}
|
||||
|
||||
mgr := New(db)
|
||||
if err := mgr.Add(&revision1{}, &revision3{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
var columns []*TableInfo
|
||||
if err := meddler.QueryAll(db, &columns, `PRAGMA table_info(samples);`); err != nil {
|
||||
t.Fatalf("Can not access table info: %q", err)
|
||||
}
|
||||
|
||||
if len(columns) < 5 {
|
||||
t.Errorf("Expect length columns: %d\nGot: %d", 5, len(columns))
|
||||
}
|
||||
|
||||
var row = AddColumnSample{
|
||||
ID: 33,
|
||||
Name: "Foo",
|
||||
Imel: "foo@bar.com",
|
||||
Url: "http://example.com",
|
||||
Num: 42,
|
||||
}
|
||||
if err := meddler.Save(db, "samples", &row); err != nil {
|
||||
t.Fatalf("Can not save into database: %q", err)
|
||||
}
|
||||
|
||||
if err := mgr.MigrateTo(1); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
var another_columns []*TableInfo
|
||||
if err := meddler.QueryAll(db, &another_columns, `PRAGMA table_info(samples);`); err != nil {
|
||||
t.Fatalf("Can not access table info: %q", err)
|
||||
}
|
||||
|
||||
if len(another_columns) != 3 {
|
||||
t.Errorf("Expect length columns = %d, got: %d", 3, len(columns))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenameColumn(t *testing.T) {
|
||||
defer tearDown()
|
||||
if err := setUp(); err != nil {
|
||||
t.Fatalf("Error preparing database: %q", err)
|
||||
}
|
||||
|
||||
mgr := New(db)
|
||||
if err := mgr.Add(&revision1{}, &revision4{}).MigrateTo(1); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
loadFixture(t)
|
||||
|
||||
if err := mgr.MigrateTo(4); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
row := RenameSample{}
|
||||
if err := meddler.QueryRow(db, &row, `SELECT * FROM samples WHERE id = 3;`); err != nil {
|
||||
t.Fatalf("Can not query database: %q", err)
|
||||
}
|
||||
|
||||
if row.Email != "crash@bandicoot.io" {
|
||||
t.Errorf("Expect %s, got %s", "crash@bandicoot.io", row.Email)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrateExistingTable(t *testing.T) {
|
||||
defer tearDown()
|
||||
if err := setUp(); err != nil {
|
||||
t.Fatalf("Error preparing database: %q", err)
|
||||
}
|
||||
|
||||
if _, err := db.Exec(testSchema); err != nil {
|
||||
t.Fatalf("Can not create database: %q", err)
|
||||
}
|
||||
|
||||
loadFixture(t)
|
||||
|
||||
mgr := New(db)
|
||||
if err := mgr.Add(&revision4{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
var rows []*RenameSample
|
||||
if err := meddler.QueryAll(db, &rows, `SELECT * from samples;`); err != nil {
|
||||
t.Fatalf("Can not query database: %q", err)
|
||||
}
|
||||
|
||||
if len(rows) != 3 {
|
||||
t.Errorf("Expect rows length = %d, got %d", 3, len(rows))
|
||||
}
|
||||
|
||||
if rows[1].Email != "foo@bar.com" {
|
||||
t.Errorf("Expect email = %s, got %s", "foo@bar.com", rows[1].Email)
|
||||
}
|
||||
}
|
||||
|
||||
type sqliteMaster struct {
|
||||
Sql interface{} `meddler:"sql"`
|
||||
}
|
||||
|
||||
func TestIndexOperations(t *testing.T) {
|
||||
defer tearDown()
|
||||
if err := setUp(); err != nil {
|
||||
t.Fatalf("Error preparing database: %q", err)
|
||||
}
|
||||
|
||||
mgr := New(db)
|
||||
|
||||
// Migrate, create index
|
||||
if err := mgr.Add(&revision1{}, &revision3{}, &revision5{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
var esquel []*sqliteMaster
|
||||
// Query sqlite_master, check if index is exists.
|
||||
query := `SELECT sql FROM sqlite_master WHERE type='index' and tbl_name='samples'`
|
||||
if err := meddler.QueryAll(db, &esquel, query); err != nil {
|
||||
t.Fatalf("Can not find index: %q", err)
|
||||
}
|
||||
|
||||
indexStatement := `CREATE INDEX idx_samples_on_url_and_name ON samples (url, name)`
|
||||
if string(esquel[1].Sql.([]byte)) != indexStatement {
|
||||
t.Errorf("Can not find index, got: %q", esquel[1])
|
||||
}
|
||||
|
||||
// Migrate, rename indexed columns
|
||||
if err := mgr.Add(&revision6{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
var esquel1 []*sqliteMaster
|
||||
if err := meddler.QueryAll(db, &esquel1, query); err != nil {
|
||||
t.Fatalf("Can not find index: %q", err)
|
||||
}
|
||||
|
||||
indexStatement = `CREATE INDEX idx_samples_on_host_and_name ON samples (host, name)`
|
||||
if string(esquel1[1].Sql.([]byte)) != indexStatement {
|
||||
t.Errorf("Can not find index, got: %q", esquel1[1])
|
||||
}
|
||||
|
||||
if err := mgr.Add(&revision7{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
var esquel2 []*sqliteMaster
|
||||
if err := meddler.QueryAll(db, &esquel2, query); err != nil {
|
||||
t.Fatalf("Can not find index: %q", err)
|
||||
}
|
||||
|
||||
if len(esquel2) != 1 {
|
||||
t.Errorf("Expect row length equal to %d, got %d", 1, len(esquel2))
|
||||
}
|
||||
}
|
||||
|
||||
func TestColumnRedundancy(t *testing.T) {
|
||||
defer tearDown()
|
||||
if err := setUp(); err != nil {
|
||||
t.Fatalf("Error preparing database: %q", err)
|
||||
}
|
||||
|
||||
migr := New(db)
|
||||
if err := migr.Add(&revision1{}, &revision8{}, &revision9{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
var tableSql string
|
||||
query := `SELECT sql FROM sqlite_master where type='table' and name='samples'`
|
||||
if err := db.QueryRow(query).Scan(&tableSql); err != nil {
|
||||
t.Fatalf("Can not query sqlite_master: %q", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(tableSql, "repository ") {
|
||||
t.Errorf("Expect column with name repository")
|
||||
}
|
||||
}
|
||||
|
||||
func TestChangeColumnType(t *testing.T) {
|
||||
defer tearDown()
|
||||
if err := setUp(); err != nil {
|
||||
t.Fatalf("Error preparing database: %q", err)
|
||||
}
|
||||
|
||||
migr := New(db)
|
||||
if err := migr.Add(&revision1{}, &revision4{}, &revision10{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
var tableSql string
|
||||
query := `SELECT sql FROM sqlite_master where type='table' and name='samples'`
|
||||
if err := db.QueryRow(query).Scan(&tableSql); err != nil {
|
||||
t.Fatalf("Can not query sqlite_master: %q", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(tableSql, "email varchar(512) UNIQUE") {
|
||||
t.Errorf("Expect email type to changed: %q", tableSql)
|
||||
}
|
||||
}
|
||||
|
||||
func setUp() error {
|
||||
var err error
|
||||
Driver = SQLite
|
||||
db, err = sql.Open("sqlite3", "migration_tests.sqlite")
|
||||
return err
|
||||
}
|
||||
|
||||
func tearDown() {
|
||||
db.Close()
|
||||
os.Remove("migration_tests.sqlite")
|
||||
}
|
||||
|
||||
func loadFixture(t *testing.T) {
|
||||
for _, sql := range dataDump {
|
||||
if _, err := db.Exec(sql); err != nil {
|
||||
t.Fatalf("Can not insert into database: %q", err)
|
||||
}
|
||||
}
|
||||
}
|
483
pkg/database/migrate/testing/migrate_test.go
Normal file
483
pkg/database/migrate/testing/migrate_test.go
Normal file
|
@ -0,0 +1,483 @@
|
|||
package migrate
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
. "github.com/drone/drone/pkg/database/migrate"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/russross/meddler"
|
||||
)
|
||||
|
||||
var (
|
||||
db *sql.DB
|
||||
driver, dsn string
|
||||
|
||||
dbname = "drone_test"
|
||||
)
|
||||
|
||||
var sqliteTestSchema = `
|
||||
CREATE TABLE samples (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
imel VARCHAR(255) UNIQUE,
|
||||
name VARCHAR(255)
|
||||
);
|
||||
`
|
||||
|
||||
var mysqlTestSchema = `
|
||||
CREATE TABLE samples (
|
||||
id INTEGER PRIMARY KEY AUTO_INCREMENT,
|
||||
imel VARCHAR(255) UNIQUE,
|
||||
name VARCHAR(255)
|
||||
)
|
||||
`
|
||||
|
||||
var dataDump = []string{
|
||||
`INSERT INTO samples (imel, name) VALUES ('test@example.com', 'Test Tester');`,
|
||||
`INSERT INTO samples (imel, name) VALUES ('foo@bar.com', 'Foo Bar');`,
|
||||
`INSERT INTO samples (imel, name) VALUES ('crash@bandicoot.io', 'Crash Bandicoot');`,
|
||||
}
|
||||
|
||||
func TestMigrateCreateTable(t *testing.T) {
|
||||
defer tearDown()
|
||||
if err := setUp(); err != nil {
|
||||
t.Fatalf("Error preparing database: %q", err)
|
||||
}
|
||||
|
||||
mgr := New(db)
|
||||
if err := mgr.Add(&revision1{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
sample := Sample{
|
||||
ID: 1,
|
||||
Imel: "test@example.com",
|
||||
Name: "Test Tester",
|
||||
}
|
||||
if err := meddler.Save(db, "samples", &sample); err != nil {
|
||||
t.Fatalf("Can not save data: %q", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrateExistingCreateTable(t *testing.T) {
|
||||
defer tearDown()
|
||||
if err := setUp(); err != nil {
|
||||
t.Fatalf("Error preparing database: %q", err)
|
||||
}
|
||||
|
||||
var testSchema string
|
||||
if driver == "mysql" {
|
||||
testSchema = mysqlTestSchema
|
||||
} else {
|
||||
testSchema = sqliteTestSchema
|
||||
}
|
||||
|
||||
if _, err := db.Exec(testSchema); err != nil {
|
||||
t.Fatalf("Can not create database: %q", err)
|
||||
}
|
||||
|
||||
mgr := New(db)
|
||||
rev := &revision1{}
|
||||
if err := mgr.Add(rev).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
var current int64
|
||||
db.QueryRow("SELECT max(revision) FROM migration").Scan(¤t)
|
||||
if current != rev.Revision() {
|
||||
t.Fatalf("Did not successfully migrate")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrateRenameTable(t *testing.T) {
|
||||
defer tearDown()
|
||||
if err := setUp(); err != nil {
|
||||
t.Fatalf("Error preparing database: %q", err)
|
||||
}
|
||||
|
||||
mgr := New(db)
|
||||
if err := mgr.Add(&revision1{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
loadFixture(t)
|
||||
|
||||
if err := mgr.Add(&revision2{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
sample := Sample{}
|
||||
if err := meddler.QueryRow(db, &sample, `SELECT * FROM examples WHERE id = ?`, 2); err != nil {
|
||||
t.Fatalf("Can not fetch data: %q", err)
|
||||
}
|
||||
|
||||
if sample.Imel != "foo@bar.com" {
|
||||
t.Errorf("Column doesn't match. Expect: %s, got: %s", "foo@bar.com", sample.Imel)
|
||||
}
|
||||
}
|
||||
|
||||
type TableInfo struct {
|
||||
CID int64 `meddler:"cid,pk"`
|
||||
Name string `meddler:"name"`
|
||||
Type string `meddler:"type"`
|
||||
Notnull bool `meddler:"notnull"`
|
||||
DfltValue interface{} `meddler:"dflt_value"`
|
||||
PK bool `meddler:"pk"`
|
||||
}
|
||||
|
||||
type MysqlTableInfo struct {
|
||||
Field string `meddler:"Field"`
|
||||
Type string `meddler:"Type"`
|
||||
Null string `meddler:"Null"`
|
||||
Key interface{} `meddler:"Key"`
|
||||
Default interface{} `meddler:"Default"`
|
||||
Extra interface{} `meddler:"Extra"`
|
||||
}
|
||||
|
||||
func TestMigrateAddRemoveColumns(t *testing.T) {
|
||||
defer tearDown()
|
||||
if err := setUp(); err != nil {
|
||||
t.Fatalf("Error preparing database: %q", err)
|
||||
}
|
||||
|
||||
mgr := New(db)
|
||||
if err := mgr.Add(&revision1{}, &revision3{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
switch driver {
|
||||
case "mysql":
|
||||
var columns []*MysqlTableInfo
|
||||
if err := meddler.QueryAll(db, &columns, `SHOW COLUMNS FROM samples`); err != nil {
|
||||
t.Fatalf("Can not access table infor: %q", err)
|
||||
}
|
||||
|
||||
if len(columns) < 5 {
|
||||
t.Errorf("Expect length columns: %d\nGot: %d", 5, len(columns))
|
||||
}
|
||||
default:
|
||||
var columns []*TableInfo
|
||||
if err := meddler.QueryAll(db, &columns, `PRAGMA table_info(samples);`); err != nil {
|
||||
t.Fatalf("Can not access table info: %q", err)
|
||||
}
|
||||
|
||||
if len(columns) < 5 {
|
||||
t.Errorf("Expect length columns: %d\nGot: %d", 5, len(columns))
|
||||
}
|
||||
}
|
||||
|
||||
var row = AddColumnSample{
|
||||
ID: 33,
|
||||
Name: "Foo",
|
||||
Imel: "foo@bar.com",
|
||||
Url: "http://example.com",
|
||||
Num: 42,
|
||||
}
|
||||
if err := meddler.Save(db, "samples", &row); err != nil {
|
||||
t.Fatalf("Can not save into database: %q", err)
|
||||
}
|
||||
|
||||
if err := mgr.MigrateTo(1); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
switch driver {
|
||||
case "mysql":
|
||||
var columns []*MysqlTableInfo
|
||||
if err := meddler.QueryAll(db, &columns, `SHOW COLUMNS FROM samples`); err != nil {
|
||||
t.Fatalf("Can not access table infor: %q", err)
|
||||
}
|
||||
|
||||
if len(columns) != 3 {
|
||||
t.Errorf("Expect length columns: %d\nGot: %d", 3, len(columns))
|
||||
}
|
||||
default:
|
||||
var columns []*TableInfo
|
||||
if err := meddler.QueryAll(db, &columns, `PRAGMA table_info(samples);`); err != nil {
|
||||
t.Fatalf("Can not access table info: %q", err)
|
||||
}
|
||||
|
||||
if len(columns) != 3 {
|
||||
t.Errorf("Expect length columns: %d\nGot: %d", 3, len(columns))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestRenameColumn(t *testing.T) {
|
||||
defer tearDown()
|
||||
if err := setUp(); err != nil {
|
||||
t.Fatalf("Error preparing database: %q", err)
|
||||
}
|
||||
|
||||
mgr := New(db)
|
||||
if err := mgr.Add(&revision1{}, &revision4{}).MigrateTo(1); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
loadFixture(t)
|
||||
|
||||
if err := mgr.MigrateTo(4); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
row := RenameSample{}
|
||||
if err := meddler.QueryRow(db, &row, `SELECT * FROM samples WHERE id = 3;`); err != nil {
|
||||
t.Fatalf("Can not query database: %q", err)
|
||||
}
|
||||
|
||||
if row.Email != "crash@bandicoot.io" {
|
||||
t.Errorf("Expect %s, got %s", "crash@bandicoot.io", row.Email)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrateExistingTable(t *testing.T) {
|
||||
defer tearDown()
|
||||
if err := setUp(); err != nil {
|
||||
t.Fatalf("Error preparing database: %q", err)
|
||||
}
|
||||
|
||||
var testSchema string
|
||||
if driver == "mysql" {
|
||||
testSchema = mysqlTestSchema
|
||||
} else {
|
||||
testSchema = sqliteTestSchema
|
||||
}
|
||||
|
||||
if _, err := db.Exec(testSchema); err != nil {
|
||||
t.Fatalf("Can not create database: %q", err)
|
||||
}
|
||||
|
||||
loadFixture(t)
|
||||
|
||||
mgr := New(db)
|
||||
if err := mgr.Add(&revision4{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
var rows []*RenameSample
|
||||
if err := meddler.QueryAll(db, &rows, `SELECT * from samples;`); err != nil {
|
||||
t.Fatalf("Can not query database: %q", err)
|
||||
}
|
||||
|
||||
if len(rows) != 3 {
|
||||
t.Errorf("Expect rows length = %d, got %d", 3, len(rows))
|
||||
}
|
||||
|
||||
if rows[1].Email != "foo@bar.com" {
|
||||
t.Errorf("Expect email = %s, got %s", "foo@bar.com", rows[1].Email)
|
||||
}
|
||||
}
|
||||
|
||||
type sqliteMaster struct {
|
||||
Sql interface{} `meddler:"sql"`
|
||||
}
|
||||
|
||||
func TestIndexOperations(t *testing.T) {
|
||||
defer tearDown()
|
||||
if err := setUp(); err != nil {
|
||||
t.Fatalf("Error preparing database: %q", err)
|
||||
}
|
||||
|
||||
mgr := New(db)
|
||||
|
||||
// Migrate, create index
|
||||
if err := mgr.Add(&revision1{}, &revision3{}, &revision5{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
var esquel []*sqliteMaster
|
||||
var mysquel struct {
|
||||
Table string `meddler:"Table"`
|
||||
CreateTable string `meddler:"Create Table"`
|
||||
}
|
||||
switch driver {
|
||||
case "mysql":
|
||||
query := `SHOW CREATE TABLE samples`
|
||||
if err := meddler.QueryRow(db, &mysquel, query); err != nil {
|
||||
t.Fatalf("Can not fetch table definition: %q", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(mysquel.CreateTable, "KEY `idx_samples_on_url_and_name` (`url`,`name`)") {
|
||||
t.Errorf("Can not find index, got: %q", mysquel.CreateTable)
|
||||
}
|
||||
|
||||
if err := mgr.Add(&revision6{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
if err := meddler.QueryRow(db, &mysquel, query); err != nil {
|
||||
t.Fatalf("Can not find index: %q", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(mysquel.CreateTable, "KEY `idx_samples_on_url_and_name` (`host`,`name`)") {
|
||||
t.Errorf("Can not find index, got: %q", mysquel.CreateTable)
|
||||
}
|
||||
|
||||
if err := mgr.Add(&revision7{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
if err := meddler.QueryRow(db, &mysquel, query); err != nil {
|
||||
t.Fatalf("Can not find index: %q", err)
|
||||
}
|
||||
|
||||
if strings.Contains(mysquel.CreateTable, "KEY `idx_samples_on_url_and_name` (`host`,`name`)") {
|
||||
t.Errorf("Expect index to be deleted.")
|
||||
}
|
||||
|
||||
default:
|
||||
// Query sqlite_master, check if index is exists.
|
||||
query := `SELECT sql FROM sqlite_master WHERE type='index' and tbl_name='samples'`
|
||||
if err := meddler.QueryAll(db, &esquel, query); err != nil {
|
||||
t.Fatalf("Can not find index: %q", err)
|
||||
}
|
||||
|
||||
indexStatement := `CREATE INDEX idx_samples_on_url_and_name ON samples (url, name)`
|
||||
if string(esquel[1].Sql.([]byte)) != indexStatement {
|
||||
t.Errorf("Can not find index, got: %q", esquel[1])
|
||||
}
|
||||
|
||||
// Migrate, rename indexed columns
|
||||
if err := mgr.Add(&revision6{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
var esquel1 []*sqliteMaster
|
||||
if err := meddler.QueryAll(db, &esquel1, query); err != nil {
|
||||
t.Fatalf("Can not find index: %q", err)
|
||||
}
|
||||
|
||||
indexStatement = `CREATE INDEX idx_samples_on_host_and_name ON samples (host, name)`
|
||||
if string(esquel1[1].Sql.([]byte)) != indexStatement {
|
||||
t.Errorf("Can not find index, got: %q", esquel1[1])
|
||||
}
|
||||
|
||||
if err := mgr.Add(&revision7{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
var esquel2 []*sqliteMaster
|
||||
if err := meddler.QueryAll(db, &esquel2, query); err != nil {
|
||||
t.Fatalf("Can not find index: %q", err)
|
||||
}
|
||||
|
||||
if len(esquel2) != 1 {
|
||||
t.Errorf("Expect row length equal to %d, got %d", 1, len(esquel2))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestColumnRedundancy(t *testing.T) {
|
||||
defer tearDown()
|
||||
if err := setUp(); err != nil {
|
||||
t.Fatalf("Error preparing database: %q", err)
|
||||
}
|
||||
|
||||
migr := New(db)
|
||||
if err := migr.Add(&revision1{}, &revision8{}, &revision9{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
var dummy, query, tableSql string
|
||||
switch driver {
|
||||
case "mysql":
|
||||
query = `SHOW CREATE TABLE samples`
|
||||
if err := db.QueryRow(query).Scan(&dummy, &tableSql); err != nil {
|
||||
t.Fatalf("Can not query table's definition: %q", err)
|
||||
}
|
||||
if !strings.Contains(tableSql, "`repository`") {
|
||||
t.Errorf("Expect column with name repository")
|
||||
}
|
||||
default:
|
||||
query = `SELECT sql FROM sqlite_master where type='table' and name='samples'`
|
||||
if err := db.QueryRow(query).Scan(&tableSql); err != nil {
|
||||
t.Fatalf("Can not query sqlite_master: %q", err)
|
||||
}
|
||||
if !strings.Contains(tableSql, "repository ") {
|
||||
t.Errorf("Expect column with name repository")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestChangeColumnType(t *testing.T) {
|
||||
defer tearDown()
|
||||
if err := setUp(); err != nil {
|
||||
t.Fatalf("Error preparing database: %q", err)
|
||||
}
|
||||
|
||||
migr := New(db)
|
||||
if err := migr.Add(&revision1{}, &revision4{}, &revision10{}).Migrate(); err != nil {
|
||||
t.Fatalf("Can not migrate: %q", err)
|
||||
}
|
||||
|
||||
var dummy, tableSql, query string
|
||||
switch driver {
|
||||
case "mysql":
|
||||
query = `SHOW CREATE TABLE samples`
|
||||
if err := db.QueryRow(query).Scan(&dummy, &tableSql); err != nil {
|
||||
t.Fatalf("Can not query table's definition: %q", err)
|
||||
}
|
||||
if !strings.Contains(tableSql, "`email` varchar(512)") {
|
||||
t.Errorf("Expect email type to changed: %q", tableSql)
|
||||
}
|
||||
default:
|
||||
query = `SELECT sql FROM sqlite_master where type='table' and name='samples'`
|
||||
if err := db.QueryRow(query).Scan(&tableSql); err != nil {
|
||||
t.Fatalf("Can not query sqlite_master: %q", err)
|
||||
}
|
||||
if !strings.Contains(tableSql, "email varchar(512) UNIQUE") {
|
||||
t.Errorf("Expect email type to changed: %q", tableSql)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
if driver = os.Getenv("DB_ENV"); len(driver) == 0 {
|
||||
driver = "sqlite3"
|
||||
}
|
||||
if dsn = os.Getenv("MYSQL_LOGIN"); len(dsn) == 0 {
|
||||
dsn = ":memory:"
|
||||
} else {
|
||||
dsn = fmt.Sprintf("%s@/?parseTime=true", dsn)
|
||||
}
|
||||
}
|
||||
|
||||
func setUp() error {
|
||||
var err error
|
||||
Driver = SQLite
|
||||
if db, err = sql.Open(driver, dsn); err != nil {
|
||||
log.Fatalf("Can't connect to database: %q", err)
|
||||
}
|
||||
if driver == "mysql" {
|
||||
Driver = MySQL
|
||||
if _, err := db.Exec(fmt.Sprintf("CREATE DATABASE %s", dbname)); err != nil {
|
||||
log.Fatalf("Can't create database: %q", err)
|
||||
}
|
||||
if _, err := db.Exec(fmt.Sprintf("USE %s", dbname)); err != nil {
|
||||
log.Fatalf("Can't use database: %q", dbname)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func tearDown() {
|
||||
if driver == "mysql" {
|
||||
db.Exec(fmt.Sprintf("DROP DATABASE %s", dbname))
|
||||
}
|
||||
db.Close()
|
||||
}
|
||||
|
||||
func loadFixture(t *testing.T) {
|
||||
for _, sql := range dataDump {
|
||||
if _, err := db.Exec(sql); err != nil {
|
||||
t.Fatalf("Can not insert into database: %q", err)
|
||||
}
|
||||
}
|
||||
}
|
246
pkg/database/migrate/testing/revisions.go
Normal file
246
pkg/database/migrate/testing/revisions.go
Normal file
|
@ -0,0 +1,246 @@
|
|||
package migrate
|
||||
|
||||
import (
|
||||
. "github.com/drone/drone/pkg/database/migrate"
|
||||
)
|
||||
|
||||
type Sample struct {
|
||||
ID int64 `meddler:"id,pk"`
|
||||
Imel string `meddler:"imel"`
|
||||
Name string `meddler:"name"`
|
||||
}
|
||||
|
||||
type RenameSample struct {
|
||||
ID int64 `meddler:"id,pk"`
|
||||
Email string `meddler:"email"`
|
||||
Name string `meddler:"name"`
|
||||
}
|
||||
|
||||
type AddColumnSample struct {
|
||||
ID int64 `meddler:"id,pk"`
|
||||
Imel string `meddler:"imel"`
|
||||
Name string `meddler:"name"`
|
||||
Url string `meddler:"url"`
|
||||
Num int64 `meddler:"num"`
|
||||
}
|
||||
|
||||
// ---------- revision 1
|
||||
|
||||
type revision1 struct{}
|
||||
|
||||
func (r *revision1) Up(mg *MigrationDriver) error {
|
||||
_, err := mg.CreateTable("samples", []string{
|
||||
mg.T.Integer("id", PRIMARYKEY, AUTOINCREMENT),
|
||||
mg.T.String("imel", UNIQUE),
|
||||
mg.T.String("name"),
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision1) Down(mg *MigrationDriver) error {
|
||||
_, err := mg.DropTable("samples")
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision1) Revision() int64 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// ---------- end of revision 1
|
||||
|
||||
// ---------- revision 2
|
||||
|
||||
type revision2 struct{}
|
||||
|
||||
func (r *revision2) Up(mg *MigrationDriver) error {
|
||||
_, err := mg.RenameTable("samples", "examples")
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision2) Down(mg *MigrationDriver) error {
|
||||
_, err := mg.RenameTable("examples", "samples")
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision2) Revision() int64 {
|
||||
return 2
|
||||
}
|
||||
|
||||
// ---------- end of revision 2
|
||||
|
||||
// ---------- revision 3
|
||||
|
||||
type revision3 struct{}
|
||||
|
||||
func (r *revision3) Up(mg *MigrationDriver) error {
|
||||
if _, err := mg.AddColumn("samples", "url VARCHAR(255)"); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := mg.AddColumn("samples", "num INTEGER")
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision3) Down(mg *MigrationDriver) error {
|
||||
_, err := mg.DropColumns("samples", "num", "url")
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision3) Revision() int64 {
|
||||
return 3
|
||||
}
|
||||
|
||||
// ---------- end of revision 3
|
||||
|
||||
// ---------- revision 4
|
||||
|
||||
type revision4 struct{}
|
||||
|
||||
func (r *revision4) Up(mg *MigrationDriver) error {
|
||||
_, err := mg.RenameColumns("samples", map[string]string{
|
||||
"imel": "email",
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision4) Down(mg *MigrationDriver) error {
|
||||
_, err := mg.RenameColumns("samples", map[string]string{
|
||||
"email": "imel",
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision4) Revision() int64 {
|
||||
return 4
|
||||
}
|
||||
|
||||
// ---------- end of revision 4
|
||||
|
||||
// ---------- revision 5
|
||||
|
||||
type revision5 struct{}
|
||||
|
||||
func (r *revision5) Up(mg *MigrationDriver) error {
|
||||
_, err := mg.AddIndex("samples", []string{"url", "name"})
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision5) Down(mg *MigrationDriver) error {
|
||||
_, err := mg.DropIndex("samples", []string{"url", "name"})
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision5) Revision() int64 {
|
||||
return 5
|
||||
}
|
||||
|
||||
// ---------- end of revision 5
|
||||
|
||||
// ---------- revision 6
|
||||
type revision6 struct{}
|
||||
|
||||
func (r *revision6) Up(mg *MigrationDriver) error {
|
||||
_, err := mg.RenameColumns("samples", map[string]string{
|
||||
"url": "host",
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision6) Down(mg *MigrationDriver) error {
|
||||
_, err := mg.RenameColumns("samples", map[string]string{
|
||||
"host": "url",
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision6) Revision() int64 {
|
||||
return 6
|
||||
}
|
||||
|
||||
// ---------- end of revision 6
|
||||
|
||||
// ---------- revision 7
|
||||
type revision7 struct{}
|
||||
|
||||
func (r *revision7) Up(mg *MigrationDriver) error {
|
||||
_, err := mg.DropColumns("samples", "host", "num")
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision7) Down(mg *MigrationDriver) error {
|
||||
if _, err := mg.AddColumn("samples", "host VARCHAR(255)"); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := mg.AddColumn("samples", "num INSTEGER")
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision7) Revision() int64 {
|
||||
return 7
|
||||
}
|
||||
|
||||
// ---------- end of revision 7
|
||||
|
||||
// ---------- revision 8
|
||||
type revision8 struct{}
|
||||
|
||||
func (r *revision8) Up(mg *MigrationDriver) error {
|
||||
if _, err := mg.AddColumn("samples", "repo_id INTEGER"); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := mg.AddColumn("samples", "repo VARCHAR(255)")
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision8) Down(mg *MigrationDriver) error {
|
||||
_, err := mg.DropColumns("samples", "repo", "repo_id")
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision8) Revision() int64 {
|
||||
return 8
|
||||
}
|
||||
|
||||
// ---------- end of revision 8
|
||||
|
||||
// ---------- revision 9
|
||||
type revision9 struct{}
|
||||
|
||||
func (r *revision9) Up(mg *MigrationDriver) error {
|
||||
_, err := mg.RenameColumns("samples", map[string]string{
|
||||
"repo": "repository",
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision9) Down(mg *MigrationDriver) error {
|
||||
_, err := mg.RenameColumns("samples", map[string]string{
|
||||
"repository": "repo",
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision9) Revision() int64 {
|
||||
return 9
|
||||
}
|
||||
|
||||
// ---------- end of revision 9
|
||||
|
||||
// ---------- revision 10
|
||||
|
||||
type revision10 struct{}
|
||||
|
||||
func (r *revision10) Revision() int64 {
|
||||
return 10
|
||||
}
|
||||
|
||||
func (r *revision10) Up(mg *MigrationDriver) error {
|
||||
_, err := mg.ChangeColumn("samples", "email", "varchar(512) UNIQUE")
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *revision10) Down(mg *MigrationDriver) error {
|
||||
_, err := mg.ChangeColumn("samples", "email", "varchar(255) unique")
|
||||
return err
|
||||
}
|
||||
|
||||
// ---------- end of revision 10
|
|
@ -63,11 +63,11 @@ func TestGetRepo(t *testing.T) {
|
|||
t.Errorf("Exepected Password %s, got %s", "no password", repo.Password)
|
||||
}
|
||||
|
||||
if repo.PublicKey != "public key" {
|
||||
if repo.PublicKey != pubkey {
|
||||
t.Errorf("Exepected PublicKey %s, got %s", "public key", repo.PublicKey)
|
||||
}
|
||||
|
||||
if repo.PrivateKey != "private key" {
|
||||
if repo.PrivateKey != privkey {
|
||||
t.Errorf("Exepected PrivateKey %s, got %s", "private key", repo.PrivateKey)
|
||||
}
|
||||
|
||||
|
@ -135,11 +135,11 @@ func TestGetRepoSlug(t *testing.T) {
|
|||
t.Errorf("Exepected Password %s, got %s", "no password", repo.Password)
|
||||
}
|
||||
|
||||
if repo.PublicKey != "public key" {
|
||||
if repo.PublicKey != pubkey {
|
||||
t.Errorf("Exepected PublicKey %s, got %s", "public key", repo.PublicKey)
|
||||
}
|
||||
|
||||
if repo.PrivateKey != "private key" {
|
||||
if repo.PrivateKey != privkey {
|
||||
t.Errorf("Exepected PrivateKey %s, got %s", "private key", repo.PrivateKey)
|
||||
}
|
||||
|
||||
|
@ -385,11 +385,11 @@ func TestListReposTeam(t *testing.T) {
|
|||
t.Errorf("Exepected Password %s, got %s", "no password", repo.Password)
|
||||
}
|
||||
|
||||
if repo.PublicKey != "public key" {
|
||||
if repo.PublicKey != pubkey {
|
||||
t.Errorf("Exepected PublicKey %s, got %s", "public key", repo.PublicKey)
|
||||
}
|
||||
|
||||
if repo.PrivateKey != "private key" {
|
||||
if repo.PrivateKey != privkey {
|
||||
t.Errorf("Exepected PrivateKey %s, got %s", "private key", repo.PrivateKey)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,11 @@ package database
|
|||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/drone/drone/pkg/database"
|
||||
"github.com/drone/drone/pkg/database/encrypt"
|
||||
|
@ -12,6 +16,42 @@ import (
|
|||
"github.com/russross/meddler"
|
||||
)
|
||||
|
||||
const (
|
||||
pubkey = `sh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQClp9+xjhYj2Wz0nwLNhUiR1RkqfoVZwlJoxdubQy8GskZtY7C7YGa/PeKfdfaKOWtVgg37r/OYS3kc7bIKVup4sx/oW59FMwCZYQ2nxoaPZpPwUJs8D0Wy0b2VSP+vAnJ6jZQEIEiClrzyYafSfqN6L9T/BTkn28ktWalOHqWVKejKeD6M0uhlpyIZFsQ1K2wNt32ACwT/rbanx/r/jfczqxSkLzvIKXXs/RdKQgwRRUYnKkl4Lh6r22n9n3m2VwRor5wdsPK8sr57OsqdRpnvsFs3lxwM8w5ZiAZV3T0xTMGVs3W8Uy5HexAD6TgWBWFjSrgdXF1pE83wmUtJtVBf`
|
||||
privkey = `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEApaffsY4WI9ls9J8CzYVIkdUZKn6FWcJSaMXbm0MvBrJGbWOw
|
||||
u2Bmvz3in3X2ijlrVYIN+6/zmEt5HO2yClbqeLMf6FufRTMAmWENp8aGj2aT8FCb
|
||||
PA9FstG9lUj/rwJyeo2UBCBIgpa88mGn0n6jei/U/wU5J9vJLVmpTh6llSnoyng+
|
||||
jNLoZaciGRbENStsDbd9gAsE/622p8f6/433M6sUpC87yCl17P0XSkIMEUVGJypJ
|
||||
eC4eq9tp/Z95tlcEaK+cHbDyvLK+ezrKnUaZ77BbN5ccDPMOWYgGVd09MUzBlbN1
|
||||
vFMuR3sQA+k4FgVhY0q4HVxdaRPN8JlLSbVQXwIDAQABAoIBAA3EqSPxwkdSf+rI
|
||||
+IuqY0CzrHbKszylmQHaSAlciSEOWionWf4I4iFM/HPycv5EDXa663yawC1NQJC1
|
||||
9NFFLhHAGYvPaapvtcIJvf/O0UpD5VHY8T4JqupU4mPxAEdEdc1XzRCWulAYRTYE
|
||||
BdXJ7r5uEU7s2TZF3y+kvxyeEXcXNWK1I4kGBSgH4KI5WIODtNJ6vaIk5Yugqt1N
|
||||
cg5Sprk4bUMRTBH6GmSiJUleA0f/k6MCCmhETKXGt9mmfJ1PXpVlfDn5m26MX6vZ
|
||||
XgaoIHUCy4sh1Fq6vbEI831JcO4kdvl4TtX90SzSadHjewNHy0V2gjAysvqbEDhw
|
||||
Hn8D+MkCgYEA00tTKPp3AUTxT9ZgfPBD3DY7tk7+xp2R2lA6H9TUWe79TRfncFtS
|
||||
8bCfEXd8xALL5cFyzi4q4YJ77mJjlWE7AMYdsFoAW1l3Q71JRRBSwsyIwp4hU8AV
|
||||
K48SDjqecDzY42UvuKGp3opPWb0PzJixJNUgawU/ZGPxqN8jlr0o+K0CgYEAyLSO
|
||||
rZqOvyE5wu8yadHLlQC4usoYtnyDC8PG2SgnZnlnZnkgNy3yLmHYvTvYSQsAv7rA
|
||||
fFsKMt2MJhlclx+sTds/LLHKj/RfVDFenFf6ajBNZ1k+KRcwrV1A4iWinWmBxiEi
|
||||
A8aM9rGs7WRBkqaCONSUQHcmLRRz7hqDtsBpkrsCgYBY2FJ2Z6LEmN2zCVx3DHws
|
||||
S22eQeclUroyhwt5uP81daVy1jtN5kihMfgg2xJORTLBQC9q/MSxIDHGUf63oDO0
|
||||
JpnzPlTqFFtu01fMv4ldOa3Dz8QJuDnun/EipIlcfmlgbHq9ctS/q36kKDhNemL6
|
||||
Lte7yHAYYWIK9RC84Hsq3QKBgAfDbC1s6A6ek2Rl6jZLpitKTtryzEfqwwrmdL+b
|
||||
nQKKuaQuFT/tKAwBPuf685/HrCy+ZYmp39gd17j1jC5QTFLqoyPwcJxm4HUaP8We
|
||||
ZZJL8gKIYi4mtnxOOh9FQ2gBV8K5L16kBHnaX40DLsIkbK8UEfP4Z+Kggud34RZl
|
||||
lO/XAoGAFFZdolsVbSieFhJt7ypzp/19dKJ8Sk6QGCk3uQpTuLJMvwcBT8X5XCTD
|
||||
zFfYARarx87mbD2k5GZ7F0fmGYTUV14qlxJCGMythLM/xZ6EJuJWBz69puNj4yhn
|
||||
exWM7t1BDHy2zIoPfIQLDH2h1zNTRjismMeErOCy0Uha7jrZhW8=
|
||||
-----END RSA PRIVATE KEY-----`
|
||||
)
|
||||
|
||||
var (
|
||||
dbname, driver, dsn, login string
|
||||
db *sql.DB
|
||||
)
|
||||
|
||||
func init() {
|
||||
// create a cipher for ecnrypting and decrypting
|
||||
// database fields
|
||||
|
@ -24,11 +64,31 @@ func init() {
|
|||
// decrypt database fields.
|
||||
meddler.Register("gobencrypt", &encrypt.EncryptedField{cipher})
|
||||
|
||||
// Check for $DB_ENV
|
||||
dbenv := os.Getenv("DB_ENV")
|
||||
if dbenv == "mysql" {
|
||||
driver = dbenv
|
||||
dbname = "drone_test"
|
||||
login = os.Getenv("MYSQL_LOGIN")
|
||||
if len(login) == 0 {
|
||||
login = "root"
|
||||
}
|
||||
log.Println("Using mysql database ...")
|
||||
} else {
|
||||
driver = "sqlite3"
|
||||
dsn = ":memory:"
|
||||
log.Println("Using sqlite3 database ...")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Setup() {
|
||||
// create an in-memory database
|
||||
database.Init("sqlite3", ":memory:")
|
||||
if driver == "mysql" {
|
||||
idsn := fmt.Sprintf("%s@/?parseTime=true", login)
|
||||
db, dsn = createDB(dbname, idsn)
|
||||
}
|
||||
database.Init(driver, dsn)
|
||||
|
||||
// create dummy user data
|
||||
user1 := User{
|
||||
|
@ -102,8 +162,8 @@ func Setup() {
|
|||
URL: "git@github.com:drone/drone.git",
|
||||
Username: "no username",
|
||||
Password: "no password",
|
||||
PublicKey: "public key",
|
||||
PrivateKey: "private key",
|
||||
PublicKey: pubkey,
|
||||
PrivateKey: privkey,
|
||||
UserID: user1.ID,
|
||||
TeamID: team1.ID,
|
||||
}
|
||||
|
@ -118,8 +178,8 @@ func Setup() {
|
|||
URL: "https://bitbucket.org/drone/test",
|
||||
Username: "no username",
|
||||
Password: "no password",
|
||||
PublicKey: "public key",
|
||||
PrivateKey: "private key",
|
||||
PublicKey: pubkey,
|
||||
PrivateKey: privkey,
|
||||
UserID: user1.ID,
|
||||
TeamID: team1.ID,
|
||||
}
|
||||
|
@ -134,8 +194,8 @@ func Setup() {
|
|||
URL: "https://bitbucket.org/brydzewski/test",
|
||||
Username: "no username",
|
||||
Password: "no password",
|
||||
PublicKey: "public key",
|
||||
PrivateKey: "private key",
|
||||
PublicKey: pubkey,
|
||||
PrivateKey: privkey,
|
||||
UserID: user2.ID,
|
||||
}
|
||||
|
||||
|
@ -207,4 +267,19 @@ func Setup() {
|
|||
|
||||
func Teardown() {
|
||||
database.Close()
|
||||
if driver == "mysql" {
|
||||
db.Exec(fmt.Sprintf("DROP DATABASE %s", dbname))
|
||||
}
|
||||
}
|
||||
|
||||
func createDB(name, datasource string) (*sql.DB, string) {
|
||||
db, err := sql.Open(driver, datasource)
|
||||
if err != nil {
|
||||
panic("Can't connect to database")
|
||||
}
|
||||
if _, err := db.Exec(fmt.Sprintf("CREATE DATABASE %s", name)); err != nil {
|
||||
panic("Can't create database")
|
||||
}
|
||||
dsn := strings.Replace(datasource, "/", fmt.Sprintf("/%s", name), 1)
|
||||
return db, dsn
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue