| // Copyright 2017 Google Inc. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package apiGatewayConfDeploy |
| |
| import ( |
| "database/sql" |
| "fmt" |
| "github.com/apid/apid-core" |
| "github.com/apid/apid-core/data" |
| . "github.com/onsi/ginkgo" |
| . "github.com/onsi/gomega" |
| "reflect" |
| "strconv" |
| "sync" |
| "time" |
| ) |
| |
| const ( |
| testBlobLocalFsPrefix = "/tmp/tmpapid/" |
| readyBlobId = "gcs:SHA-512:39ca7ae89bb9468af34df8bc873748b4035210c91bcc01359c092c1d51364b5f3df06bc69a40621acfaa46791af9ea41bc0f3429a84738ba1a7c8d394859601a" |
| readyResourceId = "gcs:SHA-512:ddd64d03c365dde4bb175cabb7d84beeb81dae11f1e326b30c9035b74be3ecb537187bdf35568647aa1b2adb341499516ca2faf2d73b78b1b98cba038f2a9e3c" |
| ) |
| |
| var ( |
| unreadyBlobIds = map[string]bool{ |
| "gcs:SHA-512:8fcc902465ccb32ceff25fa9f6fb28e3b314dbc2874c0f8add02f4e29c9e2798d344c51807aa1af56035cf09d39c800cf605d627ba65723f26d8b9c83c82d2f2": true, |
| "gcs:SHA-512:0c648779da035bfe0ac21f6268049aa0ae74d9d6411dadefaec33991e55c2d66c807e06f7ef84e0947f7c7d63b8c9e97cf0684cbef9e0a86b947d73c74ae7455": true, |
| } |
| |
| allConfigs map[string]bool |
| ) |
| |
| var _ = Describe("data", func() { |
| var testCount int |
| var testDbMan *dbManager |
| var _ = BeforeEach(func() { |
| testCount += 1 |
| testDbMan = &dbManager{ |
| data: services.Data(), |
| dbMux: sync.RWMutex{}, |
| lsnMutex: sync.RWMutex{}, |
| } |
| testDbMan.setDbVersion("test" + strconv.Itoa(testCount)) |
| initTestDb(testDbMan.getDb()) |
| err := testDbMan.initDb() |
| Expect(err).Should(Succeed()) |
| allConfigs = map[string]bool{ |
| "1dc4895e-6494-4b59-979f-5f4c89c073b4": true, |
| "319963ff-217e-4ecc-8d6e-c3665e962d1e": true, |
| "3af44bb7-0a74-4283-860c-3561e6c19132": true, |
| "d5ffd9db-4795-43eb-b645-d2a0b6c8ac6a": true, |
| "84ac8d68-b3d1-4bcc-ad0d-c6a0ed67e16c": true, |
| "3ecd351c-1173-40bf-b830-c194e5ef9038": true, |
| } |
| time.Sleep(100 * time.Millisecond) |
| }) |
| |
| var _ = AfterEach(func() { |
| testDbMan = nil |
| data.Delete(data.VersionedDBID("common", "test"+strconv.Itoa(testCount))) |
| }) |
| |
| Context("basic db tests", func() { |
| It("initDb() should be idempotent", func() { |
| err := testDbMan.initDb() |
| Expect(err).Should(Succeed()) |
| }) |
| |
| It("should succefully initialized tables", func() { |
| // apid_blob_available |
| rows, err := testDbMan.getDb().Query(` |
| SELECT count(*) from apid_blob_available; |
| `) |
| Expect(err).Should(Succeed()) |
| defer rows.Close() |
| var count int |
| for rows.Next() { |
| rows.Scan(&count) |
| } |
| Expect(count).Should(Equal(0)) |
| |
| // metadata_runtime_entity_metadata |
| rows, err = testDbMan.getDb().Query(` |
| SELECT count(*) from metadata_runtime_entity_metadata; |
| `) |
| Expect(err).Should(Succeed()) |
| defer rows.Close() |
| for rows.Next() { |
| rows.Scan(&count) |
| } |
| Expect(count).Should(Equal(6)) |
| }) |
| |
| It("should initialize support for long-polling", func() { |
| // APID_CONFIGURATION_LSN |
| rows, err := testDbMan.getDb().Query(` |
| SELECT lsn from APID_CONFIGURATION_LSN; |
| `) |
| Expect(err).Should(Succeed()) |
| defer rows.Close() |
| count := 0 |
| var lsn sql.NullString |
| for rows.Next() { |
| count++ |
| rows.Scan(&lsn) |
| } |
| Expect(count).Should(Equal(1)) |
| Expect(lsn.Valid).Should(BeTrue()) |
| Expect(lsn.String).Should(Equal(InitLSN)) |
| }) |
| |
| It("should maintain LSN", func() { |
| testLSN := fmt.Sprintf("%d.%d.%d", testCount, testCount, testCount) |
| // write |
| err := testDbMan.updateLSN(testLSN) |
| Expect(err).Should(Succeed()) |
| rows, err := testDbMan.getDb().Query(` |
| SELECT lsn from APID_CONFIGURATION_LSN; |
| `) |
| Expect(err).Should(Succeed()) |
| defer rows.Close() |
| count := 0 |
| var lsn sql.NullString |
| for rows.Next() { |
| count++ |
| rows.Scan(&lsn) |
| } |
| Expect(count).Should(Equal(1)) |
| Expect(lsn.Valid).Should(BeTrue()) |
| Expect(lsn.String).Should(Equal(testLSN)) |
| |
| // read |
| Expect(testDbMan.getLSN()).Should(Equal(testLSN)) |
| |
| //load |
| Expect(testDbMan.loadLsnFromDb()).Should(Succeed()) |
| Expect(testDbMan.apidLSN).Should(Equal(testLSN)) |
| }) |
| }) |
| |
| Context("configuration tests", func() { |
| |
| It("should get all configs", func() { |
| confs, err := testDbMan.getAllConfigurations("") |
| Expect(err).Should(Succeed()) |
| Expect(len(confs)).Should(Equal(6)) |
| for _, conf := range confs { |
| Expect(allConfigs[conf.ID]).Should(BeTrue()) |
| allConfigs[conf.ID] = false |
| } |
| }) |
| |
| It("should get empty slice if no configurations", func() { |
| trancateTestMetadataTable(testDbMan.getDb()) |
| confs, err := testDbMan.getAllConfigurations("") |
| Expect(err).Should(Succeed()) |
| Expect(len(confs)).Should(BeZero()) |
| }) |
| |
| /* |
| XIt("should get empty slice if no configurations are ready", func() { |
| confs, err := testDbMan.getReadyConfigurations("") |
| Expect(err).Should(Succeed()) |
| Expect(len(confs)).Should(BeZero()) |
| }) |
| */ |
| |
| It("should succefully update local FS location", func() { |
| |
| err := testDbMan.updateLocalFsLocation(testBlobId, testBlobLocalFsPrefix+testBlobId) |
| Expect(err).Should(Succeed()) |
| // apid_blob_available |
| rows, err := testDbMan.getDb().Query(` |
| SELECT count(*) from apid_blob_available; |
| `) |
| Expect(err).Should(Succeed()) |
| defer rows.Close() |
| var count int |
| for rows.Next() { |
| rows.Scan(&count) |
| } |
| Expect(count).Should(Equal(1)) |
| }) |
| |
| It("should succefully get local FS location", func() { |
| |
| err := testDbMan.updateLocalFsLocation(testBlobId, testBlobLocalFsPrefix+testBlobId) |
| Expect(err).Should(Succeed()) |
| |
| // apid_blob_available |
| location, err := testDbMan.getLocalFSLocation(testBlobId) |
| Expect(err).Should(Succeed()) |
| Expect(location).Should(Equal(testBlobLocalFsPrefix + testBlobId)) |
| // negative test |
| _, err = testDbMan.getLocalFSLocation("non-existent") |
| Expect(err).Should(Equal(sql.ErrNoRows)) |
| }) |
| |
| It("should get configuration by Id", func() { |
| config, err := testDbMan.getConfigById("3ecd351c-1173-40bf-b830-c194e5ef9038") |
| Expect(err).Should(Succeed()) |
| expectedResponse := &Configuration{ |
| ID: "3ecd351c-1173-40bf-b830-c194e5ef9038", |
| OrgID: "73fcac6c-5d9f-44c1-8db0-333efda3e6e8", |
| EnvID: "ada76573-68e3-4f1a-a0f9-cbc201a97e80", |
| BlobID: "gcs:SHA-512:8fcc902465ccb32ceff25fa9f6fb28e3b314dbc2874c0f8add02f4e29c9e2798d344c51807aa1af56035cf09d39c800cf605d627ba65723f26d8b9c83c82d2f2", |
| BlobResourceID: "gcs:SHA-512:0c648779da035bfe0ac21f6268049aa0ae74d9d6411dadefaec33991e55c2d66c807e06f7ef84e0947f7c7d63b8c9e97cf0684cbef9e0a86b947d73c74ae7455", |
| Type: "ENVIRONMENT", |
| Name: "test", |
| Revision: "", |
| Path: "/organizations/Org1//environments/test/", |
| Created: "2017-06-27 03:14:46.018+00:00", |
| CreatedBy: "defaultUser", |
| Updated: "2017-06-27 03:14:46.018+00:00", |
| UpdatedBy: "defaultUser", |
| } |
| Expect(config).ShouldNot(BeNil()) |
| Expect(reflect.DeepEqual(expectedResponse, config)).Should(BeTrue()) |
| }) |
| |
| It("should get non-nil error for nonexistent Id", func() { |
| _, err := testDbMan.getConfigById("3ecd351c-aaaa-40bf-b830-c194e5ef9038") |
| Expect(err).ShouldNot(Succeed()) |
| }) |
| |
| /* |
| XIt("should successfully get all ready configurations", func() { |
| |
| err := testDbMan.updateLocalFsLocation(readyBlobId, testBlobLocalFsPrefix+readyBlobId) |
| Expect(err).Should(Succeed()) |
| err = testDbMan.updateLocalFsLocation(readyResourceId, testBlobLocalFsPrefix+readyResourceId) |
| Expect(err).Should(Succeed()) |
| |
| confs, err := testDbMan.getReadyConfigurations("") |
| Expect(err).Should(Succeed()) |
| Expect(len(confs)).Should(Equal(2)) |
| for _, conf := range confs { |
| Expect(conf.BlobID).Should(Equal(readyBlobId)) |
| if conf.BlobResourceID != "" { |
| Expect(conf.BlobResourceID).Should(Equal(readyResourceId)) |
| } |
| } |
| }) |
| */ |
| It("should get all configurations by type filter", func() { |
| |
| err := testDbMan.updateLocalFsLocation(readyBlobId, testBlobLocalFsPrefix+readyBlobId) |
| Expect(err).Should(Succeed()) |
| err = testDbMan.updateLocalFsLocation(readyResourceId, testBlobLocalFsPrefix+readyResourceId) |
| Expect(err).Should(Succeed()) |
| |
| confs, err := testDbMan.getAllConfigurations("ORGANIZATION") |
| Expect(err).Should(Succeed()) |
| Expect(len(confs)).Should(Equal(2)) |
| |
| confs, err = testDbMan.getAllConfigurations("ENVIRONMENT") |
| Expect(err).Should(Succeed()) |
| Expect(len(confs)).Should(Equal(4)) |
| |
| confs, err = testDbMan.getAllConfigurations("INVALID-TYPE") |
| Expect(err).Should(Succeed()) |
| Expect(len(confs)).Should(Equal(0)) |
| }) |
| |
| It("should succefully get all unready blob ids", func() { |
| |
| err := testDbMan.updateLocalFsLocation(readyBlobId, testBlobLocalFsPrefix+readyBlobId) |
| Expect(err).Should(Succeed()) |
| err = testDbMan.updateLocalFsLocation(readyResourceId, testBlobLocalFsPrefix+readyResourceId) |
| Expect(err).Should(Succeed()) |
| |
| ids, err := testDbMan.getUnreadyBlobs() |
| Expect(err).Should(Succeed()) |
| Expect(len(ids)).Should(Equal(2)) |
| for _, id := range ids { |
| Expect(unreadyBlobIds[id]).Should(BeTrue()) |
| } |
| }) |
| |
| }) |
| |
| }) |
| |
| //initialize DB for tests |
| func initTestDb(db apid.DB) { |
| tx, err := db.Begin() |
| Expect(err).Should(Succeed()) |
| defer tx.Rollback() |
| _, err = tx.Exec(` |
| CREATE TABLE metadata_runtime_entity_metadata ( |
| id text, |
| organization_id text, |
| environment_id text, |
| bean_blob_id text, |
| resource_blob_id text, |
| type text, |
| name text, |
| revision text, |
| path text, |
| created_at blob, |
| created_by text, |
| updated_at blob, |
| updated_by text, |
| _change_selector text, |
| primary key (id)); |
| `) |
| Expect(err).Should(Succeed()) |
| |
| // ready blob, empty resource |
| _, err = tx.Exec(` |
| INSERT INTO "metadata_runtime_entity_metadata" VALUES( |
| '1dc4895e-6494-4b59-979f-5f4c89c073b4', |
| '73fcac6c-5d9f-44c1-8db0-333efda3e6e8', |
| '', |
| 'gcs:SHA-512:39ca7ae89bb9468af34df8bc873748b4035210c91bcc01359c092c1d51364b5f3df06bc69a40621acfaa46791af9ea41bc0f3429a84738ba1a7c8d394859601a', |
| NULL, |
| 'ENVIRONMENT', |
| 'Org1', |
| '', |
| '/organizations/edgex01//environments/prod/', |
| '2017-06-27 03:14:45.748+00:00', |
| 'defaultUser', |
| '2017-06-27 03:15:03.557+00:00', |
| 'defaultUser', |
| '73fcac6c-5d9f-44c1-8db0-333efda3e6e8' |
| ); |
| `) |
| Expect(err).Should(Succeed()) |
| |
| // ready blob, ready resource |
| _, err = tx.Exec(` |
| INSERT INTO "metadata_runtime_entity_metadata" VALUES( |
| '319963ff-217e-4ecc-8d6e-c3665e962d1e', |
| '73fcac6c-5d9f-44c1-8db0-333efda3e6e8', |
| '', |
| 'gcs:SHA-512:39ca7ae89bb9468af34df8bc873748b4035210c91bcc01359c092c1d51364b5f3df06bc69a40621acfaa46791af9ea41bc0f3429a84738ba1a7c8d394859601a', |
| 'gcs:SHA-512:ddd64d03c365dde4bb175cabb7d84beeb81dae11f1e326b30c9035b74be3ecb537187bdf35568647aa1b2adb341499516ca2faf2d73b78b1b98cba038f2a9e3c', |
| 'ORGANIZATION', |
| 'Org1', |
| '', |
| '/organizations/Org1/', |
| '2017-06-27 03:14:45.748+00:00', |
| 'defaultUser', |
| '2017-06-27 03:15:03.557+00:00', |
| 'defaultUser', |
| '73fcac6c-5d9f-44c1-8db0-333efda3e6e8' |
| ); |
| `) |
| Expect(err).Should(Succeed()) |
| |
| // ready blob, unready resource |
| _, err = tx.Exec(` |
| INSERT INTO "metadata_runtime_entity_metadata" VALUES( |
| '3af44bb7-0a74-4283-860c-3561e6c19132', |
| '73fcac6c-5d9f-44c1-8db0-333efda3e6e8', |
| '', |
| 'gcs:SHA-512:39ca7ae89bb9468af34df8bc873748b4035210c91bcc01359c092c1d51364b5f3df06bc69a40621acfaa46791af9ea41bc0f3429a84738ba1a7c8d394859601a', |
| 'gcs:SHA-512:0c648779da035bfe0ac21f6268049aa0ae74d9d6411dadefaec33991e55c2d66c807e06f7ef84e0947f7c7d63b8c9e97cf0684cbef9e0a86b947d73c74ae7455', |
| 'ORGANIZATION', |
| 'Org1', |
| '', |
| '/organizations/Org1/', |
| '2017-06-27 03:14:45.748+00:00', |
| 'defaultUser', |
| '2017-06-27 03:15:03.557+00:00', |
| 'defaultUser', |
| '73fcac6c-5d9f-44c1-8db0-333efda3e6e8' |
| ); |
| `) |
| Expect(err).Should(Succeed()) |
| |
| // unready blob, empty resource |
| _, err = tx.Exec(` |
| INSERT INTO "metadata_runtime_entity_metadata" VALUES( |
| 'd5ffd9db-4795-43eb-b645-d2a0b6c8ac6a', |
| '73fcac6c-5d9f-44c1-8db0-333efda3e6e8', |
| 'ada76573-68e3-4f1a-a0f9-cbc201a97e80', |
| 'gcs:SHA-512:8fcc902465ccb32ceff25fa9f6fb28e3b314dbc2874c0f8add02f4e29c9e2798d344c51807aa1af56035cf09d39c800cf605d627ba65723f26d8b9c83c82d2f2', |
| '', |
| 'ENVIRONMENT', |
| 'test', |
| '', |
| '/organizations/Org1//environments/test/', |
| '2017-06-27 03:14:46.018+00:00', |
| 'defaultUser', |
| '2017-06-27 03:14:46.018+00:00', |
| 'defaultUser', |
| 'ada76573-68e3-4f1a-a0f9-cbc201a97e80' |
| ); |
| `) |
| Expect(err).Should(Succeed()) |
| |
| // unready blob, ready resource |
| _, err = tx.Exec(` |
| INSERT INTO "metadata_runtime_entity_metadata" VALUES( |
| '84ac8d68-b3d1-4bcc-ad0d-c6a0ed67e16c', |
| '73fcac6c-5d9f-44c1-8db0-333efda3e6e8', |
| 'ada76573-68e3-4f1a-a0f9-cbc201a97e80', |
| 'gcs:SHA-512:8fcc902465ccb32ceff25fa9f6fb28e3b314dbc2874c0f8add02f4e29c9e2798d344c51807aa1af56035cf09d39c800cf605d627ba65723f26d8b9c83c82d2f2', |
| 'gcs:SHA-512:ddd64d03c365dde4bb175cabb7d84beeb81dae11f1e326b30c9035b74be3ecb537187bdf35568647aa1b2adb341499516ca2faf2d73b78b1b98cba038f2a9e3c', |
| 'ENVIRONMENT', |
| 'test', |
| '', |
| '/organizations/Org1//environments/test/', |
| '2017-06-27 03:14:46.018+00:00', |
| 'defaultUser', |
| '2017-06-27 03:14:46.018+00:00', |
| 'defaultUser', |
| 'ada76573-68e3-4f1a-a0f9-cbc201a97e80' |
| ); |
| `) |
| Expect(err).Should(Succeed()) |
| |
| // unready blob, unready resource |
| _, err = tx.Exec(` |
| INSERT INTO "metadata_runtime_entity_metadata" VALUES( |
| '3ecd351c-1173-40bf-b830-c194e5ef9038', |
| '73fcac6c-5d9f-44c1-8db0-333efda3e6e8', |
| 'ada76573-68e3-4f1a-a0f9-cbc201a97e80', |
| 'gcs:SHA-512:8fcc902465ccb32ceff25fa9f6fb28e3b314dbc2874c0f8add02f4e29c9e2798d344c51807aa1af56035cf09d39c800cf605d627ba65723f26d8b9c83c82d2f2', |
| 'gcs:SHA-512:0c648779da035bfe0ac21f6268049aa0ae74d9d6411dadefaec33991e55c2d66c807e06f7ef84e0947f7c7d63b8c9e97cf0684cbef9e0a86b947d73c74ae7455', |
| 'ENVIRONMENT', |
| 'test', |
| '', |
| '/organizations/Org1//environments/test/', |
| '2017-06-27 03:14:46.018+00:00', |
| 'defaultUser', |
| '2017-06-27 03:14:46.018+00:00', |
| 'defaultUser', |
| 'ada76573-68e3-4f1a-a0f9-cbc201a97e80' |
| ); |
| `) |
| Expect(err).Should(Succeed()) |
| Expect(tx.Commit()).Should(Succeed()) |
| } |
| |
| func trancateTestMetadataTable(db apid.DB) { |
| tx, err := db.Begin() |
| Expect(err).Should(Succeed()) |
| defer tx.Rollback() |
| _, err = tx.Exec(` |
| DELETE FROM metadata_runtime_entity_metadata; |
| `) |
| Expect(err).Should(Succeed()) |
| Expect(tx.Commit()).Should(Succeed()) |
| } |