gitlab.com/beacon-software/gadget@v0.0.0-20181217202115-54565ea1ed5e/database/setup_test.go (about)

     1  package database
     2  
     3  import (
     4  	"database/sql"
     5  	"fmt"
     6  	"os"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/mattes/migrate"
    11  
    12  	"gitlab.com/beacon-software/gadget/database/qb"
    13  	"gitlab.com/beacon-software/gadget/environment"
    14  	"gitlab.com/beacon-software/gadget/generator"
    15  	"gitlab.com/beacon-software/gadget/log"
    16  )
    17  
    18  type specification struct {
    19  	DatabaseType string
    20  	DatabaseURL  string `env:"TST_DATABASE_URL"`
    21  	DB           *Database
    22  }
    23  
    24  // DatabaseConnection return the connection string for the database
    25  func (spec specification) DatabaseConnection() string {
    26  	return spec.DatabaseURL
    27  }
    28  
    29  // DatabaseDialect returns the dialect (mysql, mongo, etc) for the connection
    30  func (spec specification) DatabaseDialect() string {
    31  	return spec.DatabaseType
    32  }
    33  
    34  // DatabaseDialectURL returns the dialect (mysql, mongo, etc) for the connection
    35  func (spec specification) DatabaseDialectURL() string {
    36  	return fmt.Sprintf("%s://%s", spec.DatabaseType, spec.DatabaseURL)
    37  }
    38  
    39  func newSpecification() *specification {
    40  	config := &specification{
    41  		DatabaseType: "mysql",
    42  	}
    43  	environment.Process(config)
    44  	config.DB = Initialize(config)
    45  	return config
    46  }
    47  
    48  // testMeta defines a table
    49  type testMeta struct {
    50  	alias string
    51  	ID    qb.TableField
    52  	Name  qb.TableField
    53  	Place qb.TableField
    54  
    55  	CreatedOn qb.TableField
    56  	UpdatedOn qb.TableField
    57  }
    58  
    59  func (p *testMeta) GetName() string {
    60  	return "test_record"
    61  }
    62  
    63  func (p *testMeta) GetAlias() string {
    64  	return p.alias
    65  }
    66  
    67  func (p *testMeta) PrimaryKey() qb.TableField {
    68  	return p.ID
    69  }
    70  
    71  func (p *testMeta) AllColumns() qb.TableField {
    72  	return qb.TableField{Table: p.GetName(), Name: "*"}
    73  }
    74  
    75  func (p *testMeta) SortBy() (qb.TableField, qb.OrderDirection) {
    76  	return p.CreatedOn, qb.Ascending
    77  }
    78  
    79  func (p *testMeta) ReadColumns() []qb.TableField {
    80  	return []qb.TableField{
    81  		p.ID,
    82  		p.Name,
    83  		p.Place,
    84  		p.CreatedOn,
    85  		p.UpdatedOn,
    86  	}
    87  }
    88  
    89  func (p *testMeta) WriteColumns() []qb.TableField {
    90  	return []qb.TableField{
    91  		p.Name,
    92  		p.Place,
    93  	}
    94  }
    95  
    96  func (p *testMeta) Alias(alias string) *testMeta {
    97  	return &testMeta{
    98  		alias: alias,
    99  		ID:    qb.TableField{Name: "id", Table: alias},
   100  		Name:  qb.TableField{Name: "name", Table: alias},
   101  		Place: qb.TableField{Name: "place", Table: alias},
   102  
   103  		CreatedOn: qb.TableField{Name: "created_on", Table: alias},
   104  		UpdatedOn: qb.TableField{Name: "updated_on", Table: alias},
   105  	}
   106  }
   107  
   108  var TestMeta = (&testMeta{}).Alias("test_record")
   109  
   110  type TestRecord struct {
   111  	DefaultRecord
   112  	ID        string         `db:"id,read_only"`
   113  	Name      string         `db:"name"`
   114  	Place     sql.NullString `db:"place"`
   115  	CreatedOn time.Time      `db:"created_on,read_only"`
   116  	UpdatedOn time.Time      `db:"updated_on,read_only"`
   117  	Skip      string
   118  }
   119  
   120  func (record *TestRecord) Initialize() {
   121  	record.ID = generator.ID("tst")
   122  }
   123  
   124  func (record *TestRecord) PrimaryKey() PrimaryKeyValue {
   125  	return NewPrimaryKey(record.ID)
   126  }
   127  
   128  func (record *TestRecord) Meta() qb.Table {
   129  	return TestMeta
   130  }
   131  
   132  // detailsTestMeta defines a table
   133  type detailsTestMeta struct {
   134  	alias string
   135  	ID    qb.TableField
   136  	Name  qb.TableField
   137  }
   138  
   139  func (p *detailsTestMeta) GetName() string {
   140  	return "details_test_record"
   141  }
   142  
   143  func (p *detailsTestMeta) GetAlias() string {
   144  	return p.alias
   145  }
   146  
   147  func (p *detailsTestMeta) PrimaryKey() qb.TableField {
   148  	return p.ID
   149  }
   150  
   151  func (p *detailsTestMeta) AllColumns() qb.TableField {
   152  	return qb.TableField{Table: p.GetName(), Name: "*"}
   153  }
   154  
   155  func (p *detailsTestMeta) SortBy() (qb.TableField, qb.OrderDirection) {
   156  	return p.ID, qb.Ascending
   157  }
   158  
   159  func (p *detailsTestMeta) ReadColumns() []qb.TableField {
   160  	return p.WriteColumns()
   161  }
   162  
   163  func (p *detailsTestMeta) WriteColumns() []qb.TableField {
   164  	return []qb.TableField{
   165  		p.ID,
   166  		p.Name,
   167  	}
   168  }
   169  
   170  func (p *detailsTestMeta) Alias(alias string) *detailsTestMeta {
   171  	return &detailsTestMeta{
   172  		alias: alias,
   173  		ID:    qb.TableField{Name: "id", Table: alias},
   174  		Name:  qb.TableField{Name: "name", Table: alias},
   175  	}
   176  }
   177  
   178  var DetailsTestMeta = (&detailsTestMeta{}).Alias("details_test_record")
   179  
   180  type DetailsTestRecord struct {
   181  	ID   string `db:"id,nonsense"`
   182  	Name string `db:"name"`
   183  }
   184  
   185  func (record DetailsTestRecord) Meta() qb.Table {
   186  	return DetailsTestMeta
   187  }
   188  
   189  func (record DetailsTestRecord) Initialize() {
   190  }
   191  
   192  func (record DetailsTestRecord) Key() string {
   193  	return "name"
   194  }
   195  
   196  func (record DetailsTestRecord) PrimaryKey() PrimaryKeyValue {
   197  	return NewPrimaryKey(record.ID)
   198  }
   199  
   200  // testDuperMeta defines a table
   201  type testDuperMeta struct {
   202  	alias string
   203  	ID    qb.TableField
   204  }
   205  
   206  func (p *testDuperMeta) GetName() string {
   207  	return "test_duper"
   208  }
   209  
   210  func (p *testDuperMeta) GetAlias() string {
   211  	return p.alias
   212  }
   213  
   214  func (p *testDuperMeta) PrimaryKey() qb.TableField {
   215  	return p.ID
   216  }
   217  
   218  func (p *testDuperMeta) AllColumns() qb.TableField {
   219  	return qb.TableField{Table: p.GetName(), Name: "*"}
   220  }
   221  
   222  func (p *testDuperMeta) SortBy() (qb.TableField, qb.OrderDirection) {
   223  	return p.ID, qb.Ascending
   224  }
   225  
   226  func (p *testDuperMeta) ReadColumns() []qb.TableField {
   227  	return p.WriteColumns()
   228  }
   229  
   230  func (p *testDuperMeta) WriteColumns() []qb.TableField {
   231  	return []qb.TableField{p.ID}
   232  }
   233  
   234  func (p *testDuperMeta) Alias(alias string) *testDuperMeta {
   235  	return &testDuperMeta{
   236  		alias: alias,
   237  		ID:    qb.TableField{Name: "id", Table: alias},
   238  	}
   239  }
   240  
   241  var TestDuperMeta = (&testDuperMeta{}).Alias("test_duper")
   242  
   243  type TestDuper struct {
   244  	ID         string `db:"id"`
   245  	intializer func() string
   246  }
   247  
   248  func (record *TestDuper) Meta() qb.Table {
   249  	return TestDuperMeta
   250  }
   251  
   252  func (record *TestDuper) Initialize() {
   253  	log.Debugf("\n\nInitializing: %s", record.ID)
   254  	record.ID = record.intializer()
   255  	log.Debugf("Initialized: %s\n\n", record.ID)
   256  
   257  }
   258  
   259  func (record *TestDuper) Key() string {
   260  	return "id"
   261  }
   262  
   263  func (record *TestDuper) PrimaryKey() PrimaryKeyValue {
   264  	return NewPrimaryKey(record.ID)
   265  }
   266  
   267  func initialize() string {
   268  	return generator.ID("dup")
   269  }
   270  
   271  func NewTestDuper() *TestDuper {
   272  	return &TestDuper{
   273  		intializer: initialize,
   274  	}
   275  }
   276  
   277  func rollback(migrations map[string]string, dbURL string) {
   278  	sqlFilesPath, _ := generateSQLFiles(migrations)
   279  	m, err := migrate.New(sqlFilesPath, dbURL)
   280  	if err != nil {
   281  		msg := fmt.Sprintf("couldn't load migration scripts from %s (%s)", sqlFilesPath, err)
   282  		log.Fatalf(msg)
   283  		panic(msg)
   284  	}
   285  	defer m.Close()
   286  
   287  	// Migrate all the way down ...
   288  	if err := m.Down(); err != nil {
   289  		msg := fmt.Sprintf("Rollback ERROR: %#v", err)
   290  		log.Fatalf(msg)
   291  		panic(msg)
   292  	}
   293  }
   294  
   295  func TestMain(m *testing.M) {
   296  	config := newSpecification()
   297  	migrations := make(map[string]string)
   298  	migrations["0001_.up.sql"] = `CREATE TABLE IF NOT EXISTS test_record (
   299  			id varchar(128) primary key,
   300  			name varchar(128) not null unique,
   301  			place varchar(128) null,
   302  			created_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
   303  			updated_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
   304  		);
   305  		CREATE TABLE IF NOT EXISTS test_duper (
   306  			id varchar(128) primary key
   307  		);
   308  `
   309  	migrations["0001_foo.down.sql"] = `DROP TABLE IF EXISTS test_record;
   310  	DROP TABLE IF EXISTS test_duper;
   311  `
   312  	Migrate(migrations, config.DatabaseDialectURL())
   313  
   314  	res := m.Run()
   315  	Reset(migrations, config.DatabaseDialectURL())
   316  
   317  	os.Exit(res)
   318  }