github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/internal/database/sqlcommon/pin_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 "fmt" 22 "testing" 23 24 "github.com/DATA-DOG/go-sqlmock" 25 "github.com/kaleido-io/firefly/internal/log" 26 "github.com/kaleido-io/firefly/pkg/database" 27 "github.com/kaleido-io/firefly/pkg/fftypes" 28 "github.com/stretchr/testify/assert" 29 "github.com/stretchr/testify/mock" 30 ) 31 32 func TestPinsE2EWithDB(t *testing.T) { 33 log.SetLevel("trace") 34 35 s := newQLTestProvider(t) 36 defer s.Close() 37 ctx := context.Background() 38 39 s.callbacks.On("PinCreated", mock.Anything).Return() 40 41 // Create a new pin entry 42 pin := &fftypes.Pin{ 43 Masked: true, 44 Hash: fftypes.NewRandB32(), 45 Batch: fftypes.NewUUID(), 46 Index: 10, 47 Created: fftypes.Now(), 48 Dispatched: false, 49 } 50 err := s.UpsertPin(ctx, pin) 51 assert.NoError(t, err) 52 53 // Query back the pin 54 fb := database.PinQueryFactory.NewFilter(ctx) 55 filter := fb.And( 56 fb.Eq("masked", pin.Masked), 57 fb.Eq("hash", pin.Hash), 58 fb.Eq("batch", pin.Batch), 59 fb.Gt("created", 0), 60 ) 61 pinRes, err := s.GetPins(ctx, filter) 62 assert.NoError(t, err) 63 assert.Equal(t, 1, len(pinRes)) 64 65 // Set it dispatched 66 err = s.SetPinDispatched(ctx, pin.Sequence) 67 assert.NoError(t, err) 68 69 // Double insert, checking no error and we keep the dispatched flag 70 existingSequence := pin.Sequence 71 pin.Sequence = 99999 72 err = s.UpsertPin(ctx, pin) 73 assert.NoError(t, err) 74 pinRes, err = s.GetPins(ctx, filter) 75 assert.NoError(t, err) 76 assert.Equal(t, 1, len(pinRes)) // we didn't add twice 77 assert.Equal(t, existingSequence, pin.Sequence) 78 assert.True(t, pin.Dispatched) 79 80 // Test delete 81 err = s.DeletePin(ctx, pin.Sequence) 82 assert.NoError(t, err) 83 p, err := s.GetPins(ctx, filter) 84 assert.NoError(t, err) 85 assert.Equal(t, 0, len(p)) 86 87 s.callbacks.AssertExpectations(t) 88 } 89 90 func TestUpsertPinFailBegin(t *testing.T) { 91 s, mock := newMockProvider().init() 92 mock.ExpectBegin().WillReturnError(fmt.Errorf("pop")) 93 err := s.UpsertPin(context.Background(), &fftypes.Pin{}) 94 assert.Regexp(t, "FF10114", err) 95 assert.NoError(t, mock.ExpectationsWereMet()) 96 } 97 98 func TestUpsertPinFailInsert(t *testing.T) { 99 s, mock := newMockProvider().init() 100 mock.ExpectBegin() 101 mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"sequence", "masked", "dispatched"})) 102 mock.ExpectExec("INSERT .*").WillReturnError(fmt.Errorf("pop")) 103 mock.ExpectRollback() 104 err := s.UpsertPin(context.Background(), &fftypes.Pin{Hash: fftypes.NewRandB32()}) 105 assert.Regexp(t, "FF10116", err) 106 assert.NoError(t, mock.ExpectationsWereMet()) 107 } 108 109 func TestUpsertPinFailSelect(t *testing.T) { 110 s, mock := newMockProvider().init() 111 mock.ExpectBegin() 112 mock.ExpectQuery("SELECT .*").WillReturnError(fmt.Errorf("pop")) 113 mock.ExpectRollback() 114 err := s.UpsertPin(context.Background(), &fftypes.Pin{Hash: fftypes.NewRandB32()}) 115 assert.Regexp(t, "FF10115", err) 116 assert.NoError(t, mock.ExpectationsWereMet()) 117 } 118 119 func TestUpsertPinFailExistingSequenceScan(t *testing.T) { 120 s, mock := newMockProvider().init() 121 mock.ExpectBegin() 122 mock.ExpectQuery("SELECT .*").WillReturnRows(mock.NewRows([]string{"only one"}).AddRow(true)) 123 mock.ExpectRollback() 124 err := s.UpsertPin(context.Background(), &fftypes.Pin{Hash: fftypes.NewRandB32()}) 125 assert.Regexp(t, "FF10121", err) 126 assert.NoError(t, mock.ExpectationsWereMet()) 127 } 128 129 func TestUpsertPinFailCommit(t *testing.T) { 130 s, mock := newMockProvider().init() 131 mock.ExpectBegin() 132 mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"sequence", "masked", "dispatched"})) 133 mock.ExpectExec("INSERT .*").WillReturnResult(sqlmock.NewResult(1, 1)) 134 mock.ExpectCommit().WillReturnError(fmt.Errorf("pop")) 135 err := s.UpsertPin(context.Background(), &fftypes.Pin{Hash: fftypes.NewRandB32()}) 136 assert.Regexp(t, "FF10119", err) 137 assert.NoError(t, mock.ExpectationsWereMet()) 138 } 139 140 func TestGetPinQueryFail(t *testing.T) { 141 s, mock := newMockProvider().init() 142 mock.ExpectQuery("SELECT .*").WillReturnError(fmt.Errorf("pop")) 143 f := database.PinQueryFactory.NewFilter(context.Background()).Eq("hash", "") 144 _, err := s.GetPins(context.Background(), f) 145 assert.Regexp(t, "FF10115", err) 146 assert.NoError(t, mock.ExpectationsWereMet()) 147 } 148 149 func TestGetPinBuildQueryFail(t *testing.T) { 150 s, _ := newMockProvider().init() 151 f := database.PinQueryFactory.NewFilter(context.Background()).Eq("hash", map[bool]bool{true: false}) 152 _, err := s.GetPins(context.Background(), f) 153 assert.Regexp(t, "FF10149.*type", err) 154 } 155 156 func TestGetPinReadMessageFail(t *testing.T) { 157 s, mock := newMockProvider().init() 158 mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"pin"}).AddRow("only one")) 159 f := database.PinQueryFactory.NewFilter(context.Background()).Eq("hash", "") 160 _, err := s.GetPins(context.Background(), f) 161 assert.Regexp(t, "FF10121", err) 162 assert.NoError(t, mock.ExpectationsWereMet()) 163 } 164 165 func TestSetPinsDispatchedBeginFail(t *testing.T) { 166 s, mock := newMockProvider().init() 167 mock.ExpectBegin().WillReturnError(fmt.Errorf("pop")) 168 err := s.SetPinDispatched(context.Background(), 12345) 169 assert.Regexp(t, "FF10114", err) 170 } 171 172 func TestSetPinsDispatchedUpdateFail(t *testing.T) { 173 s, mock := newMockProvider().init() 174 mock.ExpectBegin() 175 mock.ExpectExec("UPDATE .*").WillReturnError(fmt.Errorf("pop")) 176 mock.ExpectRollback() 177 err := s.SetPinDispatched(context.Background(), 12345) 178 assert.Regexp(t, "FF10117", err) 179 } 180 181 func TestPinDeleteBeginFail(t *testing.T) { 182 s, mock := newMockProvider().init() 183 mock.ExpectBegin().WillReturnError(fmt.Errorf("pop")) 184 err := s.DeletePin(context.Background(), 12345) 185 assert.Regexp(t, "FF10114", err) 186 } 187 188 func TestPinDeleteFail(t *testing.T) { 189 s, mock := newMockProvider().init() 190 mock.ExpectBegin() 191 mock.ExpectExec("DELETE .*").WillReturnError(fmt.Errorf("pop")) 192 mock.ExpectRollback() 193 err := s.DeletePin(context.Background(), 12345) 194 assert.Regexp(t, "FF10118", err) 195 }