Newer
Older
Copyright (c) 2012-2014 José Carlos Nieto, https://menteslibres.net/xiam
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.
*/
/*
Tests for the mysql wrapper.
Execute the Makefile in ./_dumps/ to create the expected database structure.
cd _dumps
make
cd ..
go test
*/
const (
host = "testserver.local"
dbname = "upperio_tests"
username = "upperio"
password = "upperio"
)
// Global settings for tests.
var settings = db.Settings{
// Structure for testing conversions and datatypes.
Uint uint `field:"_uint"`
Uint8 uint8 `field:"_uint8"`
Uint16 uint16 `field:"_uint16"`
Uint32 uint32 `field:"_uint32"`
Uint64 uint64 `field:"_uint64"`
Int int `field:"_int"`
Int8 int8 `field:"_int8"`
Int16 int16 `field:"_int16"`
Int32 int32 `field:"_int32"`
Int64 int64 `field:"_int64"`
Float32 float32 `field:"_float32"`
Float64 float64 `field:"_float64"`
Bool bool `field:"_bool"`
String string `field:"_string"`
Date time.Time `field:"_date"`
Time time.Duration `field:"_time"`
// Declaring some values to insert, we expect the same values to be returned.
var testValues = testValuesStruct{
1, 1, 1, 1, 1,
-1, -1, -1, -1, -1,
1.337, 1.337,
true,
"Hello world!",
time.Date(2012, 7, 28, 1, 2, 3, 0, time.Local),
// Enabling outputting some information to stdout (like the SQL query and its
// arguments), useful for development.
func TestEnableDebug(t *testing.T) {
os.Setenv(db.EnvEnableDebug, "TRUE")
// Trying to open an empty datasource, it must fail.
_, err := db.Open(wrapperName, db.Settings{})
func TestTruncate(t *testing.T) {
// We should close the database when it's no longer in use.
defer sess.Close()
// Getting a list of all collections in this database.
collections, err := sess.Collections()
// Pointing the collection.
col, err := sess.Collection(name)
// Since this is a SQL collection (table), the structure must exists before
// we can use it.
exists := col.Exists()
if exists == true {
// Truncating the structure, if exists.
err = col.Truncate()
if err != nil {
// This test appends some data into the "artist" table.
func TestAppend(t *testing.T) {
var err error
var id interface{}
// Opening database.
// We should close the database when it's no longer in use.
defer sess.Close()
// Getting a pointer to the "artist" collection.
artist, err := sess.Collection("artist")
// Appending a map.
id, err = artist.Append(map[string]string{
"name": "Ozzie",
})
if to.Int64(id) == 0 {
t.Fatalf("Expecting an ID.")
// Appending a struct.
id, err = artist.Append(struct {
Name string `field:name`
}{
"Flea",
})
if to.Int64(id) == 0 {
t.Fatalf("Expecting an ID.")
// Appending a struct (using tags to specify the field name).
id, err = artist.Append(struct {
ArtistName string `field:"name"`
}{
"Slash",
})
if to.Int64(id) == 0 {
t.Fatalf("Expecting an ID.")
// This test tries to use an empty filter and count how many elements were
// added into the artist collection.
func TestResultCount(t *testing.T) {
// Opening database.
sess, err := db.Open(wrapperName, settings)
if err != nil {
// We should close the database when it's no longer in use.
artist, _ := sess.Collection("artist")
res = artist.Find()
// Counting all the matching rows.
total, err := res.Count()
if total == 0 {
t.Fatalf("Should not be empty, we've just added some rows!")
// This test uses and result and tries to fetch items one by one.
func TestResultFetch(t *testing.T) {
// We should close the database when it's no longer in use.
defer sess.Close()
José Carlos Nieto
committed
José Carlos Nieto
committed
res = artist.Find()
for {
err = res.Next(&row_m)
if err == db.ErrNoMoreRows {
// No more row_ms left.
break
}
if err == nil {
if to.Int64(row_m["id"]) == 0 {
t.Fatalf("Expecting a not null ID.")
}
if to.String(row_m["name"]) == "" {
t.Fatalf("Expecting a name.")
}
} else {
// Testing struct
row_s := struct {
Id uint64
Name string
}{}
res = artist.Find()
if err == db.ErrNoMoreRows {
// No more row_s' left.
break
}
if err == nil {
if row_s.Id == 0 {
t.Fatalf("Expecting a not null ID.")
}
if row_s.Name == "" {
t.Fatalf("Expecting a name.")
}
} else {
// Testing tagged struct
row_t := struct {
Value1 uint64 `field:"id"`
Value2 string `field:"name"`
res = artist.Find()
if err == db.ErrNoMoreRows {
// No more row_t's left.
break
}
if err == nil {
if row_t.Value1 == 0 {
t.Fatalf("Expecting a not null ID.")
}
if row_t.Value2 == "" {
t.Fatalf("Expecting a name.")
}
} else {
// Testing Result.All() with a slice of maps.
res = artist.Find()
all_rows_m := []map[string]interface{}{}
err = res.All(&all_rows_m)
for _, single_row_m := range all_rows_m {
if to.Int64(single_row_m["id"]) == 0 {
t.Fatalf("Expecting a not null ID.")
}
}
// Testing Result.All() with a slice of structs.
res = artist.Find()
all_rows_s := []struct {
Id uint64
Name string
}{}
err = res.All(&all_rows_s)
for _, single_row_s := range all_rows_s {
if single_row_s.Id == 0 {
t.Fatalf("Expecting a not null ID.")
}
// Testing Result.All() with a slice of tagged structs.
res = artist.Find()
all_rows_t := []struct {
Value1 uint64 `field:"id"`
Value2 string `field:"name"`
for _, single_row_t := range all_rows_t {
if single_row_t.Value1 == 0 {
t.Fatalf("Expecting a not null ID.")
}
// This test tries to update some previously added rows.
func TestUpdate(t *testing.T) {
sess, err := db.Open(wrapperName, settings)
if err != nil {
// We should close the database when it's no longer in use.
// Getting a pointer to the "artist" collection.
artist, err := sess.Collection("artist")
// Value
value := struct {
Id uint64
Name string
}{}
res := artist.Find(db.Cond{"id !=": 0}).Limit(1)
// Updating with a map
row_m := map[string]interface{}{
"name": strings.ToUpper(value.Name),
}
José Carlos Nieto
committed
}
if value.Name != row_m["name"] {
t.Fatalf("Expecting a modification.")
// Updating with a struct
row_s := struct {
Name string
}{strings.ToLower(value.Name)}
if value.Name != row_s.Name {
t.Fatalf("Expecting a modification.")
// Updating with a tagged struct
row_t := struct {
Value1 string `field:"name"`
}{strings.Replace(value.Name, "z", "Z", -1)}
José Carlos Nieto
committed
José Carlos Nieto
committed
}
if value.Name != row_t.Value1 {
t.Fatalf("Expecting a modification.")
José Carlos Nieto
committed
}
José Carlos Nieto
committed
// Test database functions
func TestFunction(t *testing.T) {
var err error
var res db.Result
// Opening database.
sess, err := db.Open(wrapperName, settings)
if err != nil {
}
// We should close the database when it's no longer in use.
defer sess.Close()
// Getting a pointer to the "artist" collection.
artist, err := sess.Collection("artist")
if err != nil {
}
row_s := struct {
Id uint64
Name string
}{}
res = artist.Find(db.Cond{"id NOT IN": []int{0, -1}})
if err = res.One(&row_s); err != nil {
t.Fatalf("One: %q", err)
}
res = artist.Find(db.Cond{"id": db.Func{"NOT IN", []int{0, -1}}})
if err = res.One(&row_s); err != nil {
t.Fatalf("One: %q", err)
}
res.Close()
}
// This test tries to remove some previously added rows.
func TestRemove(t *testing.T) {
José Carlos Nieto
committed
if err != nil {
José Carlos Nieto
committed
}
// We should close the database when it's no longer in use.
defer sess.Close()
// Getting a pointer to the "artist" collection.
artist, err := sess.Collection("artist")
res := artist.Find(db.Cond{"id": 1})
José Carlos Nieto
committed
// Trying to remove the row.
err = res.Remove()
José Carlos Nieto
committed
}
// This test tries to add many different datatypes to a single row in a
// collection, then it tries to get the stored datatypes and check if the
// stored and the original values match.
// We should close the database when it's no longer in use.
defer sess.Close()
// Getting a pointer to the "data_types" collection.
dataTypes, err := sess.Collection("data_types")
dataTypes.Truncate()
// Appending our test subject.
id, err := dataTypes.Append(testValues)
res = dataTypes.Find(db.Cond{"id": id})
exists, err := res.Count()
if err != nil {
if exists == 0 {
t.Errorf("Expecting an item.")
}
// Trying to dump the subject into an empty structure of the same type.
var item testValuesStruct
res.One(&item)
// The original value and the test subject must match.
if reflect.DeepEqual(item, testValues) == false {
t.Errorf("Struct is different.")
// We are going to benchmark the engine, so this is no longed needed.
func TestDisableDebug(t *testing.T) {
os.Setenv(db.EnvEnableDebug, "")
// Benchmarking raw database/sql.
func BenchmarkAppendRaw(b *testing.B) {
sess, err := db.Open(wrapperName, settings)
artist, err := sess.Collection("artist")
artist.Truncate()
driver := sess.Driver().(*sql.DB)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := driver.Exec(`INSERT INTO artist (name) VALUES('Hayao Miyazaki')`)
if err != nil {
// Benchmarking Append().
//
// Contributed by wei2912
// See: https://github.com/gosexy/db/issues/20#issuecomment-20097801
func BenchmarkAppendDbItem(b *testing.B) {
sess, err := db.Open(wrapperName, settings)
artist, err := sess.Collection("artist")
artist.Truncate()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err = artist.Append(map[string]string{"name": "Leonardo DaVinci"})
if err != nil {
}
}
}
// Benchmarking Append() with transactions.
//
// Contributed by wei2912
// See: https://github.com/gosexy/db/issues/20#issuecomment-20167939
// Applying the BEGIN and END transaction optimizations.
func BenchmarkAppendDbItem_Transaction(b *testing.B) {
sess, err := db.Open(wrapperName, settings)
defer sess.Close()
artist, err := sess.Collection("artist")
artist.Truncate()
_, err = artist.Append(map[string]string{"name": "Isaac Asimov"})
}
}
// Benchmarking Append with a struct.
func BenchmarkAppendStruct(b *testing.B) {
sess, err := db.Open(wrapperName, settings)
if err != nil {
defer sess.Close()
artist, err := sess.Collection("artist")
artist.Truncate()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err = artist.Append(struct{ Name string }{"John Lennon"})
if err != nil {