PageRenderTime 4910ms CodeModel.GetById 45ms RepoModel.GetById 1ms app.codeStats 0ms

/drivertest/drivertest.go

https://gitlab.com/chriseaton/malk-storage
Go | 305 lines | 234 code | 15 blank | 56 comment | 80 complexity | 9aaaf41d23aeabd2a9591fb0ae611b49 MD5 | raw file
  1. /*****************************************************************************************
  2. * Copyright (c) 2016 Christopher Eaton
  3. * https://github.com/chriseaton/malk-storage
  4. * This source code is subject to the terms of the the Universal Permissive License v1.0.
  5. ****************************************************************************************/
  6. package drivertest
  7. import (
  8. "fmt"
  9. "github.com/stretchr/testify/assert"
  10. "gitlab.com/chriseaton/malk-storage"
  11. "math/rand"
  12. "testing"
  13. "time"
  14. )
  15. // Primary model for testing. This model is meant to expose fields of all types supported by Malk.
  16. type PrimaryModel struct {
  17. storage.BaseModel
  18. FieldBool bool
  19. FieldString string
  20. FieldInt int
  21. FieldInt8 int8
  22. FieldInt16 int16
  23. FieldInt32 int32
  24. FieldInt64 int64
  25. FieldUint uint
  26. FieldUint8 uint8
  27. FieldUint16 uint16
  28. FieldUint32 uint32
  29. FieldUint64 uint64
  30. FieldFloat32 float32
  31. FieldFloat64 float64
  32. Sub SecondaryModel
  33. }
  34. // Secondary model for testing
  35. type SecondaryModel struct {
  36. storage.BaseModel
  37. RandomNumber int32
  38. Name string
  39. }
  40. // Creates a primary model (used only for testing) with random values for all fields.
  41. func CreatePrimaryModel(r *rand.Rand) *PrimaryModel {
  42. return &PrimaryModel{
  43. FieldBool: (r.Intn(2) == 1),
  44. FieldString: randomString(r, 4, 12),
  45. FieldInt: r.Intn(2),
  46. FieldInt8: int8(r.Int31n(255) - 128),
  47. FieldInt16: int16(r.Int31n(32767)),
  48. FieldInt32: r.Int31(),
  49. FieldInt64: r.Int63(),
  50. FieldUint: uint(r.Intn(2)),
  51. FieldUint8: uint8(r.Int31n(255)),
  52. FieldUint16: uint16(r.Int31n(32767)),
  53. FieldUint32: r.Uint32(),
  54. FieldUint64: uint64(r.Int63()),
  55. FieldFloat32: r.Float32(),
  56. FieldFloat64: r.Float64(),
  57. Sub: *CreateSecondaryModel(r),
  58. }
  59. }
  60. // Creates a secondary model with random values for all fields. The secondary model is not registered with an
  61. // entity, but is used as a sub-struct on the primary model.
  62. func CreateSecondaryModel(r *rand.Rand) *SecondaryModel {
  63. return &SecondaryModel{
  64. RandomNumber: r.Int31(),
  65. Name: randomString(r, 4, 12),
  66. }
  67. }
  68. // Creates a random string between min and max length. Contains only A-z and 0-9 characters.
  69. func randomString(r *rand.Rand, minLen, maxLen uint16) string {
  70. strlen := minLen + uint16(r.Intn(int(maxLen-minLen)))
  71. result := ""
  72. for i := uint16(0); i < strlen; i++ {
  73. choice := r.Intn(3)
  74. if choice == 0 { //number
  75. result += string(48 + rand.Intn(10))
  76. } else if choice == 1 { //lower letter
  77. result += string(97 + rand.Intn(24))
  78. } else if choice == 2 { //upper letter
  79. result += string(65 + rand.Intn(24))
  80. }
  81. }
  82. return string(result)
  83. }
  84. // Tests all the storage driver interface functions sequentially.
  85. func Run(d storage.Driver, t *testing.T) {
  86. //configure driver
  87. reg := &storage.Registry{}
  88. err := reg.Add("Primary", func() storage.Model { return &PrimaryModel{} })
  89. if err != nil {
  90. t.Errorf("Error adding model to registry. Error: %s", err)
  91. return
  92. }
  93. err = d.Configure(nil, reg)
  94. if err != nil {
  95. t.Errorf("Error configuring driver. Error: %s", err)
  96. return
  97. }
  98. //run the tests
  99. if DriverTestSave(d, t) {
  100. if DriverTestGet(d, t) {
  101. if DriverTestExists(d, t) {
  102. if DriverTestQuery(d, t) {
  103. if DriverTestDelete(d, t) {
  104. if DriverTestTruncate(d, t) {
  105. DriverTestCycle(d, t)
  106. }
  107. }
  108. }
  109. }
  110. }
  111. }
  112. }
  113. // Creates test models with randomized values, then stores them through the driver's "Save" and "SaveAll" functions.
  114. // All save functions and results are tested.
  115. func DriverTestSave(d storage.Driver, t *testing.T) bool {
  116. r := rand.New(rand.NewSource(time.Now().UnixNano()))
  117. ok := true
  118. // create test models
  119. m1 := CreatePrimaryModel(r)
  120. m1.SetID(uint64(1))
  121. m1.FieldBool = true
  122. m1.FieldString = "The quick brown fox."
  123. m1.FieldInt8 = int8(95)
  124. m2 := CreatePrimaryModel(r)
  125. m2.FieldBool = false
  126. m2.FieldString = "Jumped over the lazy dog."
  127. m2.FieldInt8 = int8(105)
  128. m3 := CreateSecondaryModel(r)
  129. //test save with ID
  130. id, err := d.Save("Primary", m1)
  131. ok = ok && assert.NoError(t, err, "Should not return an error when saving a valid model.")
  132. ok = ok && assert.Equal(t, uint64(1), id, "Saved model should have an ID == 1.")
  133. //test second save w/o ID
  134. id, err = d.Save("Primary", m2)
  135. ok = ok && assert.NoError(t, err, "Should not return an error when saving a valid model.")
  136. ok = ok && assert.True(t, id > uint64(1), "ID of saved model should be more than 1.")
  137. //test save with invalid entity
  138. id, err = d.Save("invalid", m1)
  139. ok = ok && assert.Error(t, err, "Expected error when trying to save a model to an invalid entity.")
  140. //test save with an invalid model
  141. id, err = d.Save("Primary", m3)
  142. ok = ok && assert.Error(t, err, "Expected error when trying to save an invalid model for an entity.")
  143. err = d.SaveAll("Primary", m1, m2)
  144. ok = ok && assert.NoError(t, err, "Should not return an error when saving multiple valid models.")
  145. //test save multiple with invalid entity
  146. err = d.SaveAll("invalid", m1, m2)
  147. ok = ok && assert.Error(t, err, "Expected error when trying to save multiple models to an invalid entity.")
  148. //test save multiple with invalid models
  149. id, err = d.Save("Primary", m3)
  150. ok = ok && assert.Error(t, err, "Expected error when trying to save invalid models for an entity.")
  151. //generate additional test models
  152. if ok {
  153. //generate extra models for a total of 20
  154. for i := 0; i < 18; i++ {
  155. _, err := d.Save("Primary", CreatePrimaryModel(r))
  156. ok = ok && assert.NoError(t, err, "Error generating additional test models.")
  157. }
  158. }
  159. return ok
  160. }
  161. // Tests the driver's ability to retrieve models through the "Get" and "GetAll" functions.
  162. // All get functions and results are tested.
  163. func DriverTestGet(d storage.Driver, t *testing.T) bool {
  164. ok := true
  165. //test get call for an existing model
  166. m1, err := d.Get("Primary", 1)
  167. ok = ok && assert.NoError(t, err, "Get should not return an error when arguments are valid.")
  168. ok = ok && assert.NotNil(t, m1, "A model should be returned and not nil when the ID is valid.")
  169. if m1 != nil {
  170. ok = ok && assert.Equal(t, uint64(1), m1.ID(), "Getting a model returned a model with a unexpected ID.")
  171. }
  172. //test call with invalid entity
  173. m1, err = d.Get("invalid", 1)
  174. ok = ok && assert.Error(t, err, "Expected error when trying to get a model to an invalid entity.")
  175. //test call with non-existant id
  176. m1, err = d.Get("Primary", 100000)
  177. ok = ok && assert.NoError(t, err, "Requesting a get on an ID that doesn't exist should not return an error.")
  178. ok = ok && assert.Nil(t, m1, "Expected the model returned from a get for an ID that doesn't exist would return nil.")
  179. //test get multiple existing models
  180. ms, err := d.GetAll("Primary", 1, 2, 3, 4)
  181. ok = ok && assert.NoError(t, err, "GetAll should not return an error when arguments are valid.")
  182. ok = ok && assert.NotNil(t, ms, "A slice of models should be returned when the IDs are valid.")
  183. ok = ok && assert.True(t, len(ms) == 4, "An incorrect number of models was returned when calling GetAll with IDs.")
  184. //test get multiple models with invalid records
  185. ms, err = d.GetAll("Primary", 1, 2, 30000, 4)
  186. ok = ok && assert.NoError(t, err, "GetAll should not return an error when arguments are valid, even if an ID is not present.")
  187. ok = ok && assert.NotNil(t, ms, "A slice of models should be returned when the IDs are valid.")
  188. ok = ok && assert.True(t, len(ms) == 4, "An incorrect number of models was returned when calling GetAll with IDs.")
  189. ms, err = d.GetAll("invalid", 1, 2, 3)
  190. ok = ok && assert.Error(t, err, "Expected error when trying to get models with an invalid entity.")
  191. return ok
  192. }
  193. // Tests the driver's function to check for existing models through the "Exists" function.
  194. // The exist call and it's results are tested.
  195. func DriverTestExists(d storage.Driver, t *testing.T) bool {
  196. ok := true
  197. //test exists call for valid ids
  198. c, err := d.Exists("Primary", 1, 2)
  199. ok = ok && assert.NoError(t, err, "Exist should not return an error when arguments are valid.")
  200. ok = ok && assert.True(t, c, "Exists expected to return true when all IDs are valid.")
  201. //test exists call for some valid and invalid ids
  202. c, err = d.Exists("Primary", 1, 2, 243, 8)
  203. ok = ok && assert.NoError(t, err, "Exist should not return an error when arguments are valid.")
  204. ok = ok && assert.False(t, c, "Exists expected to return false when some IDs are missing.")
  205. //test exists call for invalid ids
  206. c, err = d.Exists("Primary", 150, 220, 138)
  207. ok = ok && assert.NoError(t, err, "Exist should not return an error when arguments are valid.")
  208. ok = ok && assert.False(t, c, "Exists expected to return false when all IDs are missing.")
  209. //test exists call for entity that is not registered
  210. c, err = d.Exists("invalid", 1)
  211. ok = ok && assert.Error(t, err, "Exists should throw an error when an invalid entity is provided as an argument.")
  212. ok = ok && assert.False(t, c, "Exists should return false when an invalid entity is provided as an argument.")
  213. return ok
  214. }
  215. // Tests the driver's function to query models through the "Query" and "QueryFields" functions.
  216. // All query functions and results are tested.
  217. func DriverTestQuery(d storage.Driver, t *testing.T) bool {
  218. ok := true
  219. q := &storage.Query{Entity: "Primary"}
  220. q.Condition("ID", ">=", uint64(2))
  221. m, err := d.Query(q)
  222. ok = ok && assert.NoError(t, err, "Query should not return an error when arguments are valid.")
  223. ok = ok && assert.NotEmpty(t, m, "Query should return at least one model with the given conditions, but none were returned.")
  224. if len(m) > 0 {
  225. for _, v := range m {
  226. ok = ok && assert.IsType(t, &PrimaryModel{}, v, "Expected Query to return models of type *PrimaryModel.")
  227. ok = ok && assert.True(t, v.ID() >= uint64(2), "Query returned entities that didn't meet the query criteria of ID >= 2.")
  228. }
  229. }
  230. if ok {
  231. //test additional condition (and)
  232. q.RootCondition.And("FieldInt8", ">", int8(100))
  233. m, err := d.Query(q)
  234. ok = ok && assert.NoError(t, err, "Query should not return an error when arguments are valid.")
  235. ok = ok && assert.NotEmpty(t, m, "Query should return at least one model with the given conditions, but none were returned.")
  236. if len(m) > 0 {
  237. for _, v := range m {
  238. pm := v.(*PrimaryModel)
  239. ok = ok && assert.True(t, v.ID() >= uint64(2), "Query returned entities that didn't meet the query criteria of ID >= 2.")
  240. ok = ok && assert.True(t, pm.FieldInt8 > int8(100), "Query returned entities that didn't meet the query criteria of fieldInt8 > 100.")
  241. }
  242. }
  243. }
  244. //test query for specific fields
  245. //TODO
  246. return ok
  247. }
  248. // Tests the driver's function to delete models through the "Delete" and "DeleteAll" functions.
  249. // All delete functions and results are tested.
  250. func DriverTestDelete(d storage.Driver, t *testing.T) bool {
  251. ok := true
  252. //test delete of model
  253. c, err := d.Delete("Primary", 1)
  254. ok = ok && assert.NoError(t, err, "Delete should not return an error when arguments are valid.")
  255. ok = ok && assert.True(t, c, "Delete expected to return true when the ID passed is for a valid, existing model.")
  256. //test delete model that was just deleted
  257. c, err = d.Delete("Primary", 1)
  258. ok = ok && assert.NoError(t, err, "Delete should not return an error when arguments are valid.")
  259. ok = ok && assert.False(t, c, "Delete expected to return false when the ID passed is for missing model.")
  260. //test delete with invalid entity
  261. c, err = d.Delete("invalid", 1)
  262. ok = ok && assert.Error(t, err, "Delete should return an error when an invalid entity is specified as an argument.")
  263. ok = ok && assert.False(t, c, "Delete expected to return false when an invalid entity is specified as an argument.")
  264. //test delete several models at once
  265. err = d.DeleteAll("Primary", 2, 3)
  266. ok = ok && assert.NoError(t, err, "DeleteAll should not return an error when arguments are valid.")
  267. //test delete all with invalid entity
  268. err = d.DeleteAll("invalid", 1, 2, 3)
  269. ok = ok && assert.Error(t, err, "DeleteAll should return an error when an invalid entity is specified as an argument.")
  270. return ok
  271. }
  272. // Tests the driver's function to query models through the "Truncate" function.
  273. // The truncate function and it's results are tested.
  274. func DriverTestTruncate(d storage.Driver, t *testing.T) bool {
  275. ok := true
  276. //test truncate
  277. err := d.Truncate("Primary")
  278. ok = ok && assert.NoError(t, err, "Truncate should not return an error when arguments are valid.")
  279. //test delete with invalid entity
  280. err = d.Truncate("invalid")
  281. ok = ok && assert.Error(t, err, "Truncate should return an error when an invalid entity is specified as an argument.")
  282. return ok
  283. }
  284. // Final test that validates a saved model's field values. After the model is saved, it should be retrieved with the
  285. // exact same values from Get* and Query* methods.
  286. func DriverTestCycle(d storage.Driver, t *testing.T) bool {
  287. ok := true
  288. fmt.Printf("")
  289. return ok
  290. }