github.com/mmatczuk/gohan@v0.0.0-20170206152520-30e45d9bdb69/db/db_test.go (about) 1 // Copyright (C) 2015 NTT Innovation Institute, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 // implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 package db_test 17 18 import ( 19 "os" 20 21 "github.com/cloudwan/gohan/db" 22 "github.com/cloudwan/gohan/db/transaction" 23 "github.com/cloudwan/gohan/schema" 24 "github.com/cloudwan/gohan/util" 25 . "github.com/onsi/ginkgo" 26 . "github.com/onsi/gomega" 27 ) 28 29 var _ = Describe("Database operation test", func() { 30 var ( 31 err error 32 ok bool 33 34 conn string 35 dbType string 36 37 manager *schema.Manager 38 networkSchema *schema.Schema 39 serverSchema *schema.Schema 40 networkResource1 *schema.Resource 41 networkResource2 *schema.Resource 42 subnetResource *schema.Resource 43 serverResource *schema.Resource 44 45 dataStore db.DB 46 ) 47 48 BeforeEach(func() { 49 manager = schema.GetManager() 50 Expect(manager.LoadSchemaFromFile("../etc/schema/gohan.json")).To(Succeed()) 51 }) 52 53 AfterEach(func() { 54 schema.ClearManager() 55 if os.Getenv("MYSQL_TEST") != "true" { 56 os.Remove(conn) 57 } 58 }) 59 60 Describe("Base operations", func() { 61 var ( 62 tx transaction.Transaction 63 ) 64 65 BeforeEach(func() { 66 Expect(manager.LoadSchemaFromFile("../tests/test_abstract_schema.yaml")).To(Succeed()) 67 Expect(manager.LoadSchemaFromFile("../tests/test_schema.yaml")).To(Succeed()) 68 networkSchema, ok = manager.Schema("network") 69 Expect(ok).To(BeTrue()) 70 _, ok = manager.Schema("subnet") 71 Expect(ok).To(BeTrue()) 72 serverSchema, ok = manager.Schema("server") 73 Expect(ok).To(BeTrue()) 74 75 network1 := map[string]interface{}{ 76 "id": "networkRed", 77 "name": "NetworkRed", 78 "description": "A crimson network", 79 "tenant_id": "red", 80 "shared": false, 81 "route_targets": []string{"1000:10000", "2000:20000"}, 82 "providor_networks": map[string]interface{}{"segmentation_id": 10, "segmentation_type": "vlan"}} 83 networkResource1, err = manager.LoadResource("network", network1) 84 Expect(err).ToNot(HaveOccurred()) 85 86 network2 := map[string]interface{}{ 87 "id": "networkBlue", 88 "name": "NetworkBlue", 89 "description": "A crimson network", 90 "tenant_id": "blue", 91 "shared": false, 92 "route_targets": []string{"1000:10000", "2000:20000"}, 93 "providor_networks": map[string]interface{}{"segmentation_id": 10, "segmentation_type": "vlan"}} 94 networkResource2, err = manager.LoadResource("network", network2) 95 Expect(err).ToNot(HaveOccurred()) 96 97 subnet := map[string]interface{}{ 98 "id": "subnetRed", 99 "name": "SubnetRed", 100 "description": "A crimson subnet", 101 "tenant_id": "red", 102 "cidr": "10.0.0.0/24"} 103 subnetResource, err = manager.LoadResource("subnet", subnet) 104 Expect(err).ToNot(HaveOccurred()) 105 subnetResource.SetParentID("networkRed") 106 Expect(subnetResource.Path()).To(Equal("/v2.0/subnets/subnetRed")) 107 108 server := map[string]interface{}{ 109 "id": "serverRed", 110 "name": "serverRed", 111 "tenant_id": "red", 112 "network_id": "networkRed", 113 "description": "red server", 114 "cidr": "10.0.0.0/24"} 115 serverResource, err = manager.LoadResource("server", server) 116 Expect(err).ToNot(HaveOccurred()) 117 }) 118 119 JustBeforeEach(func() { 120 os.Remove(conn) 121 dataStore, err = db.ConnectDB(dbType, conn, db.DefaultMaxOpenConn) 122 Expect(err).ToNot(HaveOccurred()) 123 124 for _, s := range manager.Schemas() { 125 Expect(dataStore.RegisterTable(s, false)).To(Succeed()) 126 } 127 128 tx, err = dataStore.Begin() 129 Expect(err).ToNot(HaveOccurred()) 130 }) 131 132 AfterEach(func() { 133 tx.Close() 134 }) 135 136 Describe("Using sql", func() { 137 BeforeEach(func() { 138 if os.Getenv("MYSQL_TEST") == "true" { 139 conn = "root@/gohan_test" 140 dbType = "mysql" 141 } else { 142 conn = "./test.db" 143 dbType = "sqlite3" 144 } 145 }) 146 147 Context("When the database is empty", func() { 148 It("Returns an empty list", func() { 149 list, num, err := tx.List(networkSchema, nil, nil) 150 Expect(err).ToNot(HaveOccurred()) 151 Expect(num).To(Equal(uint64(0))) 152 Expect(list).To(BeEmpty()) 153 Expect(tx.Commit()).To(Succeed()) 154 }) 155 156 It("Creates a resource", func() { 157 Expect(tx.Create(networkResource1)).To(Succeed()) 158 159 Expect(tx.Commit()).To(Succeed()) 160 }) 161 }) 162 163 Describe("When the database is not empty", func() { 164 JustBeforeEach(func() { 165 Expect(tx.Create(networkResource1)).To(Succeed()) 166 Expect(tx.Create(networkResource2)).To(Succeed()) 167 Expect(tx.Create(serverResource)).To(Succeed()) 168 Expect(tx.Commit()).To(Succeed()) 169 tx.Close() 170 tx, err = dataStore.Begin() 171 Expect(err).ToNot(HaveOccurred()) 172 }) 173 174 It("Returns the expected list", func() { 175 list, num, err := tx.List(networkSchema, nil, nil) 176 Expect(err).ToNot(HaveOccurred()) 177 Expect(num).To(Equal(uint64(2))) 178 Expect(list).To(HaveLen(2)) 179 Expect(list[0]).To(util.MatchAsJSON(networkResource1)) 180 Expect(list[1]).To(util.MatchAsJSON(networkResource2)) 181 Expect(tx.Commit()).To(Succeed()) 182 }) 183 184 It("Returns the expected list with filter", func() { 185 filter := map[string]interface{}{ 186 "tenant_id": []string{"red"}, 187 } 188 list, num, err := tx.List(networkSchema, filter, nil) 189 Expect(err).ToNot(HaveOccurred()) 190 Expect(num).To(Equal(uint64(1))) 191 Expect(list).To(HaveLen(1)) 192 Expect(list[0]).To(util.MatchAsJSON(networkResource1)) 193 Expect(tx.Commit()).To(Succeed()) 194 }) 195 196 It("Returns the error with invalid filter", func() { 197 filter := map[string]interface{}{ 198 "bad_filter": []string{"red"}, 199 } 200 _, _, err := tx.List(networkSchema, filter, nil) 201 Expect(err).To(HaveOccurred()) 202 }) 203 204 It("Shows related resources", func() { 205 list, num, err := tx.List(serverSchema, nil, nil) 206 Expect(err).ToNot(HaveOccurred()) 207 Expect(num).To(Equal(uint64(1))) 208 Expect(list).To(HaveLen(1)) 209 Expect(list[0].Data()).To(HaveKeyWithValue("network", HaveKeyWithValue("name", networkResource1.Data()["name"]))) 210 Expect(tx.Commit()).To(Succeed()) 211 }) 212 213 It("Fetches an existing resource", func() { 214 networkResourceFetched, err := tx.Fetch(networkSchema, transaction.IDFilter(networkResource1.ID())) 215 Expect(err).ToNot(HaveOccurred()) 216 Expect(networkResourceFetched).To(util.MatchAsJSON(networkResource1)) 217 Expect(tx.Commit()).To(Succeed()) 218 }) 219 220 It("Updates the resource properly", func() { 221 By("Not allowing to update some fields") 222 Expect(networkResource1.Update(map[string]interface{}{"id": "new_id"})).ToNot(Succeed()) 223 224 By("Updating other fields") 225 Expect(networkResource1.Update(map[string]interface{}{"name": "new_name"})).To(Succeed()) 226 Expect(tx.Update(networkResource1)).To(Succeed()) 227 Expect(tx.Commit()).To(Succeed()) 228 }) 229 230 It("Creates a dependent resource", func() { 231 Expect(tx.Create(subnetResource)).To(Succeed()) 232 Expect(tx.Commit()).To(Succeed()) 233 }) 234 235 It("Deletes the resource", func() { 236 Expect(tx.Delete(serverSchema, serverResource.ID())).To(Succeed()) 237 Expect(tx.Delete(networkSchema, networkResource1.ID())).To(Succeed()) 238 Expect(tx.Commit()).To(Succeed()) 239 }) 240 241 Context("Using StateFetch", func() { 242 It("Returns the defaults", func() { 243 beforeState, err := tx.StateFetch(networkSchema, transaction.IDFilter(networkResource1.ID())) 244 Expect(err).ToNot(HaveOccurred()) 245 Expect(tx.Commit()).To(Succeed()) 246 Expect(beforeState.ConfigVersion).To(Equal(int64(1))) 247 Expect(beforeState.StateVersion).To(Equal(int64(0))) 248 Expect(beforeState.State).To(Equal("")) 249 Expect(beforeState.Error).To(Equal("")) 250 Expect(beforeState.Monitoring).To(Equal("")) 251 }) 252 }) 253 }) 254 }) 255 }) 256 257 Context("Initialization", func() { 258 BeforeEach(func() { 259 conn = "test.db" 260 dbType = "sqlite3" 261 Expect(manager.LoadSchemaFromFile("../tests/test_abstract_schema.yaml")).To(Succeed()) 262 Expect(manager.LoadSchemaFromFile("../tests/test_schema.yaml")).To(Succeed()) 263 }) 264 265 It("Should initialize the database without error", func() { 266 Expect(db.InitDBWithSchemas(dbType, conn, false, false)).To(Succeed()) 267 }) 268 }) 269 270 Context("Converting", func() { 271 BeforeEach(func() { 272 Expect(manager.LoadSchemaFromFile("test_data/conv_in.yaml")).To(Succeed()) 273 }) 274 275 It("Should do it properly", func() { 276 inDB, err := db.ConnectDB("yaml", "test_data/conv_in.yaml", db.DefaultMaxOpenConn) 277 Expect(err).ToNot(HaveOccurred()) 278 defer os.Remove("test_data/conv_in.db") 279 280 db.InitDBWithSchemas("sqlite3", "test_data/conv_out.db", false, false) 281 outDB, err := db.ConnectDB("sqlite3", "test_data/conv_out.db", db.DefaultMaxOpenConn) 282 Expect(err).ToNot(HaveOccurred()) 283 defer os.Remove("test_data/conv_out.db") 284 285 db.InitDBWithSchemas("yaml", "test_data/conv_verify.yaml", false, false) 286 verifyDB, err := db.ConnectDB("yaml", "test_data/conv_verify.yaml", db.DefaultMaxOpenConn) 287 Expect(err).ToNot(HaveOccurred()) 288 defer os.Remove("test_data/conv_verify.yaml") 289 290 Expect(db.CopyDBResources(inDB, outDB, true)).To(Succeed()) 291 292 Expect(db.CopyDBResources(outDB, verifyDB, true)).To(Succeed()) 293 294 inTx, err := inDB.Begin() 295 Expect(err).ToNot(HaveOccurred()) 296 defer inTx.Close() 297 298 // SQL returns different types than JSON/YAML Database 299 // So we need to move it back again so that DeepEqual would work correctly 300 verifyTx, err := verifyDB.Begin() 301 Expect(err).ToNot(HaveOccurred()) 302 defer verifyTx.Close() 303 304 for _, s := range manager.OrderedSchemas() { 305 if s.Metadata["type"] == "metaschema" { 306 continue 307 } 308 resources, _, err := inTx.List(s, nil, nil) 309 Expect(err).ToNot(HaveOccurred()) 310 for _, inResource := range resources { 311 outResource, err := verifyTx.Fetch(s, transaction.Filter{"id": inResource.ID()}) 312 Expect(err).ToNot(HaveOccurred()) 313 Expect(outResource).To(Equal(inResource)) 314 } 315 } 316 }) 317 318 It("Should not override existing rows", func() { 319 inDB, err := db.ConnectDB("yaml", "test_data/conv_in.yaml", db.DefaultMaxOpenConn) 320 Expect(err).ToNot(HaveOccurred()) 321 defer os.Remove("test_data/conv_in.db") 322 323 db.InitDBWithSchemas("sqlite3", "test_data/conv_out.db", false, false) 324 outDB, err := db.ConnectDB("sqlite3", "test_data/conv_out.db", db.DefaultMaxOpenConn) 325 Expect(err).ToNot(HaveOccurred()) 326 defer os.Remove("test_data/conv_out.db") 327 328 Expect(err).ToNot(HaveOccurred()) 329 defer os.Remove("test_data/conv_verify.yaml") 330 331 Expect(db.CopyDBResources(inDB, outDB, false)).To(Succeed()) 332 subnetSchema, _ := manager.Schema("subnet") 333 334 // Update some data 335 tx, err := outDB.Begin() 336 Expect(err).ToNot(HaveOccurred()) 337 list, _, err := tx.List(subnetSchema, map[string]interface{}{ 338 "name": "subnetRedA", 339 }, nil) 340 Expect(err).ToNot(HaveOccurred()) 341 Expect(list).To(HaveLen(1)) 342 subnet := list[0] 343 subnet.Data()["description"] = "Updated description" 344 err = tx.Update(subnet) 345 Expect(err).ToNot(HaveOccurred()) 346 tx.Commit() 347 tx.Close() 348 349 Expect(db.CopyDBResources(inDB, outDB, false)).To(Succeed()) 350 // check description of subnetRedA 351 tx, err = outDB.Begin() 352 Expect(err).ToNot(HaveOccurred()) 353 list, _, err = tx.List(subnetSchema, map[string]interface{}{ 354 "name": "subnetRedA", 355 }, nil) 356 Expect(err).ToNot(HaveOccurred()) 357 Expect(list).To(HaveLen(1)) 358 subnet = list[0] 359 Expect(subnet.Data()["description"]).To(Equal("Updated description")) 360 tx.Close() 361 }) 362 }) 363 })