github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/internal/database/sqlcommon/node_sql_test.go (about) 1 // Copyright © 2021 Kaleido, Inc. 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 package sqlcommon 18 19 import ( 20 "context" 21 "encoding/json" 22 "fmt" 23 "testing" 24 25 "github.com/DATA-DOG/go-sqlmock" 26 "github.com/kaleido-io/firefly/internal/log" 27 "github.com/kaleido-io/firefly/pkg/database" 28 "github.com/kaleido-io/firefly/pkg/fftypes" 29 "github.com/stretchr/testify/assert" 30 ) 31 32 func TestNodesE2EWithDB(t *testing.T) { 33 log.SetLevel("debug") 34 35 s := newQLTestProvider(t) 36 defer s.Close() 37 ctx := context.Background() 38 39 // Create a new node entry 40 node := &fftypes.Node{ 41 ID: fftypes.NewUUID(), 42 Message: fftypes.NewUUID(), 43 Owner: "0x23456", 44 Name: "node1", 45 Created: fftypes.Now(), 46 } 47 err := s.UpsertNode(ctx, node, true) 48 assert.NoError(t, err) 49 50 // Check we get the exact same node back 51 nodeRead, err := s.GetNode(ctx, node.Owner, node.Name) 52 assert.NoError(t, err) 53 assert.NotNil(t, nodeRead) 54 nodeJson, _ := json.Marshal(&node) 55 nodeReadJson, _ := json.Marshal(&nodeRead) 56 assert.Equal(t, string(nodeJson), string(nodeReadJson)) 57 58 // Rejects attempt to update ID 59 err = s.UpsertNode(context.Background(), &fftypes.Node{ 60 ID: fftypes.NewUUID(), 61 Owner: "0x23456", 62 Name: "node1", 63 }, true) 64 assert.Equal(t, database.IDMismatch, err) 65 66 // Update the node (this is testing what's possible at the database layer, 67 // and does not account for the verification that happens at the higher level) 68 nodeUpdated := &fftypes.Node{ 69 ID: nil, // as long as we don't specify one we're fine 70 Message: fftypes.NewUUID(), 71 Owner: "0x23456", 72 Name: "node1", 73 Description: "node1", 74 DX: fftypes.DXInfo{ 75 Peer: "peer1", 76 Endpoint: fftypes.JSONObject{"some": "info"}, 77 }, 78 Created: fftypes.Now(), 79 } 80 err = s.UpsertNode(context.Background(), nodeUpdated, true) 81 assert.NoError(t, err) 82 83 // Check we get the exact same data back - note the removal of one of the node elements 84 nodeRead, err = s.GetNode(ctx, node.Owner, node.Name) 85 assert.NoError(t, err) 86 nodeJson, _ = json.Marshal(&nodeUpdated) 87 nodeReadJson, _ = json.Marshal(&nodeRead) 88 assert.Equal(t, string(nodeJson), string(nodeReadJson)) 89 90 // Query back the node 91 fb := database.NodeQueryFactory.NewFilter(ctx) 92 filter := fb.And( 93 fb.Eq("description", string(nodeUpdated.Description)), 94 fb.Eq("name", nodeUpdated.Name), 95 ) 96 nodeRes, err := s.GetNodes(ctx, filter) 97 assert.NoError(t, err) 98 assert.Equal(t, 1, len(nodeRes)) 99 nodeReadJson, _ = json.Marshal(nodeRes[0]) 100 assert.Equal(t, string(nodeJson), string(nodeReadJson)) 101 102 // Update 103 updateTime := fftypes.Now() 104 up := database.NodeQueryFactory.NewUpdate(ctx).Set("created", updateTime) 105 err = s.UpdateNode(ctx, nodeUpdated.ID, up) 106 assert.NoError(t, err) 107 108 // Test find updated value 109 filter = fb.And( 110 fb.Eq("name", nodeUpdated.Name), 111 fb.Eq("created", updateTime.String()), 112 ) 113 nodes, err := s.GetNodes(ctx, filter) 114 assert.NoError(t, err) 115 assert.Equal(t, 1, len(nodes)) 116 } 117 118 func TestUpsertNodeFailBegin(t *testing.T) { 119 s, mock := newMockProvider().init() 120 mock.ExpectBegin().WillReturnError(fmt.Errorf("pop")) 121 err := s.UpsertNode(context.Background(), &fftypes.Node{}, true) 122 assert.Regexp(t, "FF10114", err) 123 assert.NoError(t, mock.ExpectationsWereMet()) 124 } 125 126 func TestUpsertNodeFailSelect(t *testing.T) { 127 s, mock := newMockProvider().init() 128 mock.ExpectBegin() 129 mock.ExpectQuery("SELECT .*").WillReturnError(fmt.Errorf("pop")) 130 mock.ExpectRollback() 131 err := s.UpsertNode(context.Background(), &fftypes.Node{Name: "node1"}, true) 132 assert.Regexp(t, "FF10115", err) 133 assert.NoError(t, mock.ExpectationsWereMet()) 134 } 135 136 func TestUpsertNodeFailInsert(t *testing.T) { 137 s, mock := newMockProvider().init() 138 mock.ExpectBegin() 139 mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{})) 140 mock.ExpectExec("INSERT .*").WillReturnError(fmt.Errorf("pop")) 141 mock.ExpectRollback() 142 err := s.UpsertNode(context.Background(), &fftypes.Node{Name: "node1"}, true) 143 assert.Regexp(t, "FF10116", err) 144 assert.NoError(t, mock.ExpectationsWereMet()) 145 } 146 147 func TestUpsertNodeFailUpdate(t *testing.T) { 148 s, mock := newMockProvider().init() 149 mock.ExpectBegin() 150 mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"name"}). 151 AddRow("id1")) 152 mock.ExpectExec("UPDATE .*").WillReturnError(fmt.Errorf("pop")) 153 mock.ExpectRollback() 154 err := s.UpsertNode(context.Background(), &fftypes.Node{Name: "node1"}, true) 155 assert.Regexp(t, "FF10117", err) 156 assert.NoError(t, mock.ExpectationsWereMet()) 157 } 158 159 func TestUpsertNodeFailCommit(t *testing.T) { 160 s, mock := newMockProvider().init() 161 mock.ExpectBegin() 162 mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"name"})) 163 mock.ExpectExec("INSERT .*").WillReturnResult(sqlmock.NewResult(1, 1)) 164 mock.ExpectCommit().WillReturnError(fmt.Errorf("pop")) 165 err := s.UpsertNode(context.Background(), &fftypes.Node{Name: "node1"}, true) 166 assert.Regexp(t, "FF10119", err) 167 assert.NoError(t, mock.ExpectationsWereMet()) 168 } 169 170 func TestGetNodeByIDSelectFail(t *testing.T) { 171 s, mock := newMockProvider().init() 172 mock.ExpectQuery("SELECT .*").WillReturnError(fmt.Errorf("pop")) 173 _, err := s.GetNode(context.Background(), "owner1", "node1") 174 assert.Regexp(t, "FF10115", err) 175 assert.NoError(t, mock.ExpectationsWereMet()) 176 } 177 178 func TestGetNodeByIDNotFound(t *testing.T) { 179 s, mock := newMockProvider().init() 180 mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"name", "node", "name"})) 181 msg, err := s.GetNode(context.Background(), "owner1", "node1") 182 assert.NoError(t, err) 183 assert.Nil(t, msg) 184 assert.NoError(t, mock.ExpectationsWereMet()) 185 } 186 187 func TestGetNodeByIDScanFail(t *testing.T) { 188 s, mock := newMockProvider().init() 189 mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"name"}).AddRow("only one")) 190 _, err := s.GetNodeByID(context.Background(), fftypes.NewUUID()) 191 assert.Regexp(t, "FF10121", err) 192 assert.NoError(t, mock.ExpectationsWereMet()) 193 } 194 195 func TestGetNodeQueryFail(t *testing.T) { 196 s, mock := newMockProvider().init() 197 mock.ExpectQuery("SELECT .*").WillReturnError(fmt.Errorf("pop")) 198 f := database.NodeQueryFactory.NewFilter(context.Background()).Eq("name", "") 199 _, err := s.GetNodes(context.Background(), f) 200 assert.Regexp(t, "FF10115", err) 201 assert.NoError(t, mock.ExpectationsWereMet()) 202 } 203 204 func TestGetNodeBuildQueryFail(t *testing.T) { 205 s, _ := newMockProvider().init() 206 f := database.NodeQueryFactory.NewFilter(context.Background()).Eq("name", map[bool]bool{true: false}) 207 _, err := s.GetNodes(context.Background(), f) 208 assert.Regexp(t, "FF10149.*type", err) 209 } 210 211 func TestGetNodeReadMessageFail(t *testing.T) { 212 s, mock := newMockProvider().init() 213 mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"name"}).AddRow("only one")) 214 f := database.NodeQueryFactory.NewFilter(context.Background()).Eq("name", "") 215 _, err := s.GetNodes(context.Background(), f) 216 assert.Regexp(t, "FF10121", err) 217 assert.NoError(t, mock.ExpectationsWereMet()) 218 } 219 220 func TestNodeUpdateBeginFail(t *testing.T) { 221 s, mock := newMockProvider().init() 222 mock.ExpectBegin().WillReturnError(fmt.Errorf("pop")) 223 u := database.NodeQueryFactory.NewUpdate(context.Background()).Set("name", "anything") 224 err := s.UpdateNode(context.Background(), fftypes.NewUUID(), u) 225 assert.Regexp(t, "FF10114", err) 226 } 227 228 func TestNodeUpdateBuildQueryFail(t *testing.T) { 229 s, mock := newMockProvider().init() 230 mock.ExpectBegin() 231 u := database.NodeQueryFactory.NewUpdate(context.Background()).Set("name", map[bool]bool{true: false}) 232 err := s.UpdateNode(context.Background(), fftypes.NewUUID(), u) 233 assert.Regexp(t, "FF10149.*name", err) 234 } 235 236 func TestNodeUpdateFail(t *testing.T) { 237 s, mock := newMockProvider().init() 238 mock.ExpectBegin() 239 mock.ExpectExec("UPDATE .*").WillReturnError(fmt.Errorf("pop")) 240 mock.ExpectRollback() 241 u := database.NodeQueryFactory.NewUpdate(context.Background()).Set("name", fftypes.NewUUID()) 242 err := s.UpdateNode(context.Background(), fftypes.NewUUID(), u) 243 assert.Regexp(t, "FF10117", err) 244 }