Vendor TO GOlang go-sqlmock
Project: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/commit/f9f7cfa0 Tree: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/tree/f9f7cfa0 Diff: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/diff/f9f7cfa0 Branch: refs/heads/master Commit: f9f7cfa06217d5b3d4c1ba4bd026982b8d8fcaba Parents: 4fd7feb Author: Robert Butts <robert.o.bu...@gmail.com> Authored: Mon Jul 17 21:53:50 2017 -0600 Committer: Dewayne Richardson <dewr...@apache.org> Committed: Thu Aug 10 09:46:02 2017 -0600 ---------------------------------------------------------------------- .../vendor/gopkg.in/DATA-DOG/go-sqlmock/LICENSE | 28 + .../gopkg.in/DATA-DOG/go-sqlmock/README.md | 223 +++++ .../gopkg.in/DATA-DOG/go-sqlmock/argument.go | 24 + .../DATA-DOG/go-sqlmock/argument_test.go | 58 ++ .../gopkg.in/DATA-DOG/go-sqlmock/driver.go | 78 ++ .../gopkg.in/DATA-DOG/go-sqlmock/driver_test.go | 112 +++ .../DATA-DOG/go-sqlmock/examples/basic/basic.go | 40 + .../go-sqlmock/examples/basic/basic_test.go | 58 ++ .../DATA-DOG/go-sqlmock/examples/blog/blog.go | 81 ++ .../go-sqlmock/examples/blog/blog_test.go | 102 ++ .../DATA-DOG/go-sqlmock/examples/doc.go | 1 + .../go-sqlmock/examples/orders/orders.go | 121 +++ .../go-sqlmock/examples/orders/orders_test.go | 108 ++ .../DATA-DOG/go-sqlmock/expectations.go | 344 +++++++ .../go-sqlmock/expectations_before_go18.go | 52 + .../DATA-DOG/go-sqlmock/expectations_go18.go | 66 ++ .../go-sqlmock/expectations_go18_test.go | 64 ++ .../DATA-DOG/go-sqlmock/expectations_test.go | 154 +++ .../gopkg.in/DATA-DOG/go-sqlmock/result.go | 39 + .../gopkg.in/DATA-DOG/go-sqlmock/result_test.go | 62 ++ .../vendor/gopkg.in/DATA-DOG/go-sqlmock/rows.go | 144 +++ .../gopkg.in/DATA-DOG/go-sqlmock/rows_go18.go | 20 + .../DATA-DOG/go-sqlmock/rows_go18_test.go | 92 ++ .../gopkg.in/DATA-DOG/go-sqlmock/rows_test.go | 265 +++++ .../gopkg.in/DATA-DOG/go-sqlmock/sqlmock.go | 525 ++++++++++ .../DATA-DOG/go-sqlmock/sqlmock_go18.go | 101 ++ .../DATA-DOG/go-sqlmock/sqlmock_go18_test.go | 426 ++++++++ .../DATA-DOG/go-sqlmock/sqlmock_test.go | 998 +++++++++++++++++++ .../gopkg.in/DATA-DOG/go-sqlmock/statement.go | 27 + .../DATA-DOG/go-sqlmock/statement_test.go | 33 + .../gopkg.in/DATA-DOG/go-sqlmock/stubs_test.go | 76 ++ .../vendor/gopkg.in/DATA-DOG/go-sqlmock/util.go | 13 + .../gopkg.in/DATA-DOG/go-sqlmock/util_test.go | 21 + 33 files changed, 4556 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/LICENSE ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/LICENSE b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/LICENSE new file mode 100644 index 0000000..7f8bedf --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/LICENSE @@ -0,0 +1,28 @@ +The three clause BSD license (http://en.wikipedia.org/wiki/BSD_licenses) + +Copyright (c) 2013-2017, DATA-DOG team +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* The name DataDog.lt may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/README.md ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/README.md b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/README.md new file mode 100644 index 0000000..f3d5487 --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/README.md @@ -0,0 +1,223 @@ +[![Build Status](https://travis-ci.org/DATA-DOG/go-sqlmock.png)](https://travis-ci.org/DATA-DOG/go-sqlmock) +[![GoDoc](https://godoc.org/github.com/DATA-DOG/go-sqlmock?status.png)](https://godoc.org/github.com/DATA-DOG/go-sqlmock) +[![codecov.io](https://codecov.io/github/DATA-DOG/go-sqlmock/branch/master/graph/badge.svg)](https://codecov.io/github/DATA-DOG/go-sqlmock) + +# Sql driver mock for Golang + +**sqlmock** is a mock library implementing [sql/driver](https://godoc.org/database/sql/driver). Which has one and only +purpose - to simulate any **sql** driver behavior in tests, without needing a real database connection. It helps to +maintain correct **TDD** workflow. + +- this library is now complete and stable. (you may not find new changes for this reason) +- supports concurrency and multiple connections. +- supports **go1.8** Context related feature mocking and Named sql parameters. +- does not require any modifications to your source code. +- the driver allows to mock any sql driver method behavior. +- has strict by default expectation order matching. +- has no third party dependencies. + +## Install + + go get gopkg.in/DATA-DOG/go-sqlmock.v1 + +## Documentation and Examples + +Visit [godoc](http://godoc.org/github.com/DATA-DOG/go-sqlmock) for general examples and public api reference. +See **.travis.yml** for supported **go** versions. +Different use case, is to functionally test with a real database - [go-txdb](https://github.com/DATA-DOG/go-txdb) +all database related actions are isolated within a single transaction so the database can remain in the same state. + +See implementation examples: + +- [blog API server](https://github.com/DATA-DOG/go-sqlmock/tree/master/examples/blog) +- [the same orders example](https://github.com/DATA-DOG/go-sqlmock/tree/master/examples/orders) + +### Something you may want to test + +``` go +package main + +import "database/sql" + +func recordStats(db *sql.DB, userID, productID int64) (err error) { + tx, err := db.Begin() + if err != nil { + return + } + + defer func() { + switch err { + case nil: + err = tx.Commit() + default: + tx.Rollback() + } + }() + + if _, err = tx.Exec("UPDATE products SET views = views + 1"); err != nil { + return + } + if _, err = tx.Exec("INSERT INTO product_viewers (user_id, product_id) VALUES (?, ?)", userID, productID); err != nil { + return + } + return +} + +func main() { + // @NOTE: the real connection is not required for tests + db, err := sql.Open("mysql", "root@/blog") + if err != nil { + panic(err) + } + defer db.Close() + + if err = recordStats(db, 1 /*some user id*/, 5 /*some product id*/); err != nil { + panic(err) + } +} +``` + +### Tests with sqlmock + +``` go +package main + +import ( + "fmt" + "testing" + + "gopkg.in/DATA-DOG/go-sqlmock.v1" +) + +// a successful case +func TestShouldUpdateStats(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + mock.ExpectBegin() + mock.ExpectExec("UPDATE products").WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectExec("INSERT INTO product_viewers").WithArgs(2, 3).WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectCommit() + + // now we execute our method + if err = recordStats(db, 2, 3); err != nil { + t.Errorf("error was not expected while updating stats: %s", err) + } + + // we make sure that all expectations were met + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expections: %s", err) + } +} + +// a failing test case +func TestShouldRollbackStatUpdatesOnFailure(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + mock.ExpectBegin() + mock.ExpectExec("UPDATE products").WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectExec("INSERT INTO product_viewers"). + WithArgs(2, 3). + WillReturnError(fmt.Errorf("some error")) + mock.ExpectRollback() + + // now we execute our method + if err = recordStats(db, 2, 3); err == nil { + t.Errorf("was expecting an error, but there was none") + } + + // we make sure that all expectations were met + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expections: %s", err) + } +} +``` + +## Matching arguments like time.Time + +There may be arguments which are of `struct` type and cannot be compared easily by value like `time.Time`. In this case +**sqlmock** provides an [Argument](https://godoc.org/github.com/DATA-DOG/go-sqlmock#Argument) interface which +can be used in more sophisticated matching. Here is a simple example of time argument matching: + +``` go +type AnyTime struct{} + +// Match satisfies sqlmock.Argument interface +func (a AnyTime) Match(v driver.Value) bool { + _, ok := v.(time.Time) + return ok +} + +func TestAnyTimeArgument(t *testing.T) { + t.Parallel() + db, mock, err := New() + if err != nil { + t.Errorf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + mock.ExpectExec("INSERT INTO users"). + WithArgs("john", AnyTime{}). + WillReturnResult(NewResult(1, 1)) + + _, err = db.Exec("INSERT INTO users(name, created_at) VALUES (?, ?)", "john", time.Now()) + if err != nil { + t.Errorf("error '%s' was not expected, while inserting a row", err) + } + + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expections: %s", err) + } +} +``` + +It only asserts that argument is of `time.Time` type. + +## Run tests + + go test -race + +## Change Log + +- **2017-02-09** - implemented support for **go1.8** features. **Rows** interface was changed to struct + but contains all methods as before and should maintain backwards compatibility. **ExpectedQuery.WillReturnRows** may now + accept multiple row sets. +- **2016-11-02** - `db.Prepare()` was not validating expected prepare SQL + query. It should still be validated even if Exec or Query is not + executed on that prepared statement. +- **2016-02-23** - added **sqlmock.AnyArg()** function to provide any kind + of argument matcher. +- **2016-02-23** - convert expected arguments to driver.Value as natural + driver does, the change may affect time.Time comparison and will be + stricter. See [issue](https://github.com/DATA-DOG/go-sqlmock/issues/31). +- **2015-08-27** - **v1** api change, concurrency support, all known issues fixed. +- **2014-08-16** instead of **panic** during reflect type mismatch when comparing query arguments - now return error +- **2014-08-14** added **sqlmock.NewErrorResult** which gives an option to return driver.Result with errors for +interface methods, see [issue](https://github.com/DATA-DOG/go-sqlmock/issues/5) +- **2014-05-29** allow to match arguments in more sophisticated ways, by providing an **sqlmock.Argument** interface +- **2014-04-21** introduce **sqlmock.New()** to open a mock database connection for tests. This method +calls sql.DB.Ping to ensure that connection is open, see [issue](https://github.com/DATA-DOG/go-sqlmock/issues/4). +This way on Close it will surely assert if all expectations are met, even if database was not triggered at all. +The old way is still available, but it is advisable to call db.Ping manually before asserting with db.Close. +- **2014-02-14** RowsFromCSVString is now a part of Rows interface named as FromCSVString. +It has changed to allow more ways to construct rows and to easily extend this API in future. +See [issue 1](https://github.com/DATA-DOG/go-sqlmock/issues/1) +**RowsFromCSVString** is deprecated and will be removed in future + +## Contributions + +Feel free to open a pull request. Note, if you wish to contribute an extension to public (exported methods or types) - +please open an issue before, to discuss whether these changes can be accepted. All backward incompatible changes are +and will be treated cautiously + +## License + +The [three clause BSD license](http://en.wikipedia.org/wiki/BSD_licenses) + http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/argument.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/argument.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/argument.go new file mode 100644 index 0000000..7727481 --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/argument.go @@ -0,0 +1,24 @@ +package sqlmock + +import "database/sql/driver" + +// Argument interface allows to match +// any argument in specific way when used with +// ExpectedQuery and ExpectedExec expectations. +type Argument interface { + Match(driver.Value) bool +} + +// AnyArg will return an Argument which can +// match any kind of arguments. +// +// Useful for time.Time or similar kinds of arguments. +func AnyArg() Argument { + return anyArgument{} +} + +type anyArgument struct{} + +func (a anyArgument) Match(_ driver.Value) bool { + return true +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/argument_test.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/argument_test.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/argument_test.go new file mode 100644 index 0000000..3088ed4 --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/argument_test.go @@ -0,0 +1,58 @@ +package sqlmock + +import ( + "database/sql/driver" + "testing" + "time" +) + +type AnyTime struct{} + +// Match satisfies sqlmock.Argument interface +func (a AnyTime) Match(v driver.Value) bool { + _, ok := v.(time.Time) + return ok +} + +func TestAnyTimeArgument(t *testing.T) { + t.Parallel() + db, mock, err := New() + if err != nil { + t.Errorf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + mock.ExpectExec("INSERT INTO users"). + WithArgs("john", AnyTime{}). + WillReturnResult(NewResult(1, 1)) + + _, err = db.Exec("INSERT INTO users(name, created_at) VALUES (?, ?)", "john", time.Now()) + if err != nil { + t.Errorf("error '%s' was not expected, while inserting a row", err) + } + + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expections: %s", err) + } +} + +func TestByteSliceArgument(t *testing.T) { + t.Parallel() + db, mock, err := New() + if err != nil { + t.Errorf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + username := []byte("user") + mock.ExpectExec("INSERT INTO users").WithArgs(username).WillReturnResult(NewResult(1, 1)) + + _, err = db.Exec("INSERT INTO users(username) VALUES (?)", username) + if err != nil { + t.Errorf("error '%s' was not expected, while inserting a row", err) + } + + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expections: %s", err) + } +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/driver.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/driver.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/driver.go new file mode 100644 index 0000000..2a480fe --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/driver.go @@ -0,0 +1,78 @@ +package sqlmock + +import ( + "database/sql" + "database/sql/driver" + "fmt" + "sync" +) + +var pool *mockDriver + +func init() { + pool = &mockDriver{ + conns: make(map[string]*sqlmock), + } + sql.Register("sqlmock", pool) +} + +type mockDriver struct { + sync.Mutex + counter int + conns map[string]*sqlmock +} + +func (d *mockDriver) Open(dsn string) (driver.Conn, error) { + d.Lock() + defer d.Unlock() + + c, ok := d.conns[dsn] + if !ok { + return c, fmt.Errorf("expected a connection to be available, but it is not") + } + + c.opened++ + return c, nil +} + +// New creates sqlmock database connection +// and a mock to manage expectations. +// Pings db so that all expectations could be +// asserted. +func New() (*sql.DB, Sqlmock, error) { + pool.Lock() + dsn := fmt.Sprintf("sqlmock_db_%d", pool.counter) + pool.counter++ + + smock := &sqlmock{dsn: dsn, drv: pool, ordered: true} + pool.conns[dsn] = smock + pool.Unlock() + + return smock.open() +} + +// NewWithDSN creates sqlmock database connection +// with a specific DSN and a mock to manage expectations. +// Pings db so that all expectations could be asserted. +// +// This method is introduced because of sql abstraction +// libraries, which do not provide a way to initialize +// with sql.DB instance. For example GORM library. +// +// Note, it will error if attempted to create with an +// already used dsn +// +// It is not recommended to use this method, unless you +// really need it and there is no other way around. +func NewWithDSN(dsn string) (*sql.DB, Sqlmock, error) { + pool.Lock() + if _, ok := pool.conns[dsn]; ok { + pool.Unlock() + return nil, nil, fmt.Errorf("cannot create a new mock database with the same dsn: %s", dsn) + } + smock := &sqlmock{dsn: dsn, drv: pool, ordered: true} + pool.conns[dsn] = smock + pool.Unlock() + + return smock.open() +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/driver_test.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/driver_test.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/driver_test.go new file mode 100644 index 0000000..1a65c1c --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/driver_test.go @@ -0,0 +1,112 @@ +package sqlmock + +import ( + "fmt" + "testing" +) + +type void struct{} + +func (void) Print(...interface{}) {} + +func ExampleNew() { + db, mock, err := New() + if err != nil { + fmt.Println("expected no error, but got:", err) + return + } + defer db.Close() + // now we can expect operations performed on db + mock.ExpectBegin().WillReturnError(fmt.Errorf("an error will occur on db.Begin() call")) +} + +func TestShouldOpenConnectionIssue15(t *testing.T) { + db, mock, err := New() + if err != nil { + t.Errorf("expected no error, but got: %s", err) + } + if len(pool.conns) != 1 { + t.Errorf("expected 1 connection in pool, but there is: %d", len(pool.conns)) + } + + smock, _ := mock.(*sqlmock) + if smock.opened != 1 { + t.Errorf("expected 1 connection on mock to be opened, but there is: %d", smock.opened) + } + + // defer so the rows gets closed first + defer func() { + if smock.opened != 0 { + t.Errorf("expected no connections on mock to be opened, but there is: %d", smock.opened) + } + }() + + mock.ExpectQuery("SELECT").WillReturnRows(NewRows([]string{"one", "two"}).AddRow("val1", "val2")) + rows, err := db.Query("SELECT") + if err != nil { + t.Errorf("unexpected error: %s", err) + } + defer rows.Close() + + mock.ExpectExec("UPDATE").WillReturnResult(NewResult(1, 1)) + if _, err = db.Exec("UPDATE"); err != nil { + t.Errorf("unexpected error: %s", err) + } + + // now there should be two connections open + if smock.opened != 2 { + t.Errorf("expected 2 connection on mock to be opened, but there is: %d", smock.opened) + } + + mock.ExpectClose() + if err = db.Close(); err != nil { + t.Errorf("expected no error on close, but got: %s", err) + } + + // one is still reserved for rows + if smock.opened != 1 { + t.Errorf("expected 1 connection on mock to be still reserved for rows, but there is: %d", smock.opened) + } +} + +func TestTwoOpenConnectionsOnTheSameDSN(t *testing.T) { + db, mock, err := New() + if err != nil { + t.Errorf("expected no error, but got: %s", err) + } + db2, mock2, err := New() + if err != nil { + t.Errorf("expected no error, but got: %s", err) + } + if len(pool.conns) != 2 { + t.Errorf("expected 2 connection in pool, but there is: %d", len(pool.conns)) + } + + if db == db2 { + t.Errorf("expected not the same database instance, but it is the same") + } + if mock == mock2 { + t.Errorf("expected not the same mock instance, but it is the same") + } +} + +func TestWrongDSN(t *testing.T) { + t.Parallel() + db, _, _ := New() + defer db.Close() + if _, err := db.Driver().Open("wrong_dsn"); err == nil { + t.Error("expected error on Open") + } +} + +func TestNewDSN(t *testing.T) { + if _, _, err := NewWithDSN("sqlmock_db_99"); err != nil { + t.Errorf("expected no error on NewWithDSN, but got: %s", err) + } +} + +func TestDuplicateNewDSN(t *testing.T) { + if _, _, err := NewWithDSN("sqlmock_db_1"); err == nil { + t.Error("expected error on NewWithDSN") + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/basic/basic.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/basic/basic.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/basic/basic.go new file mode 100644 index 0000000..0fbf98d --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/basic/basic.go @@ -0,0 +1,40 @@ +package main + +import "database/sql" + +func recordStats(db *sql.DB, userID, productID int64) (err error) { + tx, err := db.Begin() + if err != nil { + return + } + + defer func() { + switch err { + case nil: + err = tx.Commit() + default: + tx.Rollback() + } + }() + + if _, err = tx.Exec("UPDATE products SET views = views + 1"); err != nil { + return + } + if _, err = tx.Exec("INSERT INTO product_viewers (user_id, product_id) VALUES (?, ?)", userID, productID); err != nil { + return + } + return +} + +func main() { + // @NOTE: the real connection is not required for tests + db, err := sql.Open("mysql", "root@/blog") + if err != nil { + panic(err) + } + defer db.Close() + + if err = recordStats(db, 1 /*some user id*/, 5 /*some product id*/); err != nil { + panic(err) + } +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/basic/basic_test.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/basic/basic_test.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/basic/basic_test.go new file mode 100644 index 0000000..0825f90 --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/basic/basic_test.go @@ -0,0 +1,58 @@ +package main + +import ( + "fmt" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +// a successful case +func TestShouldUpdateStats(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + mock.ExpectBegin() + mock.ExpectExec("UPDATE products").WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectExec("INSERT INTO product_viewers").WithArgs(2, 3).WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectCommit() + + // now we execute our method + if err = recordStats(db, 2, 3); err != nil { + t.Errorf("error was not expected while updating stats: %s", err) + } + + // we make sure that all expectations were met + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expections: %s", err) + } +} + +// a failing test case +func TestShouldRollbackStatUpdatesOnFailure(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + mock.ExpectBegin() + mock.ExpectExec("UPDATE products").WillReturnResult(sqlmock.NewResult(1, 1)) + mock.ExpectExec("INSERT INTO product_viewers"). + WithArgs(2, 3). + WillReturnError(fmt.Errorf("some error")) + mock.ExpectRollback() + + // now we execute our method + if err = recordStats(db, 2, 3); err == nil { + t.Errorf("was expecting an error, but there was none") + } + + // we make sure that all expectations were met + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expections: %s", err) + } +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/blog/blog.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/blog/blog.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/blog/blog.go new file mode 100644 index 0000000..c4aec06 --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/blog/blog.go @@ -0,0 +1,81 @@ +package main + +import ( + "database/sql" + "encoding/json" + "net/http" +) + +type api struct { + db *sql.DB +} + +type post struct { + ID int + Title string + Body string +} + +func (a *api) posts(w http.ResponseWriter, r *http.Request) { + rows, err := a.db.Query("SELECT id, title, body FROM posts") + if err != nil { + a.fail(w, "failed to fetch posts: "+err.Error(), 500) + return + } + defer rows.Close() + + var posts []*post + for rows.Next() { + p := &post{} + if err := rows.Scan(&p.ID, &p.Title, &p.Body); err != nil { + a.fail(w, "failed to scan post: "+err.Error(), 500) + return + } + posts = append(posts, p) + } + if rows.Err() != nil { + a.fail(w, "failed to read all posts: "+rows.Err().Error(), 500) + return + } + + data := struct { + Posts []*post + }{posts} + + a.ok(w, data) +} + +func main() { + // @NOTE: the real connection is not required for tests + db, err := sql.Open("mysql", "root@/blog") + if err != nil { + panic(err) + } + app := &api{db: db} + http.HandleFunc("/posts", app.posts) + http.ListenAndServe(":8080", nil) +} + +func (a *api) fail(w http.ResponseWriter, msg string, status int) { + w.Header().Set("Content-Type", "application/json") + + data := struct { + Error string + }{Error: msg} + + resp, _ := json.Marshal(data) + w.WriteHeader(status) + w.Write(resp) +} + +func (a *api) ok(w http.ResponseWriter, data interface{}) { + w.Header().Set("Content-Type", "application/json") + + resp, err := json.Marshal(data) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + a.fail(w, "oops something evil has happened", 500) + return + } + w.Write(resp) +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/blog/blog_test.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/blog/blog_test.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/blog/blog_test.go new file mode 100644 index 0000000..aa1881a --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/blog/blog_test.go @@ -0,0 +1,102 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +func (a *api) assertJSON(actual []byte, data interface{}, t *testing.T) { + expected, err := json.Marshal(data) + if err != nil { + t.Fatalf("an error '%s' was not expected when marshaling expected json data", err) + } + + if bytes.Compare(expected, actual) != 0 { + t.Errorf("the expected json: %s is different from actual %s", expected, actual) + } +} + +func TestShouldGetPosts(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + // create app with mocked db, request and response to test + app := &api{db} + req, err := http.NewRequest("GET", "http://localhost/posts", nil) + if err != nil { + t.Fatalf("an error '%s' was not expected while creating request", err) + } + w := httptest.NewRecorder() + + // before we actually execute our api function, we need to expect required DB actions + rows := sqlmock.NewRows([]string{"id", "title", "body"}). + AddRow(1, "post 1", "hello"). + AddRow(2, "post 2", "world") + + mock.ExpectQuery("^SELECT (.+) FROM posts$").WillReturnRows(rows) + + // now we execute our request + app.posts(w, req) + + if w.Code != 200 { + t.Fatalf("expected status code to be 200, but got: %d", w.Code) + } + + data := struct { + Posts []*post + }{Posts: []*post{ + {ID: 1, Title: "post 1", Body: "hello"}, + {ID: 2, Title: "post 2", Body: "world"}, + }} + app.assertJSON(w.Body.Bytes(), data, t) + + // we make sure that all expectations were met + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expections: %s", err) + } +} + +func TestShouldRespondWithErrorOnFailure(t *testing.T) { + db, mock, err := sqlmock.New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + // create app with mocked db, request and response to test + app := &api{db} + req, err := http.NewRequest("GET", "http://localhost/posts", nil) + if err != nil { + t.Fatalf("an error '%s' was not expected while creating request", err) + } + w := httptest.NewRecorder() + + // before we actually execute our api function, we need to expect required DB actions + mock.ExpectQuery("^SELECT (.+) FROM posts$").WillReturnError(fmt.Errorf("some error")) + + // now we execute our request + app.posts(w, req) + + if w.Code != 500 { + t.Fatalf("expected status code to be 500, but got: %d", w.Code) + } + + data := struct { + Error string + }{"failed to fetch posts: some error"} + app.assertJSON(w.Body.Bytes(), data, t) + + // we make sure that all expectations were met + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expections: %s", err) + } +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/doc.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/doc.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/doc.go new file mode 100644 index 0000000..c7842af --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/doc.go @@ -0,0 +1 @@ +package examples http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/orders/orders.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/orders/orders.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/orders/orders.go new file mode 100644 index 0000000..fb7e47e --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/orders/orders.go @@ -0,0 +1,121 @@ +package main + +import ( + "database/sql" + "fmt" + "log" + + "github.com/kisielk/sqlstruct" +) + +const ORDER_PENDING = 0 +const ORDER_CANCELLED = 1 + +type User struct { + Id int `sql:"id"` + Username string `sql:"username"` + Balance float64 `sql:"balance"` +} + +type Order struct { + Id int `sql:"id"` + Value float64 `sql:"value"` + ReservedFee float64 `sql:"reserved_fee"` + Status int `sql:"status"` +} + +func cancelOrder(id int, db *sql.DB) (err error) { + tx, err := db.Begin() + if err != nil { + return + } + + var order Order + var user User + sql := fmt.Sprintf(` +SELECT %s, %s +FROM orders AS o +INNER JOIN users AS u ON o.buyer_id = u.id +WHERE o.id = ? +FOR UPDATE`, + sqlstruct.ColumnsAliased(order, "o"), + sqlstruct.ColumnsAliased(user, "u")) + + // fetch order to cancel + rows, err := tx.Query(sql, id) + if err != nil { + tx.Rollback() + return + } + + defer rows.Close() + // no rows, nothing to do + if !rows.Next() { + tx.Rollback() + return + } + + // read order + err = sqlstruct.ScanAliased(&order, rows, "o") + if err != nil { + tx.Rollback() + return + } + + // ensure order status + if order.Status != ORDER_PENDING { + tx.Rollback() + return + } + + // read user + err = sqlstruct.ScanAliased(&user, rows, "u") + if err != nil { + tx.Rollback() + return + } + rows.Close() // manually close before other prepared statements + + // refund order value + sql = "UPDATE users SET balance = balance + ? WHERE id = ?" + refundStmt, err := tx.Prepare(sql) + if err != nil { + tx.Rollback() + return + } + defer refundStmt.Close() + _, err = refundStmt.Exec(order.Value+order.ReservedFee, user.Id) + if err != nil { + tx.Rollback() + return + } + + // update order status + order.Status = ORDER_CANCELLED + sql = "UPDATE orders SET status = ?, updated = NOW() WHERE id = ?" + orderUpdStmt, err := tx.Prepare(sql) + if err != nil { + tx.Rollback() + return + } + defer orderUpdStmt.Close() + _, err = orderUpdStmt.Exec(order.Status, order.Id) + if err != nil { + tx.Rollback() + return + } + return tx.Commit() +} + +func main() { + // @NOTE: the real connection is not required for tests + db, err := sql.Open("mysql", "root:@/orders") + if err != nil { + log.Fatal(err) + } + defer db.Close() + err = cancelOrder(1, db) + if err != nil { + log.Fatal(err) + } +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/orders/orders_test.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/orders/orders_test.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/orders/orders_test.go new file mode 100644 index 0000000..7562b8f --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/examples/orders/orders_test.go @@ -0,0 +1,108 @@ +package main + +import ( + "fmt" + "testing" + + "github.com/DATA-DOG/go-sqlmock" +) + +// will test that order with a different status, cannot be cancelled +func TestShouldNotCancelOrderWithNonPendingStatus(t *testing.T) { + // open database stub + db, mock, err := sqlmock.New() + if err != nil { + t.Errorf("An error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + // columns are prefixed with "o" since we used sqlstruct to generate them + columns := []string{"o_id", "o_status"} + // expect transaction begin + mock.ExpectBegin() + // expect query to fetch order and user, match it with regexp + mock.ExpectQuery("SELECT (.+) FROM orders AS o INNER JOIN users AS u (.+) FOR UPDATE"). + WithArgs(1). + WillReturnRows(sqlmock.NewRows(columns).FromCSVString("1,1")) + // expect transaction rollback, since order status is "cancelled" + mock.ExpectRollback() + + // run the cancel order function + err = cancelOrder(1, db) + if err != nil { + t.Errorf("Expected no error, but got %s instead", err) + } + // we make sure that all expectations were met + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expections: %s", err) + } +} + +// will test order cancellation +func TestShouldRefundUserWhenOrderIsCancelled(t *testing.T) { + // open database stub + db, mock, err := sqlmock.New() + if err != nil { + t.Errorf("An error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + // columns are prefixed with "o" since we used sqlstruct to generate them + columns := []string{"o_id", "o_status", "o_value", "o_reserved_fee", "u_id", "u_balance"} + // expect transaction begin + mock.ExpectBegin() + // expect query to fetch order and user, match it with regexp + mock.ExpectQuery("SELECT (.+) FROM orders AS o INNER JOIN users AS u (.+) FOR UPDATE"). + WithArgs(1). + WillReturnRows(sqlmock.NewRows(columns).AddRow(1, 0, 25.75, 3.25, 2, 10.00)) + // expect user balance update + mock.ExpectPrepare("UPDATE users SET balance").ExpectExec(). + WithArgs(25.75+3.25, 2). // refund amount, user id + WillReturnResult(sqlmock.NewResult(0, 1)) // no insert id, 1 affected row + // expect order status update + mock.ExpectPrepare("UPDATE orders SET status").ExpectExec(). + WithArgs(ORDER_CANCELLED, 1). // status, id + WillReturnResult(sqlmock.NewResult(0, 1)) // no insert id, 1 affected row + // expect a transaction commit + mock.ExpectCommit() + + // run the cancel order function + err = cancelOrder(1, db) + if err != nil { + t.Errorf("Expected no error, but got %s instead", err) + } + // we make sure that all expectations were met + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expections: %s", err) + } +} + +// will test order cancellation +func TestShouldRollbackOnError(t *testing.T) { + // open database stub + db, mock, err := sqlmock.New() + if err != nil { + t.Errorf("An error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + // expect transaction begin + mock.ExpectBegin() + // expect query to fetch order and user, match it with regexp + mock.ExpectQuery("SELECT (.+) FROM orders AS o INNER JOIN users AS u (.+) FOR UPDATE"). + WithArgs(1). + WillReturnError(fmt.Errorf("Some error")) + // should rollback since error was returned from query execution + mock.ExpectRollback() + + // run the cancel order function + err = cancelOrder(1, db) + // error should return back + if err == nil { + t.Error("Expected error, but got none") + } + // we make sure that all expectations were met + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expections: %s", err) + } +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/expectations.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/expectations.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/expectations.go new file mode 100644 index 0000000..415759e --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/expectations.go @@ -0,0 +1,344 @@ +package sqlmock + +import ( + "database/sql/driver" + "fmt" + "regexp" + "strings" + "sync" + "time" +) + +// an expectation interface +type expectation interface { + fulfilled() bool + Lock() + Unlock() + String() string +} + +// common expectation struct +// satisfies the expectation interface +type commonExpectation struct { + sync.Mutex + triggered bool + err error +} + +func (e *commonExpectation) fulfilled() bool { + return e.triggered +} + +// ExpectedClose is used to manage *sql.DB.Close expectation +// returned by *Sqlmock.ExpectClose. +type ExpectedClose struct { + commonExpectation +} + +// WillReturnError allows to set an error for *sql.DB.Close action +func (e *ExpectedClose) WillReturnError(err error) *ExpectedClose { + e.err = err + return e +} + +// String returns string representation +func (e *ExpectedClose) String() string { + msg := "ExpectedClose => expecting database Close" + if e.err != nil { + msg += fmt.Sprintf(", which should return error: %s", e.err) + } + return msg +} + +// ExpectedBegin is used to manage *sql.DB.Begin expectation +// returned by *Sqlmock.ExpectBegin. +type ExpectedBegin struct { + commonExpectation + delay time.Duration +} + +// WillReturnError allows to set an error for *sql.DB.Begin action +func (e *ExpectedBegin) WillReturnError(err error) *ExpectedBegin { + e.err = err + return e +} + +// String returns string representation +func (e *ExpectedBegin) String() string { + msg := "ExpectedBegin => expecting database transaction Begin" + if e.err != nil { + msg += fmt.Sprintf(", which should return error: %s", e.err) + } + return msg +} + +// WillDelayFor allows to specify duration for which it will delay +// result. May be used together with Context +func (e *ExpectedBegin) WillDelayFor(duration time.Duration) *ExpectedBegin { + e.delay = duration + return e +} + +// ExpectedCommit is used to manage *sql.Tx.Commit expectation +// returned by *Sqlmock.ExpectCommit. +type ExpectedCommit struct { + commonExpectation +} + +// WillReturnError allows to set an error for *sql.Tx.Close action +func (e *ExpectedCommit) WillReturnError(err error) *ExpectedCommit { + e.err = err + return e +} + +// String returns string representation +func (e *ExpectedCommit) String() string { + msg := "ExpectedCommit => expecting transaction Commit" + if e.err != nil { + msg += fmt.Sprintf(", which should return error: %s", e.err) + } + return msg +} + +// ExpectedRollback is used to manage *sql.Tx.Rollback expectation +// returned by *Sqlmock.ExpectRollback. +type ExpectedRollback struct { + commonExpectation +} + +// WillReturnError allows to set an error for *sql.Tx.Rollback action +func (e *ExpectedRollback) WillReturnError(err error) *ExpectedRollback { + e.err = err + return e +} + +// String returns string representation +func (e *ExpectedRollback) String() string { + msg := "ExpectedRollback => expecting transaction Rollback" + if e.err != nil { + msg += fmt.Sprintf(", which should return error: %s", e.err) + } + return msg +} + +// ExpectedQuery is used to manage *sql.DB.Query, *dql.DB.QueryRow, *sql.Tx.Query, +// *sql.Tx.QueryRow, *sql.Stmt.Query or *sql.Stmt.QueryRow expectations. +// Returned by *Sqlmock.ExpectQuery. +type ExpectedQuery struct { + queryBasedExpectation + rows driver.Rows + delay time.Duration +} + +// WithArgs will match given expected args to actual database query arguments. +// if at least one argument does not match, it will return an error. For specific +// arguments an sqlmock.Argument interface can be used to match an argument. +func (e *ExpectedQuery) WithArgs(args ...driver.Value) *ExpectedQuery { + e.args = args + return e +} + +// WillReturnError allows to set an error for expected database query +func (e *ExpectedQuery) WillReturnError(err error) *ExpectedQuery { + e.err = err + return e +} + +// WillDelayFor allows to specify duration for which it will delay +// result. May be used together with Context +func (e *ExpectedQuery) WillDelayFor(duration time.Duration) *ExpectedQuery { + e.delay = duration + return e +} + +// String returns string representation +func (e *ExpectedQuery) String() string { + msg := "ExpectedQuery => expecting Query or QueryRow which:" + msg += "\n - matches sql: '" + e.sqlRegex.String() + "'" + + if len(e.args) == 0 { + msg += "\n - is without arguments" + } else { + msg += "\n - is with arguments:\n" + for i, arg := range e.args { + msg += fmt.Sprintf(" %d - %+v\n", i, arg) + } + msg = strings.TrimSpace(msg) + } + + if e.rows != nil { + msg += fmt.Sprintf("\n - %s", e.rows) + } + + if e.err != nil { + msg += fmt.Sprintf("\n - should return error: %s", e.err) + } + + return msg +} + +// ExpectedExec is used to manage *sql.DB.Exec, *sql.Tx.Exec or *sql.Stmt.Exec expectations. +// Returned by *Sqlmock.ExpectExec. +type ExpectedExec struct { + queryBasedExpectation + result driver.Result + delay time.Duration +} + +// WithArgs will match given expected args to actual database exec operation arguments. +// if at least one argument does not match, it will return an error. For specific +// arguments an sqlmock.Argument interface can be used to match an argument. +func (e *ExpectedExec) WithArgs(args ...driver.Value) *ExpectedExec { + e.args = args + return e +} + +// WillReturnError allows to set an error for expected database exec action +func (e *ExpectedExec) WillReturnError(err error) *ExpectedExec { + e.err = err + return e +} + +// WillDelayFor allows to specify duration for which it will delay +// result. May be used together with Context +func (e *ExpectedExec) WillDelayFor(duration time.Duration) *ExpectedExec { + e.delay = duration + return e +} + +// String returns string representation +func (e *ExpectedExec) String() string { + msg := "ExpectedExec => expecting Exec which:" + msg += "\n - matches sql: '" + e.sqlRegex.String() + "'" + + if len(e.args) == 0 { + msg += "\n - is without arguments" + } else { + msg += "\n - is with arguments:\n" + var margs []string + for i, arg := range e.args { + margs = append(margs, fmt.Sprintf(" %d - %+v", i, arg)) + } + msg += strings.Join(margs, "\n") + } + + if e.result != nil { + res, _ := e.result.(*result) + msg += "\n - should return Result having:" + msg += fmt.Sprintf("\n LastInsertId: %d", res.insertID) + msg += fmt.Sprintf("\n RowsAffected: %d", res.rowsAffected) + if res.err != nil { + msg += fmt.Sprintf("\n Error: %s", res.err) + } + } + + if e.err != nil { + msg += fmt.Sprintf("\n - should return error: %s", e.err) + } + + return msg +} + +// WillReturnResult arranges for an expected Exec() to return a particular +// result, there is sqlmock.NewResult(lastInsertID int64, affectedRows int64) method +// to build a corresponding result. Or if actions needs to be tested against errors +// sqlmock.NewErrorResult(err error) to return a given error. +func (e *ExpectedExec) WillReturnResult(result driver.Result) *ExpectedExec { + e.result = result + return e +} + +// ExpectedPrepare is used to manage *sql.DB.Prepare or *sql.Tx.Prepare expectations. +// Returned by *Sqlmock.ExpectPrepare. +type ExpectedPrepare struct { + commonExpectation + mock *sqlmock + sqlRegex *regexp.Regexp + statement driver.Stmt + closeErr error + delay time.Duration +} + +// WillReturnError allows to set an error for the expected *sql.DB.Prepare or *sql.Tx.Prepare action. +func (e *ExpectedPrepare) WillReturnError(err error) *ExpectedPrepare { + e.err = err + return e +} + +// WillReturnCloseError allows to set an error for this prapared statement Close action +func (e *ExpectedPrepare) WillReturnCloseError(err error) *ExpectedPrepare { + e.closeErr = err + return e +} + +// WillDelayFor allows to specify duration for which it will delay +// result. May be used together with Context +func (e *ExpectedPrepare) WillDelayFor(duration time.Duration) *ExpectedPrepare { + e.delay = duration + return e +} + +// ExpectQuery allows to expect Query() or QueryRow() on this prepared statement. +// this method is convenient in order to prevent duplicating sql query string matching. +func (e *ExpectedPrepare) ExpectQuery() *ExpectedQuery { + eq := &ExpectedQuery{} + eq.sqlRegex = e.sqlRegex + e.mock.expected = append(e.mock.expected, eq) + return eq +} + +// ExpectExec allows to expect Exec() on this prepared statement. +// this method is convenient in order to prevent duplicating sql query string matching. +func (e *ExpectedPrepare) ExpectExec() *ExpectedExec { + eq := &ExpectedExec{} + eq.sqlRegex = e.sqlRegex + e.mock.expected = append(e.mock.expected, eq) + return eq +} + +// String returns string representation +func (e *ExpectedPrepare) String() string { + msg := "ExpectedPrepare => expecting Prepare statement which:" + msg += "\n - matches sql: '" + e.sqlRegex.String() + "'" + + if e.err != nil { + msg += fmt.Sprintf("\n - should return error: %s", e.err) + } + + if e.closeErr != nil { + msg += fmt.Sprintf("\n - should return error on Close: %s", e.closeErr) + } + + return msg +} + +// query based expectation +// adds a query matching logic +type queryBasedExpectation struct { + commonExpectation + sqlRegex *regexp.Regexp + args []driver.Value +} + +func (e *queryBasedExpectation) attemptMatch(sql string, args []namedValue) (err error) { + if !e.queryMatches(sql) { + return fmt.Errorf(`could not match sql: "%s" with expected regexp "%s"`, sql, e.sqlRegex.String()) + } + + // catch panic + defer func() { + if e := recover(); e != nil { + _, ok := e.(error) + if !ok { + err = fmt.Errorf(e.(string)) + } + } + }() + + err = e.argsMatches(args) + return +} + +func (e *queryBasedExpectation) queryMatches(sql string) bool { + return e.sqlRegex.MatchString(sql) +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/expectations_before_go18.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/expectations_before_go18.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/expectations_before_go18.go new file mode 100644 index 0000000..146f240 --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/expectations_before_go18.go @@ -0,0 +1,52 @@ +// +build !go1.8 + +package sqlmock + +import ( + "database/sql/driver" + "fmt" + "reflect" +) + +// WillReturnRows specifies the set of resulting rows that will be returned +// by the triggered query +func (e *ExpectedQuery) WillReturnRows(rows *Rows) *ExpectedQuery { + e.rows = &rowSets{sets: []*Rows{rows}} + return e +} + +func (e *queryBasedExpectation) argsMatches(args []namedValue) error { + if nil == e.args { + return nil + } + if len(args) != len(e.args) { + return fmt.Errorf("expected %d, but got %d arguments", len(e.args), len(args)) + } + for k, v := range args { + // custom argument matcher + matcher, ok := e.args[k].(Argument) + if ok { + // @TODO: does it make sense to pass value instead of named value? + if !matcher.Match(v.Value) { + return fmt.Errorf("matcher %T could not match %d argument %T - %+v", matcher, k, args[k], args[k]) + } + continue + } + + dval := e.args[k] + // convert to driver converter + darg, err := driver.DefaultParameterConverter.ConvertValue(dval) + if err != nil { + return fmt.Errorf("could not convert %d argument %T - %+v to driver value: %s", k, e.args[k], e.args[k], err) + } + + if !driver.IsValue(darg) { + return fmt.Errorf("argument %d: non-subset type %T returned from Value", k, darg) + } + + if !reflect.DeepEqual(darg, v.Value) { + return fmt.Errorf("argument %d expected [%T - %+v] does not match actual [%T - %+v]", k, darg, darg, v.Value, v.Value) + } + } + return nil +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/expectations_go18.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/expectations_go18.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/expectations_go18.go new file mode 100644 index 0000000..2b4b44e --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/expectations_go18.go @@ -0,0 +1,66 @@ +// +build go1.8 + +package sqlmock + +import ( + "database/sql" + "database/sql/driver" + "fmt" + "reflect" +) + +// WillReturnRows specifies the set of resulting rows that will be returned +// by the triggered query +func (e *ExpectedQuery) WillReturnRows(rows ...*Rows) *ExpectedQuery { + sets := make([]*Rows, len(rows)) + for i, r := range rows { + sets[i] = r + } + e.rows = &rowSets{sets: sets} + return e +} + +func (e *queryBasedExpectation) argsMatches(args []namedValue) error { + if nil == e.args { + return nil + } + if len(args) != len(e.args) { + return fmt.Errorf("expected %d, but got %d arguments", len(e.args), len(args)) + } + // @TODO should we assert either all args are named or ordinal? + for k, v := range args { + // custom argument matcher + matcher, ok := e.args[k].(Argument) + if ok { + if !matcher.Match(v.Value) { + return fmt.Errorf("matcher %T could not match %d argument %T - %+v", matcher, k, args[k], args[k]) + } + continue + } + + dval := e.args[k] + if named, isNamed := dval.(sql.NamedArg); isNamed { + dval = named.Value + if v.Name != named.Name { + return fmt.Errorf("named argument %d: name: \"%s\" does not match expected: \"%s\"", k, v.Name, named.Name) + } + } else if k+1 != v.Ordinal { + return fmt.Errorf("argument %d: ordinal position: %d does not match expected: %d", k, k+1, v.Ordinal) + } + + // convert to driver converter + darg, err := driver.DefaultParameterConverter.ConvertValue(dval) + if err != nil { + return fmt.Errorf("could not convert %d argument %T - %+v to driver value: %s", k, e.args[k], e.args[k], err) + } + + if !driver.IsValue(darg) { + return fmt.Errorf("argument %d: non-subset type %T returned from Value", k, darg) + } + + if !reflect.DeepEqual(darg, v.Value) { + return fmt.Errorf("argument %d expected [%T - %+v] does not match actual [%T - %+v]", k, darg, darg, v.Value, v.Value) + } + } + return nil +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/expectations_go18_test.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/expectations_go18_test.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/expectations_go18_test.go new file mode 100644 index 0000000..5f30d2f --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/expectations_go18_test.go @@ -0,0 +1,64 @@ +// +build go1.8 + +package sqlmock + +import ( + "database/sql" + "database/sql/driver" + "testing" +) + +func TestQueryExpectationNamedArgComparison(t *testing.T) { + e := &queryBasedExpectation{} + against := []namedValue{{Value: int64(5), Name: "id"}} + if err := e.argsMatches(against); err != nil { + t.Errorf("arguments should match, since the no expectation was set, but got err: %s", err) + } + + e.args = []driver.Value{ + sql.Named("id", 5), + sql.Named("s", "str"), + } + + if err := e.argsMatches(against); err == nil { + t.Error("arguments should not match, since the size is not the same") + } + + against = []namedValue{ + {Value: int64(5), Name: "id"}, + {Value: "str", Name: "s"}, + } + + if err := e.argsMatches(against); err != nil { + t.Errorf("arguments should have matched, but it did not: %v", err) + } + + against = []namedValue{ + {Value: int64(5), Name: "id"}, + {Value: "str", Name: "username"}, + } + + if err := e.argsMatches(against); err == nil { + t.Error("arguments matched, but it should have not due to Name") + } + + e.args = []driver.Value{int64(5), "str"} + + against = []namedValue{ + {Value: int64(5), Ordinal: 0}, + {Value: "str", Ordinal: 1}, + } + + if err := e.argsMatches(against); err == nil { + t.Error("arguments matched, but it should have not due to wrong Ordinal position") + } + + against = []namedValue{ + {Value: int64(5), Ordinal: 1}, + {Value: "str", Ordinal: 2}, + } + + if err := e.argsMatches(against); err != nil { + t.Errorf("arguments should have matched, but it did not: %v", err) + } +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/expectations_test.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/expectations_test.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/expectations_test.go new file mode 100644 index 0000000..2e3c097 --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/expectations_test.go @@ -0,0 +1,154 @@ +package sqlmock + +import ( + "database/sql/driver" + "fmt" + "regexp" + "testing" + "time" +) + +func TestQueryExpectationArgComparison(t *testing.T) { + e := &queryBasedExpectation{} + against := []namedValue{{Value: int64(5), Ordinal: 1}} + if err := e.argsMatches(against); err != nil { + t.Errorf("arguments should match, since the no expectation was set, but got err: %s", err) + } + + e.args = []driver.Value{5, "str"} + + against = []namedValue{{Value: int64(5), Ordinal: 1}} + if err := e.argsMatches(against); err == nil { + t.Error("arguments should not match, since the size is not the same") + } + + against = []namedValue{ + {Value: int64(3), Ordinal: 1}, + {Value: "str", Ordinal: 2}, + } + if err := e.argsMatches(against); err == nil { + t.Error("arguments should not match, since the first argument (int value) is different") + } + + against = []namedValue{ + {Value: int64(5), Ordinal: 1}, + {Value: "st", Ordinal: 2}, + } + if err := e.argsMatches(against); err == nil { + t.Error("arguments should not match, since the second argument (string value) is different") + } + + against = []namedValue{ + {Value: int64(5), Ordinal: 1}, + {Value: "str", Ordinal: 2}, + } + if err := e.argsMatches(against); err != nil { + t.Errorf("arguments should match, but it did not: %s", err) + } + + const longForm = "Jan 2, 2006 at 3:04pm (MST)" + tm, _ := time.Parse(longForm, "Feb 3, 2013 at 7:54pm (PST)") + e.args = []driver.Value{5, tm} + + against = []namedValue{ + {Value: int64(5), Ordinal: 1}, + {Value: tm, Ordinal: 2}, + } + if err := e.argsMatches(against); err != nil { + t.Error("arguments should match, but it did not") + } + + e.args = []driver.Value{5, AnyArg()} + if err := e.argsMatches(against); err != nil { + t.Errorf("arguments should match, but it did not: %s", err) + } +} + +func TestQueryExpectationArgComparisonBool(t *testing.T) { + var e *queryBasedExpectation + + e = &queryBasedExpectation{args: []driver.Value{true}} + against := []namedValue{ + {Value: true, Ordinal: 1}, + } + if err := e.argsMatches(against); err != nil { + t.Error("arguments should match, since arguments are the same") + } + + e = &queryBasedExpectation{args: []driver.Value{false}} + against = []namedValue{ + {Value: false, Ordinal: 1}, + } + if err := e.argsMatches(against); err != nil { + t.Error("arguments should match, since argument are the same") + } + + e = &queryBasedExpectation{args: []driver.Value{true}} + against = []namedValue{ + {Value: false, Ordinal: 1}, + } + if err := e.argsMatches(against); err == nil { + t.Error("arguments should not match, since argument is different") + } + + e = &queryBasedExpectation{args: []driver.Value{false}} + against = []namedValue{ + {Value: true, Ordinal: 1}, + } + if err := e.argsMatches(against); err == nil { + t.Error("arguments should not match, since argument is different") + } +} + +func TestQueryExpectationSqlMatch(t *testing.T) { + e := &ExpectedExec{} + + e.sqlRegex = regexp.MustCompile("SELECT x FROM") + if !e.queryMatches("SELECT x FROM someting") { + t.Errorf("Sql must have matched the query") + } + + e.sqlRegex = regexp.MustCompile("SELECT COUNT\\(x\\) FROM") + if !e.queryMatches("SELECT COUNT(x) FROM someting") { + t.Errorf("Sql must have matched the query") + } +} + +func ExampleExpectedExec() { + db, mock, _ := New() + result := NewErrorResult(fmt.Errorf("some error")) + mock.ExpectExec("^INSERT (.+)").WillReturnResult(result) + res, _ := db.Exec("INSERT something") + _, err := res.LastInsertId() + fmt.Println(err) + // Output: some error +} + +func TestBuildQuery(t *testing.T) { + db, mock, _ := New() + query := ` + SELECT + name, + email, + address, + anotherfield + FROM user + where + name = 'John' + and + address = 'Jakarta' + + ` + + mock.ExpectQuery(query) + mock.ExpectExec(query) + mock.ExpectPrepare(query) + + db.QueryRow(query) + db.Exec(query) + db.Prepare(query) + + if err := mock.ExpectationsWereMet(); err != nil { + t.Error(err) + } +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/result.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/result.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/result.go new file mode 100644 index 0000000..a63e72b --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/result.go @@ -0,0 +1,39 @@ +package sqlmock + +import ( + "database/sql/driver" +) + +// Result satisfies sql driver Result, which +// holds last insert id and rows affected +// by Exec queries +type result struct { + insertID int64 + rowsAffected int64 + err error +} + +// NewResult creates a new sql driver Result +// for Exec based query mocks. +func NewResult(lastInsertID int64, rowsAffected int64) driver.Result { + return &result{ + insertID: lastInsertID, + rowsAffected: rowsAffected, + } +} + +// NewErrorResult creates a new sql driver Result +// which returns an error given for both interface methods +func NewErrorResult(err error) driver.Result { + return &result{ + err: err, + } +} + +func (r *result) LastInsertId() (int64, error) { + return r.insertID, r.err +} + +func (r *result) RowsAffected() (int64, error) { + return r.rowsAffected, r.err +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/result_test.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/result_test.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/result_test.go new file mode 100644 index 0000000..08d47c9 --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/result_test.go @@ -0,0 +1,62 @@ +package sqlmock + +import ( + "fmt" + "testing" +) + +// used for examples +var mock = &sqlmock{} + +func ExampleNewErrorResult() { + db, mock, _ := New() + result := NewErrorResult(fmt.Errorf("some error")) + mock.ExpectExec("^INSERT (.+)").WillReturnResult(result) + res, _ := db.Exec("INSERT something") + _, err := res.LastInsertId() + fmt.Println(err) + // Output: some error +} + +func ExampleNewResult() { + var lastInsertID, affected int64 + result := NewResult(lastInsertID, affected) + mock.ExpectExec("^INSERT (.+)").WillReturnResult(result) + fmt.Println(mock.ExpectationsWereMet()) + // Output: there is a remaining expectation which was not matched: ExpectedExec => expecting Exec which: + // - matches sql: '^INSERT (.+)' + // - is without arguments + // - should return Result having: + // LastInsertId: 0 + // RowsAffected: 0 +} + +func TestShouldReturnValidSqlDriverResult(t *testing.T) { + result := NewResult(1, 2) + id, err := result.LastInsertId() + if 1 != id { + t.Errorf("Expected last insert id to be 1, but got: %d", id) + } + if err != nil { + t.Errorf("expected no error, but got: %s", err) + } + affected, err := result.RowsAffected() + if 2 != affected { + t.Errorf("Expected affected rows to be 2, but got: %d", affected) + } + if err != nil { + t.Errorf("expected no error, but got: %s", err) + } +} + +func TestShouldReturnErroeSqlDriverResult(t *testing.T) { + result := NewErrorResult(fmt.Errorf("some error")) + _, err := result.LastInsertId() + if err == nil { + t.Error("expected error, but got none") + } + _, err = result.RowsAffected() + if err == nil { + t.Error("expected error, but got none") + } +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/rows.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/rows.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/rows.go new file mode 100644 index 0000000..39f9f83 --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/rows.go @@ -0,0 +1,144 @@ +package sqlmock + +import ( + "database/sql/driver" + "encoding/csv" + "fmt" + "io" + "strings" +) + +// CSVColumnParser is a function which converts trimmed csv +// column string to a []byte representation. currently +// transforms NULL to nil +var CSVColumnParser = func(s string) []byte { + switch { + case strings.ToLower(s) == "null": + return nil + } + return []byte(s) +} + +type rowSets struct { + sets []*Rows + pos int +} + +func (rs *rowSets) Columns() []string { + return rs.sets[rs.pos].cols +} + +func (rs *rowSets) Close() error { + return rs.sets[rs.pos].closeErr +} + +// advances to next row +func (rs *rowSets) Next(dest []driver.Value) error { + r := rs.sets[rs.pos] + r.pos++ + if r.pos > len(r.rows) { + return io.EOF // per interface spec + } + + for i, col := range r.rows[r.pos-1] { + dest[i] = col + } + + return r.nextErr[r.pos-1] +} + +// transforms to debuggable printable string +func (rs *rowSets) String() string { + msg := "should return rows:\n" + if len(rs.sets) == 1 { + for n, row := range rs.sets[0].rows { + msg += fmt.Sprintf(" row %d - %+v\n", n, row) + } + return strings.TrimSpace(msg) + } + for i, set := range rs.sets { + msg += fmt.Sprintf(" result set: %d\n", i) + for n, row := range set.rows { + msg += fmt.Sprintf(" row %d - %+v\n", n, row) + } + } + return strings.TrimSpace(msg) +} + +// Rows is a mocked collection of rows to +// return for Query result +type Rows struct { + cols []string + rows [][]driver.Value + pos int + nextErr map[int]error + closeErr error +} + +// NewRows allows Rows to be created from a +// sql driver.Value slice or from the CSV string and +// to be used as sql driver.Rows +func NewRows(columns []string) *Rows { + return &Rows{cols: columns, nextErr: make(map[int]error)} +} + +// CloseError allows to set an error +// which will be returned by rows.Close +// function. +// +// The close error will be triggered only in cases +// when rows.Next() EOF was not yet reached, that is +// a default sql library behavior +func (r *Rows) CloseError(err error) *Rows { + r.closeErr = err + return r +} + +// RowError allows to set an error +// which will be returned when a given +// row number is read +func (r *Rows) RowError(row int, err error) *Rows { + r.nextErr[row] = err + return r +} + +// AddRow composed from database driver.Value slice +// return the same instance to perform subsequent actions. +// Note that the number of values must match the number +// of columns +func (r *Rows) AddRow(values ...driver.Value) *Rows { + if len(values) != len(r.cols) { + panic("Expected number of values to match number of columns") + } + + row := make([]driver.Value, len(r.cols)) + for i, v := range values { + row[i] = v + } + + r.rows = append(r.rows, row) + return r +} + +// FromCSVString build rows from csv string. +// return the same instance to perform subsequent actions. +// Note that the number of values must match the number +// of columns +func (r *Rows) FromCSVString(s string) *Rows { + res := strings.NewReader(strings.TrimSpace(s)) + csvReader := csv.NewReader(res) + + for { + res, err := csvReader.Read() + if err != nil || res == nil { + break + } + + row := make([]driver.Value, len(r.cols)) + for i, v := range res { + row[i] = CSVColumnParser(strings.TrimSpace(v)) + } + r.rows = append(r.rows, row) + } + return r +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/rows_go18.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/rows_go18.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/rows_go18.go new file mode 100644 index 0000000..4ecf84e --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/rows_go18.go @@ -0,0 +1,20 @@ +// +build go1.8 + +package sqlmock + +import "io" + +// Implement the "RowsNextResultSet" interface +func (rs *rowSets) HasNextResultSet() bool { + return rs.pos+1 < len(rs.sets) +} + +// Implement the "RowsNextResultSet" interface +func (rs *rowSets) NextResultSet() error { + if !rs.HasNextResultSet() { + return io.EOF + } + + rs.pos++ + return nil +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/rows_go18_test.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/rows_go18_test.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/rows_go18_test.go new file mode 100644 index 0000000..297e7c0 --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/rows_go18_test.go @@ -0,0 +1,92 @@ +// +build go1.8 + +package sqlmock + +import ( + "fmt" + "testing" +) + +func TestQueryMultiRows(t *testing.T) { + t.Parallel() + db, mock, err := New() + if err != nil { + t.Errorf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + rs1 := NewRows([]string{"id", "title"}).AddRow(5, "hello world") + rs2 := NewRows([]string{"name"}).AddRow("gopher").AddRow("john").AddRow("jane").RowError(2, fmt.Errorf("error")) + + mock.ExpectQuery("SELECT (.+) FROM articles WHERE id = \\?;SELECT name FROM users"). + WithArgs(5). + WillReturnRows(rs1, rs2) + + rows, err := db.Query("SELECT id, title FROM articles WHERE id = ?;SELECT name FROM users", 5) + if err != nil { + t.Errorf("error was not expected, but got: %v", err) + } + defer rows.Close() + + if !rows.Next() { + t.Error("expected a row to be available in first result set") + } + + var id int + var name string + + err = rows.Scan(&id, &name) + if err != nil { + t.Errorf("error was not expected, but got: %v", err) + } + + if id != 5 || name != "hello world" { + t.Errorf("unexpected row values id: %v name: %v", id, name) + } + + if rows.Next() { + t.Error("was not expecting next row in first result set") + } + + if !rows.NextResultSet() { + t.Error("had to have next result set") + } + + if !rows.Next() { + t.Error("expected a row to be available in second result set") + } + + err = rows.Scan(&name) + if err != nil { + t.Errorf("error was not expected, but got: %v", err) + } + + if name != "gopher" { + t.Errorf("unexpected row name: %v", name) + } + + if !rows.Next() { + t.Error("expected a row to be available in second result set") + } + + err = rows.Scan(&name) + if err != nil { + t.Errorf("error was not expected, but got: %v", err) + } + + if name != "john" { + t.Errorf("unexpected row name: %v", name) + } + + if rows.Next() { + t.Error("expected next row to produce error") + } + + if rows.Err() == nil { + t.Error("expected an error, but there was none") + } + + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expections: %s", err) + } +} http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/f9f7cfa0/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/rows_test.go ---------------------------------------------------------------------- diff --git a/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/rows_test.go b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/rows_test.go new file mode 100644 index 0000000..56e834e --- /dev/null +++ b/traffic_ops_golang/vendor/gopkg.in/DATA-DOG/go-sqlmock/rows_test.go @@ -0,0 +1,265 @@ +package sqlmock + +import ( + "database/sql" + "fmt" + "testing" +) + +func ExampleRows() { + db, mock, err := New() + if err != nil { + fmt.Println("failed to open sqlmock database:", err) + } + defer db.Close() + + rows := NewRows([]string{"id", "title"}). + AddRow(1, "one"). + AddRow(2, "two") + + mock.ExpectQuery("SELECT").WillReturnRows(rows) + + rs, _ := db.Query("SELECT") + defer rs.Close() + + for rs.Next() { + var id int + var title string + rs.Scan(&id, &title) + fmt.Println("scanned id:", id, "and title:", title) + } + + if rs.Err() != nil { + fmt.Println("got rows error:", rs.Err()) + } + // Output: scanned id: 1 and title: one + // scanned id: 2 and title: two +} + +func ExampleRows_rowError() { + db, mock, err := New() + if err != nil { + fmt.Println("failed to open sqlmock database:", err) + } + defer db.Close() + + rows := NewRows([]string{"id", "title"}). + AddRow(0, "one"). + AddRow(1, "two"). + RowError(1, fmt.Errorf("row error")) + mock.ExpectQuery("SELECT").WillReturnRows(rows) + + rs, _ := db.Query("SELECT") + defer rs.Close() + + for rs.Next() { + var id int + var title string + rs.Scan(&id, &title) + fmt.Println("scanned id:", id, "and title:", title) + } + + if rs.Err() != nil { + fmt.Println("got rows error:", rs.Err()) + } + // Output: scanned id: 0 and title: one + // got rows error: row error +} + +func ExampleRows_closeError() { + db, mock, err := New() + if err != nil { + fmt.Println("failed to open sqlmock database:", err) + } + defer db.Close() + + rows := NewRows([]string{"id", "title"}).CloseError(fmt.Errorf("close error")) + mock.ExpectQuery("SELECT").WillReturnRows(rows) + + rs, _ := db.Query("SELECT") + + // Note: that close will return error only before rows EOF + // that is a default sql package behavior. If you run rs.Next() + // it will handle the error internally and return nil bellow + if err := rs.Close(); err != nil { + fmt.Println("got error:", err) + } + + // Output: got error: close error +} + +func TestAllowsToSetRowsErrors(t *testing.T) { + t.Parallel() + db, mock, err := New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + rows := NewRows([]string{"id", "title"}). + AddRow(0, "one"). + AddRow(1, "two"). + RowError(1, fmt.Errorf("error")) + mock.ExpectQuery("SELECT").WillReturnRows(rows) + + rs, err := db.Query("SELECT") + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + defer rs.Close() + + if !rs.Next() { + t.Fatal("expected the first row to be available") + } + if rs.Err() != nil { + t.Fatalf("unexpected error: %s", rs.Err()) + } + + if rs.Next() { + t.Fatal("was not expecting the second row, since there should be an error") + } + if rs.Err() == nil { + t.Fatal("expected an error, but got none") + } + + if err := mock.ExpectationsWereMet(); err != nil { + t.Fatal(err) + } +} + +func TestRowsCloseError(t *testing.T) { + t.Parallel() + db, mock, err := New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + rows := NewRows([]string{"id"}).CloseError(fmt.Errorf("close error")) + mock.ExpectQuery("SELECT").WillReturnRows(rows) + + rs, err := db.Query("SELECT") + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + if err := rs.Close(); err == nil { + t.Fatal("expected a close error") + } + + if err := mock.ExpectationsWereMet(); err != nil { + t.Fatal(err) + } +} + +func TestQuerySingleRow(t *testing.T) { + t.Parallel() + db, mock, err := New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + rows := NewRows([]string{"id"}). + AddRow(1). + AddRow(2) + mock.ExpectQuery("SELECT").WillReturnRows(rows) + + var id int + if err := db.QueryRow("SELECT").Scan(&id); err != nil { + t.Fatalf("unexpected error: %s", err) + } + + mock.ExpectQuery("SELECT").WillReturnRows(NewRows([]string{"id"})) + if err := db.QueryRow("SELECT").Scan(&id); err != sql.ErrNoRows { + t.Fatal("expected sql no rows error") + } + + if err := mock.ExpectationsWereMet(); err != nil { + t.Fatal(err) + } +} + +func TestRowsScanError(t *testing.T) { + t.Parallel() + db, mock, err := New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + r := NewRows([]string{"col1", "col2"}).AddRow("one", "two").AddRow("one", nil) + mock.ExpectQuery("SELECT").WillReturnRows(r) + + rs, err := db.Query("SELECT") + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + defer rs.Close() + + var one, two string + if !rs.Next() || rs.Err() != nil || rs.Scan(&one, &two) != nil { + t.Fatal("unexpected error on first row scan") + } + + if !rs.Next() || rs.Err() != nil { + t.Fatal("unexpected error on second row read") + } + + err = rs.Scan(&one, &two) + if err == nil { + t.Fatal("expected an error for scan, but got none") + } + + if err := mock.ExpectationsWereMet(); err != nil { + t.Fatal(err) + } +} + +func TestCSVRowParser(t *testing.T) { + t.Parallel() + rs := NewRows([]string{"col1", "col2"}).FromCSVString("a,NULL") + db, mock, err := New() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) + } + defer db.Close() + + mock.ExpectQuery("SELECT").WillReturnRows(rs) + + rw, err := db.Query("SELECT") + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + defer rw.Close() + var col1 string + var col2 []byte + + rw.Next() + if err = rw.Scan(&col1, &col2); err != nil { + t.Fatalf("unexpected error: %s", err) + } + if col1 != "a" { + t.Fatalf("expected col1 to be 'a', but got [%T]:%+v", col1, col1) + } + if col2 != nil { + t.Fatalf("expected col2 to be nil, but got [%T]:%+v", col2, col2) + } +} + +func TestWrongNumberOfValues(t *testing.T) { + // Open new mock database + db, mock, err := New() + if err != nil { + fmt.Println("error creating mock database") + return + } + defer db.Close() + defer func() { + recover() + }() + mock.ExpectQuery("SELECT ID FROM TABLE").WithArgs(101).WillReturnRows(NewRows([]string{"ID"}).AddRow(101, "Hello")) + db.Query("SELECT ID FROM TABLE", 101) + // shouldn't reach here + t.Error("expected panic from query") +}