/drivertest/drivertest.go
Go | 305 lines | 234 code | 15 blank | 56 comment | 80 complexity | 9aaaf41d23aeabd2a9591fb0ae611b49 MD5 | raw file
- /*****************************************************************************************
- * Copyright (c) 2016 Christopher Eaton
- * https://github.com/chriseaton/malk-storage
- * This source code is subject to the terms of the the Universal Permissive License v1.0.
- ****************************************************************************************/
- package drivertest
- import (
- "fmt"
- "github.com/stretchr/testify/assert"
- "gitlab.com/chriseaton/malk-storage"
- "math/rand"
- "testing"
- "time"
- )
- // Primary model for testing. This model is meant to expose fields of all types supported by Malk.
- type PrimaryModel struct {
- storage.BaseModel
- FieldBool bool
- FieldString string
- FieldInt int
- FieldInt8 int8
- FieldInt16 int16
- FieldInt32 int32
- FieldInt64 int64
- FieldUint uint
- FieldUint8 uint8
- FieldUint16 uint16
- FieldUint32 uint32
- FieldUint64 uint64
- FieldFloat32 float32
- FieldFloat64 float64
- Sub SecondaryModel
- }
- // Secondary model for testing
- type SecondaryModel struct {
- storage.BaseModel
- RandomNumber int32
- Name string
- }
- // Creates a primary model (used only for testing) with random values for all fields.
- func CreatePrimaryModel(r *rand.Rand) *PrimaryModel {
- return &PrimaryModel{
- FieldBool: (r.Intn(2) == 1),
- FieldString: randomString(r, 4, 12),
- FieldInt: r.Intn(2),
- FieldInt8: int8(r.Int31n(255) - 128),
- FieldInt16: int16(r.Int31n(32767)),
- FieldInt32: r.Int31(),
- FieldInt64: r.Int63(),
- FieldUint: uint(r.Intn(2)),
- FieldUint8: uint8(r.Int31n(255)),
- FieldUint16: uint16(r.Int31n(32767)),
- FieldUint32: r.Uint32(),
- FieldUint64: uint64(r.Int63()),
- FieldFloat32: r.Float32(),
- FieldFloat64: r.Float64(),
- Sub: *CreateSecondaryModel(r),
- }
- }
- // Creates a secondary model with random values for all fields. The secondary model is not registered with an
- // entity, but is used as a sub-struct on the primary model.
- func CreateSecondaryModel(r *rand.Rand) *SecondaryModel {
- return &SecondaryModel{
- RandomNumber: r.Int31(),
- Name: randomString(r, 4, 12),
- }
- }
- // Creates a random string between min and max length. Contains only A-z and 0-9 characters.
- func randomString(r *rand.Rand, minLen, maxLen uint16) string {
- strlen := minLen + uint16(r.Intn(int(maxLen-minLen)))
- result := ""
- for i := uint16(0); i < strlen; i++ {
- choice := r.Intn(3)
- if choice == 0 { //number
- result += string(48 + rand.Intn(10))
- } else if choice == 1 { //lower letter
- result += string(97 + rand.Intn(24))
- } else if choice == 2 { //upper letter
- result += string(65 + rand.Intn(24))
- }
- }
- return string(result)
- }
- // Tests all the storage driver interface functions sequentially.
- func Run(d storage.Driver, t *testing.T) {
- //configure driver
- reg := &storage.Registry{}
- err := reg.Add("Primary", func() storage.Model { return &PrimaryModel{} })
- if err != nil {
- t.Errorf("Error adding model to registry. Error: %s", err)
- return
- }
- err = d.Configure(nil, reg)
- if err != nil {
- t.Errorf("Error configuring driver. Error: %s", err)
- return
- }
- //run the tests
- if DriverTestSave(d, t) {
- if DriverTestGet(d, t) {
- if DriverTestExists(d, t) {
- if DriverTestQuery(d, t) {
- if DriverTestDelete(d, t) {
- if DriverTestTruncate(d, t) {
- DriverTestCycle(d, t)
- }
- }
- }
- }
- }
- }
- }
- // Creates test models with randomized values, then stores them through the driver's "Save" and "SaveAll" functions.
- // All save functions and results are tested.
- func DriverTestSave(d storage.Driver, t *testing.T) bool {
- r := rand.New(rand.NewSource(time.Now().UnixNano()))
- ok := true
- // create test models
- m1 := CreatePrimaryModel(r)
- m1.SetID(uint64(1))
- m1.FieldBool = true
- m1.FieldString = "The quick brown fox."
- m1.FieldInt8 = int8(95)
- m2 := CreatePrimaryModel(r)
- m2.FieldBool = false
- m2.FieldString = "Jumped over the lazy dog."
- m2.FieldInt8 = int8(105)
- m3 := CreateSecondaryModel(r)
- //test save with ID
- id, err := d.Save("Primary", m1)
- ok = ok && assert.NoError(t, err, "Should not return an error when saving a valid model.")
- ok = ok && assert.Equal(t, uint64(1), id, "Saved model should have an ID == 1.")
- //test second save w/o ID
- id, err = d.Save("Primary", m2)
- ok = ok && assert.NoError(t, err, "Should not return an error when saving a valid model.")
- ok = ok && assert.True(t, id > uint64(1), "ID of saved model should be more than 1.")
- //test save with invalid entity
- id, err = d.Save("invalid", m1)
- ok = ok && assert.Error(t, err, "Expected error when trying to save a model to an invalid entity.")
- //test save with an invalid model
- id, err = d.Save("Primary", m3)
- ok = ok && assert.Error(t, err, "Expected error when trying to save an invalid model for an entity.")
- err = d.SaveAll("Primary", m1, m2)
- ok = ok && assert.NoError(t, err, "Should not return an error when saving multiple valid models.")
- //test save multiple with invalid entity
- err = d.SaveAll("invalid", m1, m2)
- ok = ok && assert.Error(t, err, "Expected error when trying to save multiple models to an invalid entity.")
- //test save multiple with invalid models
- id, err = d.Save("Primary", m3)
- ok = ok && assert.Error(t, err, "Expected error when trying to save invalid models for an entity.")
- //generate additional test models
- if ok {
- //generate extra models for a total of 20
- for i := 0; i < 18; i++ {
- _, err := d.Save("Primary", CreatePrimaryModel(r))
- ok = ok && assert.NoError(t, err, "Error generating additional test models.")
- }
- }
- return ok
- }
- // Tests the driver's ability to retrieve models through the "Get" and "GetAll" functions.
- // All get functions and results are tested.
- func DriverTestGet(d storage.Driver, t *testing.T) bool {
- ok := true
- //test get call for an existing model
- m1, err := d.Get("Primary", 1)
- ok = ok && assert.NoError(t, err, "Get should not return an error when arguments are valid.")
- ok = ok && assert.NotNil(t, m1, "A model should be returned and not nil when the ID is valid.")
- if m1 != nil {
- ok = ok && assert.Equal(t, uint64(1), m1.ID(), "Getting a model returned a model with a unexpected ID.")
- }
- //test call with invalid entity
- m1, err = d.Get("invalid", 1)
- ok = ok && assert.Error(t, err, "Expected error when trying to get a model to an invalid entity.")
- //test call with non-existant id
- m1, err = d.Get("Primary", 100000)
- ok = ok && assert.NoError(t, err, "Requesting a get on an ID that doesn't exist should not return an error.")
- ok = ok && assert.Nil(t, m1, "Expected the model returned from a get for an ID that doesn't exist would return nil.")
- //test get multiple existing models
- ms, err := d.GetAll("Primary", 1, 2, 3, 4)
- ok = ok && assert.NoError(t, err, "GetAll should not return an error when arguments are valid.")
- ok = ok && assert.NotNil(t, ms, "A slice of models should be returned when the IDs are valid.")
- ok = ok && assert.True(t, len(ms) == 4, "An incorrect number of models was returned when calling GetAll with IDs.")
- //test get multiple models with invalid records
- ms, err = d.GetAll("Primary", 1, 2, 30000, 4)
- ok = ok && assert.NoError(t, err, "GetAll should not return an error when arguments are valid, even if an ID is not present.")
- ok = ok && assert.NotNil(t, ms, "A slice of models should be returned when the IDs are valid.")
- ok = ok && assert.True(t, len(ms) == 4, "An incorrect number of models was returned when calling GetAll with IDs.")
- ms, err = d.GetAll("invalid", 1, 2, 3)
- ok = ok && assert.Error(t, err, "Expected error when trying to get models with an invalid entity.")
- return ok
- }
- // Tests the driver's function to check for existing models through the "Exists" function.
- // The exist call and it's results are tested.
- func DriverTestExists(d storage.Driver, t *testing.T) bool {
- ok := true
- //test exists call for valid ids
- c, err := d.Exists("Primary", 1, 2)
- ok = ok && assert.NoError(t, err, "Exist should not return an error when arguments are valid.")
- ok = ok && assert.True(t, c, "Exists expected to return true when all IDs are valid.")
- //test exists call for some valid and invalid ids
- c, err = d.Exists("Primary", 1, 2, 243, 8)
- ok = ok && assert.NoError(t, err, "Exist should not return an error when arguments are valid.")
- ok = ok && assert.False(t, c, "Exists expected to return false when some IDs are missing.")
- //test exists call for invalid ids
- c, err = d.Exists("Primary", 150, 220, 138)
- ok = ok && assert.NoError(t, err, "Exist should not return an error when arguments are valid.")
- ok = ok && assert.False(t, c, "Exists expected to return false when all IDs are missing.")
- //test exists call for entity that is not registered
- c, err = d.Exists("invalid", 1)
- ok = ok && assert.Error(t, err, "Exists should throw an error when an invalid entity is provided as an argument.")
- ok = ok && assert.False(t, c, "Exists should return false when an invalid entity is provided as an argument.")
- return ok
- }
- // Tests the driver's function to query models through the "Query" and "QueryFields" functions.
- // All query functions and results are tested.
- func DriverTestQuery(d storage.Driver, t *testing.T) bool {
- ok := true
- q := &storage.Query{Entity: "Primary"}
- q.Condition("ID", ">=", uint64(2))
- m, err := d.Query(q)
- ok = ok && assert.NoError(t, err, "Query should not return an error when arguments are valid.")
- ok = ok && assert.NotEmpty(t, m, "Query should return at least one model with the given conditions, but none were returned.")
- if len(m) > 0 {
- for _, v := range m {
- ok = ok && assert.IsType(t, &PrimaryModel{}, v, "Expected Query to return models of type *PrimaryModel.")
- ok = ok && assert.True(t, v.ID() >= uint64(2), "Query returned entities that didn't meet the query criteria of ID >= 2.")
- }
- }
- if ok {
- //test additional condition (and)
- q.RootCondition.And("FieldInt8", ">", int8(100))
- m, err := d.Query(q)
- ok = ok && assert.NoError(t, err, "Query should not return an error when arguments are valid.")
- ok = ok && assert.NotEmpty(t, m, "Query should return at least one model with the given conditions, but none were returned.")
- if len(m) > 0 {
- for _, v := range m {
- pm := v.(*PrimaryModel)
- ok = ok && assert.True(t, v.ID() >= uint64(2), "Query returned entities that didn't meet the query criteria of ID >= 2.")
- ok = ok && assert.True(t, pm.FieldInt8 > int8(100), "Query returned entities that didn't meet the query criteria of fieldInt8 > 100.")
- }
- }
- }
- //test query for specific fields
- //TODO
- return ok
- }
- // Tests the driver's function to delete models through the "Delete" and "DeleteAll" functions.
- // All delete functions and results are tested.
- func DriverTestDelete(d storage.Driver, t *testing.T) bool {
- ok := true
- //test delete of model
- c, err := d.Delete("Primary", 1)
- ok = ok && assert.NoError(t, err, "Delete should not return an error when arguments are valid.")
- ok = ok && assert.True(t, c, "Delete expected to return true when the ID passed is for a valid, existing model.")
- //test delete model that was just deleted
- c, err = d.Delete("Primary", 1)
- ok = ok && assert.NoError(t, err, "Delete should not return an error when arguments are valid.")
- ok = ok && assert.False(t, c, "Delete expected to return false when the ID passed is for missing model.")
- //test delete with invalid entity
- c, err = d.Delete("invalid", 1)
- ok = ok && assert.Error(t, err, "Delete should return an error when an invalid entity is specified as an argument.")
- ok = ok && assert.False(t, c, "Delete expected to return false when an invalid entity is specified as an argument.")
- //test delete several models at once
- err = d.DeleteAll("Primary", 2, 3)
- ok = ok && assert.NoError(t, err, "DeleteAll should not return an error when arguments are valid.")
- //test delete all with invalid entity
- err = d.DeleteAll("invalid", 1, 2, 3)
- ok = ok && assert.Error(t, err, "DeleteAll should return an error when an invalid entity is specified as an argument.")
- return ok
- }
- // Tests the driver's function to query models through the "Truncate" function.
- // The truncate function and it's results are tested.
- func DriverTestTruncate(d storage.Driver, t *testing.T) bool {
- ok := true
- //test truncate
- err := d.Truncate("Primary")
- ok = ok && assert.NoError(t, err, "Truncate should not return an error when arguments are valid.")
- //test delete with invalid entity
- err = d.Truncate("invalid")
- ok = ok && assert.Error(t, err, "Truncate should return an error when an invalid entity is specified as an argument.")
- return ok
- }
- // Final test that validates a saved model's field values. After the model is saved, it should be retrieved with the
- // exact same values from Get* and Query* methods.
- func DriverTestCycle(d storage.Driver, t *testing.T) bool {
- ok := true
- fmt.Printf("")
- return ok
- }