Unit tests for token and update models

This commit is contained in:
Ethan Koenig
2016-12-28 20:03:40 -05:00
committed by Kim "BKC" Carlbäcker
parent c0904f1942
commit de8b73dd92
41 changed files with 11919 additions and 0 deletions

21
vendor/gopkg.in/testfixtures.v2/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Andrey Nering
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

323
vendor/gopkg.in/testfixtures.v2/README.md generated vendored Normal file
View File

@@ -0,0 +1,323 @@
# Go Test Fixtures
[![license](https://img.shields.io/github/license/mashape/apistatus.svg?maxAge=2592000)](https://github.com/go-testfixtures/testfixtures/blob/master/LICENSE)
[![Join the chat at https://gitter.im/go-testfixtures/testfixtures](https://badges.gitter.im/go-testfixtures/testfixtures.svg)](https://gitter.im/go-testfixtures/testfixtures?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![GoDoc](https://godoc.org/gopkg.in/testfixtures.v1?status.svg)](https://godoc.org/gopkg.in/testfixtures.v1)
[![Build Status](https://travis-ci.org/go-testfixtures/testfixtures.svg?branch=master)](https://travis-ci.org/go-testfixtures/testfixtures)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-testfixtures/testfixtures)](https://goreportcard.com/report/github.com/go-testfixtures/testfixtures)
> ***Warning***: this package will wipe the database data before loading the
fixtures! It is supposed to be used on a test database. Please, double check
if you are running it against the correct database.
Writing tests is hard, even more when you have to deal with an SQL database.
This package aims to make writing functional tests for web apps written in
Go easier.
Basically this package mimics the ["Rails' way"][railstests] of writing tests
for database applications, where sample data is kept in fixtures files. Before
the execution of every test, the test database is cleaned and the fixture data
is loaded into the database.
The idea is running tests against a real database, instead of relying in mocks,
which is boring to setup and may lead to production bugs not to being catch in
the tests.
## Installation
First, get it:
```bash
go get -u gopkg.in/testfixtures.v2
```
## Usage
Create a folder for the fixture files. Each file should contain data for a
single table and have the name `<table-name>.yml`:
```yml
myapp
- myapp.go
- myapp_test.go
- ...
- fixtures:
- posts.yml
- comments.yml
- tags.yml
- posts_tags.yml
- ...
```
The file would look like this (it can have as many record you want):
```yml
# comments.yml
-
id: 1
post_id: 1
content: This post is awesome!
author_name: John Doe
author_email: john@doe.com
created_at: 2016-01-01 12:30:12
updated_at: 2016-01-01 12:30:12
-
id: 2
post_id: 2
content: Are you kidding me?
author_name: John Doe
author_email: john@doe.com
created_at: 2016-01-01 12:30:12
updated_at: 2016-01-01 12:30:12
# ...
```
Your tests would look like this:
```go
package myapp
import (
"database/sql"
"log"
_ "github.com/lib/pq"
"gopkg.in/testfixtures.v2"
)
var (
db *sql.DB
fixtures *testfixtures.Context
)
func TestMain(m *testing.M) {
var err error
// Open connection with the test database.
// Do NOT import fixtures in a production database!
// Existing data would be deleted
db, err = sql.Open("postgres", "dbname=myapp_test")
if err != nil {
log.Fatal(err)
}
// creating the context that hold the fixtures
// see about all compatible databases in this page below
c, err = testfixtures.NewFolder(db, &testfixtures.PostgreSQL{}, "testdata/fixtures")
if err != nil {
log.Fatal(err)
}
os.Exit(m.Run())
}
func prepareTestDatabase() {
if err := fixtures.Load(); err != nil {
log.Fatal(err)
}
}
func TestX(t *testing.T) {
prepareTestDatabase()
// your test here ...
}
func TestY(t *testing.T) {
prepareTestDatabase()
// your test here ...
}
func TestZ(t *testing.T) {
prepareTestDatabase()
// your test here ...
}
```
Alternatively, you can use the `NewFiles` function, to specify which
files you want to load into the database:
```go
fixtures, err := testfixtures.NewFiles(db, &testfixtures.PostgreSQL{},
"fixtures/orders.yml",
"fixtures/customers.yml",
// add as many files you want
)
if err != nil {
log.Fatal(err)
}
```
## Security check
In order to prevent you from accidentally wiping the wrong database, this
package will refuse to load fixtures if the database name (or database
filename for SQLite) doesn't contains "test". If you want to disable this
check, use:
```go
testfixtures.SkipDatabaseNameCheck(true)
```
## Sequences
For PostgreSQL or Oracle, this package also resets all sequences to a high
number to prevent duplicated primary keys while running the tests.
The default is 10000, but you can change that with:
```go
testfixtures.ResetSequencesTo(10000)
```
## Compatible databases
### PostgreSQL
This package has two approaches to disable foreign keys while importing fixtures
in PostgreSQL databases:
#### With `DISABLE TRIGGER`
This is the default approach. For that use:
```go
&testfixtures.PostgreSQL{}
```
With the above snippet this package will use `DISABLE TRIGGER` to temporarily
disabling foreign key constraints while loading fixtures. This work with any
version of PostgreSQL, but it is **required** to be connected in the database
as a SUPERUSER. You can make a PostgreSQL user a SUPERUSER with:
```sql
ALTER USER your_user SUPERUSER;
```
#### With `ALTER CONSTRAINT`
This approach don't require to be connected as a SUPERUSER, but only work with
PostgreSQL versions >= 9.4. Try this if you are getting foreign key violation
errors with the previous approach. It is as simple as using:
```go
&testfixtures.PostgreSQL{UseAlterConstraint: true}
```
### MySQL
Just make sure the connection string have
[the multistatement parameter](https://github.com/go-sql-driver/mysql#multistatements)
set to true, and use:
```go
&testfixtures.MySQL{}
```
### SQLite
SQLite is also supported. It is recommended to create foreign keys as
`DEFERRABLE` (the default) to prevent problems. See more
[on the SQLite documentation](https://www.sqlite.org/foreignkeys.html#fk_deferred).
(Foreign key constraints are no-op by default on SQLite, but enabling it is
recommended).
```go
&testfixtures.SQLite{}
```
### Microsoft SQL Server
SQL Server support requires SQL Server >= 2008. Inserting on `IDENTITY` columns
are handled as well. Just make sure you are logged in with a user with
`ALTER TABLE` permission.
```go
&testfixtures.SQLServer{}
```
### Oracle
Oracle is supported as well. Use:
```go
&testfixtures.Oracle{}
```
## Contributing
Tests were written to ensure everything work as expected. You can run the tests
with:
```bash
# running tests for PostgreSQL
go test -tags postgresql
# running test for MySQL
go test -tags mysql
# running tests for SQLite
go test -tags sqlite
# running tests for SQL Server
go test -tags sqlserver
# running tests for Oracle
go test -tags oracle
# running test for multiple databases at once
go test -tags 'sqlite postgresql mysql'
# running tests + benchmark
go test -v -bench=. -tags postgresql
```
Travis runs tests for PostgreSQL, MySQL and SQLite.
To set the connection string of tests for each database, edit the `.env`
file, but do not include the changes a in pull request.
## Changes in v2
A context was created to allow cache of some SQL statements. See in the
documentation above how to use it.
The helpers were renamed to have a smaller name:
```go
PostgreSQLHelper{} -> PostgreSQL{}
MySQLHelper{} -> MySQL{}
SQLiteHelper{} -> SQLite{}
SQLServerHelper{} -> SQLServer{}
OracleHelper{} -> Oracle{}
```
The old functions and helpers are still available for backward compatibility.
See the file [deprecated.go](https://github.com/go-testfixtures/testfixtures/blob/master/LICENSE)
## Alternatives
If you don't think using fixtures is a good idea, you can try one of these
packages instead:
- [factory-go][factorygo]: Factory for Go. Inspired by Python's Factory Boy
and Ruby's Factory Girl
- [go-txdb (Single transaction SQL driver for Go)][gotxdb]: Use a single
database transaction for each functional test, so you can rollback to
previous state between tests to have the same database state in all tests
- [go-sqlmock][gosqlmock]: A mock for the sql.DB interface. This allow you to unit
test database code without having to connect to a real database
There's also these other implementations of test fixtures for Go:
- [go-fixtures][gofixtures]: Django style fixtures for Go
- [mongofixtures][mongofixtures]: Fixtures for MongoDB
- [fixturer][fixturer]: Another fixture loader supporting MySQL
[railstests]: http://guides.rubyonrails.org/testing.html#the-test-database
[gotxdb]: https://github.com/DATA-DOG/go-txdb
[gosqlmock]: https://github.com/DATA-DOG/go-sqlmock
[gofixtures]: https://github.com/AreaHQ/go-fixtures
[mongofixtures]: https://github.com/OwlyCode/mongofixtures
[fixturer]: https://github.com/44hapa/fixturer
[factorygo]: https://github.com/bluele/factory-go

59
vendor/gopkg.in/testfixtures.v2/deprecated.go generated vendored Normal file
View File

@@ -0,0 +1,59 @@
package testfixtures
import (
"database/sql"
)
type (
DataBaseHelper Helper // Deprecated: Use Helper instead
PostgreSQLHelper struct { // Deprecated: Use PostgreSQL{} instead
PostgreSQL
UseAlterConstraint bool
}
MySQLHelper struct { // Deprecated: Use MySQL{} instead
MySQL
}
SQLiteHelper struct { // Deprecated: Use SQLite{} instead
SQLite
}
SQLServerHelper struct { // Deprecated: Use SQLServer{} instead
SQLServer
}
OracleHelper struct { // Deprecated: Use Oracle{} instead
Oracle
}
)
func (h *PostgreSQLHelper) disableReferentialIntegrity(db *sql.DB, loadFn loadFunction) error {
h.PostgreSQL.UseAlterConstraint = h.UseAlterConstraint
return h.PostgreSQL.disableReferentialIntegrity(db, loadFn)
}
// LoadFixtureFiles load all specified fixtures files into database:
// LoadFixtureFiles(db, &PostgreSQL{},
// "fixtures/customers.yml", "fixtures/orders.yml")
// // add as many files you want
//
// Deprecated: Use NewFiles() and Load() instead.
func LoadFixtureFiles(db *sql.DB, helper Helper, files ...string) error {
c, err := NewFiles(db, helper, files...)
if err != nil {
return err
}
return c.Load()
}
// LoadFixtures loads all fixtures in a given folder into the database:
// LoadFixtures("myfixturesfolder", db, &PostgreSQL{})
//
// Deprecated: Use NewFolder() and Load() instead.
func LoadFixtures(folderName string, db *sql.DB, helper Helper) error {
c, err := NewFolder(db, helper, folderName)
if err != nil {
return err
}
return c.Load()
}

38
vendor/gopkg.in/testfixtures.v2/helper.go generated vendored Normal file
View File

@@ -0,0 +1,38 @@
package testfixtures
import (
"database/sql"
"fmt"
)
const (
paramTypeDollar = iota + 1
paramTypeQuestion
paramTypeColon
)
type loadFunction func(tx *sql.Tx) error
// Helper is the generic interface for the database helper
type Helper interface {
init(*sql.DB) error
disableReferentialIntegrity(*sql.DB, loadFunction) error
paramType() int
databaseName(*sql.DB) string
quoteKeyword(string) string
whileInsertOnTable(*sql.Tx, string, func() error) error
}
type baseHelper struct{}
func (*baseHelper) init(_ *sql.DB) error {
return nil
}
func (*baseHelper) quoteKeyword(str string) string {
return fmt.Sprintf(`"%s"`, str)
}
func (*baseHelper) whileInsertOnTable(_ *sql.Tx, _ string, fn func() error) error {
return fn()
}

45
vendor/gopkg.in/testfixtures.v2/mysql.go generated vendored Normal file
View File

@@ -0,0 +1,45 @@
package testfixtures
import (
"database/sql"
"fmt"
)
// MySQL is the MySQL helper for this package
type MySQL struct {
baseHelper
}
func (*MySQL) paramType() int {
return paramTypeQuestion
}
func (*MySQL) quoteKeyword(str string) string {
return fmt.Sprintf("`%s`", str)
}
func (*MySQL) databaseName(db *sql.DB) (dbName string) {
db.QueryRow("SELECT DATABASE()").Scan(&dbName)
return
}
func (h *MySQL) disableReferentialIntegrity(db *sql.DB, loadFn loadFunction) error {
// re-enable after load
defer db.Exec("SET FOREIGN_KEY_CHECKS = 1")
tx, err := db.Begin()
if err != nil {
return err
}
if _, err = tx.Exec("SET FOREIGN_KEY_CHECKS = 0"); err != nil {
return err
}
if err = loadFn(tx); err != nil {
tx.Rollback()
return err
}
return tx.Commit()
}

19
vendor/gopkg.in/testfixtures.v2/options.go generated vendored Normal file
View File

@@ -0,0 +1,19 @@
package testfixtures
var (
skipDatabaseNameCheck bool
resetSequencesTo int64 = 10000
)
// SkipDatabaseNameCheck If true, loading fixtures will not check if the database
// name constaint "test". Use with caution!
func SkipDatabaseNameCheck(value bool) {
skipDatabaseNameCheck = value
}
// ResetSequencesTo sets the value the sequences will be reset to.
// This is used by PostgreSQL and Oracle.
// Defaults to 10000.
func ResetSequencesTo(value int64) {
resetSequencesTo = value
}

132
vendor/gopkg.in/testfixtures.v2/oracle.go generated vendored Normal file
View File

@@ -0,0 +1,132 @@
package testfixtures
import (
"database/sql"
"fmt"
"strings"
)
// Oracle is the Oracle database helper for this package
type Oracle struct {
baseHelper
enabledConstraints []oracleConstraint
sequences []string
}
type oracleConstraint struct {
tableName string
constraintName string
}
func (h *Oracle) init(db *sql.DB) error {
var err error
h.enabledConstraints, err = h.getEnabledConstraints(db)
if err != nil {
return err
}
h.sequences, err = h.getSequences(db)
if err != nil {
return err
}
return nil
}
func (*Oracle) paramType() int {
return paramTypeColon
}
func (*Oracle) quoteKeyword(str string) string {
return fmt.Sprintf("\"%s\"", strings.ToUpper(str))
}
func (*Oracle) databaseName(db *sql.DB) (dbName string) {
db.QueryRow("SELECT user FROM DUAL").Scan(&dbName)
return
}
func (*Oracle) getEnabledConstraints(db *sql.DB) ([]oracleConstraint, error) {
constraints := make([]oracleConstraint, 0)
rows, err := db.Query(`
SELECT table_name, constraint_name
FROM user_constraints
WHERE constraint_type = 'R'
AND status = 'ENABLED'
`)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var constraint oracleConstraint
rows.Scan(&constraint.tableName, &constraint.constraintName)
constraints = append(constraints, constraint)
}
return constraints, nil
}
func (*Oracle) getSequences(db *sql.DB) ([]string, error) {
sequences := make([]string, 0)
rows, err := db.Query("SELECT sequence_name FROM user_sequences")
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var sequence string
rows.Scan(&sequence)
sequences = append(sequences, sequence)
}
return sequences, nil
}
func (h *Oracle) resetSequences(db *sql.DB) error {
for _, sequence := range h.sequences {
_, err := db.Exec(fmt.Sprintf("DROP SEQUENCE %s", h.quoteKeyword(sequence)))
if err != nil {
return err
}
_, err = db.Exec(fmt.Sprintf("CREATE SEQUENCE %s START WITH %d", h.quoteKeyword(sequence), resetSequencesTo))
if err != nil {
return err
}
}
return nil
}
func (h *Oracle) disableReferentialIntegrity(db *sql.DB, loadFn loadFunction) error {
// re-enable after load
defer func() {
for _, c := range h.enabledConstraints {
db.Exec(fmt.Sprintf("ALTER TABLE %s ENABLE CONSTRAINT %s", h.quoteKeyword(c.tableName), h.quoteKeyword(c.constraintName)))
}
}()
// disable foreign keys
for _, c := range h.enabledConstraints {
_, err := db.Exec(fmt.Sprintf("ALTER TABLE %s DISABLE CONSTRAINT %s", h.quoteKeyword(c.tableName), h.quoteKeyword(c.constraintName)))
if err != nil {
return err
}
}
tx, err := db.Begin()
if err != nil {
return err
}
if err = loadFn(tx); err != nil {
tx.Rollback()
return err
}
if err = tx.Commit(); err != nil {
return err
}
return h.resetSequences(db)
}

211
vendor/gopkg.in/testfixtures.v2/postgresql.go generated vendored Normal file
View File

@@ -0,0 +1,211 @@
package testfixtures
import (
"database/sql"
"fmt"
)
// PostgreSQL is the PG helper for this package
type PostgreSQL struct {
baseHelper
// UseAlterConstraint If true, the contraint disabling will do
// using ALTER CONTRAINT sintax, only allowed in PG >= 9.4.
// If false, the constraint disabling will use DISABLE TRIGGER ALL,
// which requires SUPERUSER privileges.
UseAlterConstraint bool
tables []string
sequences []string
nonDeferrableConstraints []pgConstraint
}
type pgConstraint struct {
tableName string
constraintName string
}
func (h *PostgreSQL) init(db *sql.DB) error {
var err error
h.tables, err = h.getTables(db)
if err != nil {
return err
}
h.sequences, err = h.getSequences(db)
if err != nil {
return err
}
h.nonDeferrableConstraints, err = h.getNonDeferrableConstraints(db)
if err != nil {
return err
}
return nil
}
func (*PostgreSQL) paramType() int {
return paramTypeDollar
}
func (*PostgreSQL) databaseName(db *sql.DB) (dbName string) {
db.QueryRow("SELECT current_database()").Scan(&dbName)
return
}
func (h *PostgreSQL) getTables(db *sql.DB) ([]string, error) {
var tables []string
sql := `
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public'
AND table_type = 'BASE TABLE';
`
rows, err := db.Query(sql)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var table string
rows.Scan(&table)
tables = append(tables, table)
}
return tables, nil
}
func (h *PostgreSQL) getSequences(db *sql.DB) ([]string, error) {
var sequences []string
sql := "SELECT relname FROM pg_class WHERE relkind = 'S'"
rows, err := db.Query(sql)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var sequence string
if err = rows.Scan(&sequence); err != nil {
return nil, err
}
sequences = append(sequences, sequence)
}
return sequences, nil
}
func (*PostgreSQL) getNonDeferrableConstraints(db *sql.DB) ([]pgConstraint, error) {
var constraints []pgConstraint
sql := `
SELECT table_name, constraint_name
FROM information_schema.table_constraints
WHERE constraint_type = 'FOREIGN KEY'
AND is_deferrable = 'NO'`
rows, err := db.Query(sql)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var constraint pgConstraint
err = rows.Scan(&constraint.tableName, &constraint.constraintName)
if err != nil {
return nil, err
}
constraints = append(constraints, constraint)
}
return constraints, nil
}
func (h *PostgreSQL) disableTriggers(db *sql.DB, loadFn loadFunction) error {
defer func() {
// re-enable triggers after load
var sql string
for _, table := range h.tables {
sql += fmt.Sprintf("ALTER TABLE %s ENABLE TRIGGER ALL;", h.quoteKeyword(table))
}
db.Exec(sql)
}()
tx, err := db.Begin()
if err != nil {
return err
}
var sql string
for _, table := range h.tables {
sql += fmt.Sprintf("ALTER TABLE %s DISABLE TRIGGER ALL;", h.quoteKeyword(table))
}
if _, err = tx.Exec(sql); err != nil {
return err
}
if err = loadFn(tx); err != nil {
tx.Rollback()
return err
}
return tx.Commit()
}
func (h *PostgreSQL) makeConstraintsDeferrable(db *sql.DB, loadFn loadFunction) error {
defer func() {
// ensure constraint being not deferrable again after load
var sql string
for _, constraint := range h.nonDeferrableConstraints {
sql += fmt.Sprintf("ALTER TABLE %s ALTER CONSTRAINT %s NOT DEFERRABLE;", h.quoteKeyword(constraint.tableName), h.quoteKeyword(constraint.constraintName))
}
db.Exec(sql)
}()
var sql string
for _, constraint := range h.nonDeferrableConstraints {
sql += fmt.Sprintf("ALTER TABLE %s ALTER CONSTRAINT %s DEFERRABLE;", h.quoteKeyword(constraint.tableName), h.quoteKeyword(constraint.constraintName))
}
if _, err := db.Exec(sql); err != nil {
return err
}
tx, err := db.Begin()
if err != nil {
return err
}
if _, err = tx.Exec("SET CONSTRAINTS ALL DEFERRED"); err != nil {
return nil
}
if err = loadFn(tx); err != nil {
tx.Rollback()
return err
}
return tx.Commit()
}
func (h *PostgreSQL) disableReferentialIntegrity(db *sql.DB, loadFn loadFunction) error {
// ensure sequences being reset after load
defer h.resetSequences(db)
if h.UseAlterConstraint {
return h.makeConstraintsDeferrable(db, loadFn)
} else {
return h.disableTriggers(db, loadFn)
}
}
func (h *PostgreSQL) resetSequences(db *sql.DB) error {
for _, sequence := range h.sequences {
_, err := db.Exec(fmt.Sprintf("SELECT SETVAL('%s', %d)", sequence, resetSequencesTo))
if err != nil {
return err
}
}
return nil
}

40
vendor/gopkg.in/testfixtures.v2/sqlite.go generated vendored Normal file
View File

@@ -0,0 +1,40 @@
package testfixtures
import (
"database/sql"
"path/filepath"
)
// SQLite is the SQLite Helper for this package
type SQLite struct {
baseHelper
}
func (*SQLite) paramType() int {
return paramTypeQuestion
}
func (*SQLite) databaseName(db *sql.DB) (dbName string) {
var seq int
var main string
db.QueryRow("PRAGMA database_list").Scan(&seq, &main, &dbName)
dbName = filepath.Base(dbName)
return
}
func (*SQLite) disableReferentialIntegrity(db *sql.DB, loadFn loadFunction) error {
tx, err := db.Begin()
if err != nil {
return err
}
if _, err = tx.Exec("PRAGMA defer_foreign_keys = ON"); err != nil {
return err
}
if err = loadFn(tx); err != nil {
return err
}
return tx.Commit()
}

110
vendor/gopkg.in/testfixtures.v2/sqlserver.go generated vendored Normal file
View File

@@ -0,0 +1,110 @@
package testfixtures
import (
"database/sql"
"fmt"
)
// SQLServer is the helper for SQL Server for this package.
// SQL Server >= 2008 is required.
type SQLServer struct {
baseHelper
tables []string
}
func (h *SQLServer) init(db *sql.DB) error {
var err error
h.tables, err = h.getTables(db)
if err != nil {
return err
}
return nil
}
func (*SQLServer) paramType() int {
return paramTypeQuestion
}
func (*SQLServer) quoteKeyword(str string) string {
return fmt.Sprintf("[%s]", str)
}
func (*SQLServer) databaseName(db *sql.DB) (dbname string) {
db.QueryRow("SELECT DB_NAME()").Scan(&dbname)
return
}
func (*SQLServer) getTables(db *sql.DB) ([]string, error) {
rows, err := db.Query("SELECT table_name FROM information_schema.tables")
if err != nil {
return nil, err
}
tables := make([]string, 0)
defer rows.Close()
for rows.Next() {
var table string
rows.Scan(&table)
tables = append(tables, table)
}
return tables, nil
}
func (*SQLServer) tableHasIdentityColumn(tx *sql.Tx, tableName string) bool {
sql := `
SELECT COUNT(*)
FROM SYS.IDENTITY_COLUMNS
WHERE OBJECT_NAME(OBJECT_ID) = ?
`
var count int
tx.QueryRow(sql, tableName).Scan(&count)
return count > 0
}
func (h *SQLServer) whileInsertOnTable(tx *sql.Tx, tableName string, fn func() error) error {
if h.tableHasIdentityColumn(tx, tableName) {
defer tx.Exec(fmt.Sprintf("SET IDENTITY_INSERT %s OFF", h.quoteKeyword(tableName)))
_, err := tx.Exec(fmt.Sprintf("SET IDENTITY_INSERT %s ON", h.quoteKeyword(tableName)))
if err != nil {
return err
}
}
return fn()
}
func (h *SQLServer) disableReferentialIntegrity(db *sql.DB, loadFn loadFunction) error {
// ensure the triggers are re-enable after all
defer func() {
sql := ""
for _, table := range h.tables {
sql += fmt.Sprintf("ALTER TABLE %s WITH CHECK CHECK CONSTRAINT ALL;", h.quoteKeyword(table))
}
if _, err := db.Exec(sql); err != nil {
fmt.Printf("Error on re-enabling constraints: %v\n", err)
}
}()
sql := ""
for _, table := range h.tables {
sql += fmt.Sprintf("ALTER TABLE %s NOCHECK CONSTRAINT ALL;", h.quoteKeyword(table))
}
if _, err := db.Exec(sql); err != nil {
return err
}
tx, err := db.Begin()
if err != nil {
return err
}
if err = loadFn(tx); err != nil {
tx.Rollback()
return err
}
return tx.Commit()
}

279
vendor/gopkg.in/testfixtures.v2/testfixtures.go generated vendored Normal file
View File

@@ -0,0 +1,279 @@
package testfixtures
import (
"database/sql"
"errors"
"fmt"
"io/ioutil"
"path"
"path/filepath"
"regexp"
"strings"
"gopkg.in/yaml.v2"
)
// Context holds the fixtures to be loaded in the database.
type Context struct {
db *sql.DB
helper Helper
fixturesFiles []*fixtureFile
}
type fixtureFile struct {
path string
fileName string
content []byte
insertSQLs []insertSQL
}
type insertSQL struct {
sql string
params []interface{}
}
var (
// ErrWrongCastNotAMap is returned when a map is not a map[interface{}]interface{}
ErrWrongCastNotAMap = errors.New("Could not cast record: not a map[interface{}]interface{}")
// ErrFileIsNotSliceOrMap is returned the the fixture file is not a slice or map.
ErrFileIsNotSliceOrMap = errors.New("The fixture file is not a slice or map")
// ErrKeyIsNotString is returned when a record is not of type string
ErrKeyIsNotString = errors.New("Record map key is not string")
// ErrNotTestDatabase is returned when the database name doesn't contains "test"
ErrNotTestDatabase = errors.New(`Loading aborted because the database name does not contains "test"`)
dbnameRegexp = regexp.MustCompile("(?i)test")
)
// NewFolder craetes a context for all fixtures in a given folder into the database:
// NewFolder(db, &PostgreSQL{}, "my/fixtures/folder")
func NewFolder(db *sql.DB, helper Helper, folderName string) (*Context, error) {
fixtures, err := fixturesFromFolder(folderName)
if err != nil {
return nil, err
}
c, err := newContext(db, helper, fixtures)
if err != nil {
return nil, err
}
return c, nil
}
// NewFiles craetes a context for all specified fixtures files into database:
// NewFiles(db, &PostgreSQL{},
// "fixtures/customers.yml",
// "fixtures/orders.yml"
// // add as many files you want
// )
func NewFiles(db *sql.DB, helper Helper, fileNames ...string) (*Context, error) {
fixtures, err := fixturesFromFiles(fileNames...)
if err != nil {
return nil, err
}
c, err := newContext(db, helper, fixtures)
if err != nil {
return nil, err
}
return c, nil
}
func newContext(db *sql.DB, helper Helper, fixtures []*fixtureFile) (*Context, error) {
c := &Context{
db: db,
helper: helper,
fixturesFiles: fixtures,
}
if err := c.helper.init(c.db); err != nil {
return nil, err
}
if err := c.buildInsertSQLs(); err != nil {
return nil, err
}
return c, nil
}
// Load wipes and after load all fixtures in the database.
// if err := fixtures.Load(); err != nil {
// log.Fatal(err)
// }
func (c *Context) Load() error {
if !skipDatabaseNameCheck {
if !dbnameRegexp.MatchString(c.helper.databaseName(c.db)) {
return ErrNotTestDatabase
}
}
err := c.helper.disableReferentialIntegrity(c.db, func(tx *sql.Tx) error {
for _, file := range c.fixturesFiles {
if err := file.delete(tx, c.helper); err != nil {
return err
}
err := c.helper.whileInsertOnTable(tx, file.fileNameWithoutExtension(), func() error {
for _, i := range file.insertSQLs {
if _, err := tx.Exec(i.sql, i.params...); err != nil {
return err
}
}
return nil
})
if err != nil {
return err
}
}
return nil
})
return err
}
func (c *Context) buildInsertSQLs() error {
for _, f := range c.fixturesFiles {
var records interface{}
if err := yaml.Unmarshal(f.content, &records); err != nil {
return err
}
switch records := records.(type) {
case []interface{}:
for _, record := range records {
recordMap, ok := record.(map[interface{}]interface{})
if !ok {
return ErrWrongCastNotAMap
}
sql, values, err := f.buildInsertSQL(c.helper, recordMap)
if err != nil {
return err
}
f.insertSQLs = append(f.insertSQLs, insertSQL{sql, values})
}
case map[interface{}]interface{}:
for _, record := range records {
recordMap, ok := record.(map[interface{}]interface{})
if !ok {
return ErrWrongCastNotAMap
}
sql, values, err := f.buildInsertSQL(c.helper, recordMap)
if err != nil {
return err
}
f.insertSQLs = append(f.insertSQLs, insertSQL{sql, values})
}
default:
return ErrFileIsNotSliceOrMap
}
}
return nil
}
func (f *fixtureFile) fileNameWithoutExtension() string {
return strings.Replace(f.fileName, filepath.Ext(f.fileName), "", 1)
}
func (f *fixtureFile) delete(tx *sql.Tx, h Helper) error {
_, err := tx.Exec(fmt.Sprintf("DELETE FROM %s", h.quoteKeyword(f.fileNameWithoutExtension())))
return err
}
func (f *fixtureFile) buildInsertSQL(h Helper, record map[interface{}]interface{}) (sqlStr string, values []interface{}, err error) {
var (
sqlColumns []string
sqlValues []string
i = 1
)
for key, value := range record {
keyStr, ok := key.(string)
if !ok {
err = ErrKeyIsNotString
return
}
sqlColumns = append(sqlColumns, h.quoteKeyword(keyStr))
switch h.paramType() {
case paramTypeDollar:
sqlValues = append(sqlValues, fmt.Sprintf("$%d", i))
case paramTypeQuestion:
sqlValues = append(sqlValues, "?")
case paramTypeColon:
switch {
case isDateTime(value):
sqlValues = append(sqlValues, fmt.Sprintf("to_date(:%d, 'YYYY-MM-DD HH24:MI:SS')", i))
case isDate(value):
sqlValues = append(sqlValues, fmt.Sprintf("to_date(:%d, 'YYYY-MM-DD')", i))
case isTime(value):
sqlValues = append(sqlValues, fmt.Sprintf("to_date(:%d, 'HH24:MI:SS')", i))
default:
sqlValues = append(sqlValues, fmt.Sprintf(":%d", i))
}
}
i++
values = append(values, value)
}
sqlStr = fmt.Sprintf(
"INSERT INTO %s (%s) VALUES (%s)",
h.quoteKeyword(f.fileNameWithoutExtension()),
strings.Join(sqlColumns, ", "),
strings.Join(sqlValues, ", "),
)
return
}
func fixturesFromFolder(folderName string) ([]*fixtureFile, error) {
var files []*fixtureFile
fileinfos, err := ioutil.ReadDir(folderName)
if err != nil {
return nil, err
}
for _, fileinfo := range fileinfos {
if !fileinfo.IsDir() && filepath.Ext(fileinfo.Name()) == ".yml" {
fixture := &fixtureFile{
path: path.Join(folderName, fileinfo.Name()),
fileName: fileinfo.Name(),
}
fixture.content, err = ioutil.ReadFile(fixture.path)
if err != nil {
return nil, err
}
files = append(files, fixture)
}
}
return files, nil
}
func fixturesFromFiles(fileNames ...string) ([]*fixtureFile, error) {
var (
fixtureFiles []*fixtureFile
err error
)
for _, f := range fileNames {
fixture := &fixtureFile{
path: f,
fileName: filepath.Base(f),
}
fixture.content, err = ioutil.ReadFile(fixture.path)
if err != nil {
return nil, err
}
fixtureFiles = append(fixtureFiles, fixture)
}
return fixtureFiles, nil
}

36
vendor/gopkg.in/testfixtures.v2/time.go generated vendored Normal file
View File

@@ -0,0 +1,36 @@
package testfixtures
import "regexp"
var (
regexpDate = regexp.MustCompile("\\d\\d\\d\\d-\\d\\d-\\d\\d")
regexpDateTime = regexp.MustCompile("\\d\\d\\d\\d-\\d\\d-\\d\\d \\d\\d:\\d\\d:\\d\\d")
regexpTime = regexp.MustCompile("\\d\\d:\\d\\d:\\d\\d")
)
func isDate(value interface{}) bool {
str, isStr := value.(string)
if !isStr {
return false
}
return regexpDate.MatchString(str)
}
func isDateTime(value interface{}) bool {
str, isStr := value.(string)
if !isStr {
return false
}
return regexpDateTime.MatchString(str)
}
func isTime(value interface{}) bool {
str, isStr := value.(string)
if !isStr {
return false
}
return regexpTime.MatchString(str)
}