github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/internal/database/sqlcommon/subscription_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/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 TestSubscriptionsE2EWithDB(t *testing.T) { 33 34 s := newQLTestProvider(t) 35 defer s.Close() 36 ctx := context.Background() 37 38 // Create a new subscription entry 39 subscription := &fftypes.Subscription{ 40 SubscriptionRef: fftypes.SubscriptionRef{ 41 ID: nil, // generated for us 42 Namespace: "ns1", 43 Name: "subscription1", 44 }, 45 Created: fftypes.Now(), 46 } 47 48 s.callbacks.On("SubscriptionCreated", mock.Anything).Return() 49 s.callbacks.On("SubscriptionDeleted", mock.Anything).Return() 50 51 err := s.UpsertSubscription(ctx, subscription, true) 52 assert.NoError(t, err) 53 54 // Check we get the exact same subscription back 55 subscriptionRead, err := s.GetSubscriptionByName(ctx, subscription.Namespace, subscription.Name) 56 assert.NoError(t, err) 57 assert.NotNil(t, subscriptionRead) 58 subscriptionJson, _ := json.Marshal(&subscription) 59 subscriptionReadJson, _ := json.Marshal(&subscriptionRead) 60 assert.Equal(t, string(subscriptionJson), string(subscriptionReadJson)) 61 62 // Update the subscription (this is testing what's possible at the database layer, 63 // and does not account for the verification that happens at the higher level) 64 newest := fftypes.SubOptsFirstEventNewest 65 fifty := uint16(50) 66 subscriptionUpdated := &fftypes.Subscription{ 67 SubscriptionRef: fftypes.SubscriptionRef{ 68 ID: fftypes.NewUUID(), // will fail with us trying to update this 69 Namespace: "ns1", 70 Name: "subscription1", 71 }, 72 Transport: "websockets", 73 Filter: fftypes.SubscriptionFilter{ 74 Events: string(fftypes.EventTypeMessageConfirmed), 75 Topics: "topics.*", 76 Tag: "tag.*", 77 Group: "group.*", 78 }, 79 Options: fftypes.SubscriptionOptions{ 80 FirstEvent: &newest, 81 ReadAhead: &fifty, 82 }, 83 Created: fftypes.Now(), 84 } 85 86 // Rejects attempt to update ID 87 err = s.UpsertSubscription(context.Background(), subscriptionUpdated, true) 88 assert.Equal(t, database.IDMismatch, err) 89 90 // Blank out the ID and retry 91 subscriptionUpdated.ID = nil 92 err = s.UpsertSubscription(context.Background(), subscriptionUpdated, true) 93 assert.NoError(t, err) 94 95 // Check we get the exact same data back - note the removal of one of the subscription elements 96 subscriptionRead, err = s.GetSubscriptionByID(ctx, subscription.ID) 97 assert.NoError(t, err) 98 subscriptionJson, _ = json.Marshal(&subscriptionUpdated) 99 subscriptionReadJson, _ = json.Marshal(&subscriptionRead) 100 assert.Equal(t, string(subscriptionJson), string(subscriptionReadJson)) 101 102 // Query back the subscription 103 fb := database.SubscriptionQueryFactory.NewFilter(ctx) 104 filter := fb.And( 105 fb.Eq("namespace", subscriptionUpdated.Namespace), 106 fb.Eq("name", subscriptionUpdated.Name), 107 ) 108 subscriptionRes, err := s.GetSubscriptions(ctx, filter) 109 assert.NoError(t, err) 110 assert.Equal(t, 1, len(subscriptionRes)) 111 subscriptionReadJson, _ = json.Marshal(subscriptionRes[0]) 112 assert.Equal(t, string(subscriptionJson), string(subscriptionReadJson)) 113 114 // Update 115 updateTime := fftypes.Now() 116 up := database.SubscriptionQueryFactory.NewUpdate(ctx).Set("created", updateTime) 117 err = s.UpdateSubscription(ctx, subscriptionUpdated.Namespace, subscriptionUpdated.Name, up) 118 assert.NoError(t, err) 119 120 // Test find updated value 121 filter = fb.And( 122 fb.Eq("name", subscriptionUpdated.Name), 123 fb.Eq("created", updateTime.String()), 124 ) 125 subscriptions, err := s.GetSubscriptions(ctx, filter) 126 assert.NoError(t, err) 127 assert.Equal(t, 1, len(subscriptions)) 128 129 // Test delete, and refind no return 130 err = s.DeleteSubscriptionByID(ctx, subscriptionUpdated.ID) 131 assert.NoError(t, err) 132 subscriptions, err = s.GetSubscriptions(ctx, filter) 133 assert.NoError(t, err) 134 assert.Equal(t, 0, len(subscriptions)) 135 136 s.callbacks.AssertExpectations(t) 137 } 138 139 func TestUpsertSubscriptionFailBegin(t *testing.T) { 140 s, mock := newMockProvider().init() 141 mock.ExpectBegin().WillReturnError(fmt.Errorf("pop")) 142 err := s.UpsertSubscription(context.Background(), &fftypes.Subscription{}, true) 143 assert.Regexp(t, "FF10114", err) 144 assert.NoError(t, mock.ExpectationsWereMet()) 145 } 146 147 func TestUpsertSubscriptionFailSelect(t *testing.T) { 148 s, mock := newMockProvider().init() 149 mock.ExpectBegin() 150 mock.ExpectQuery("SELECT .*").WillReturnError(fmt.Errorf("pop")) 151 mock.ExpectRollback() 152 err := s.UpsertSubscription(context.Background(), &fftypes.Subscription{SubscriptionRef: fftypes.SubscriptionRef{Name: "name1"}}, true) 153 assert.Regexp(t, "FF10115", err) 154 assert.NoError(t, mock.ExpectationsWereMet()) 155 } 156 157 func TestUpsertSubscriptionFailInsert(t *testing.T) { 158 s, mock := newMockProvider().init() 159 mock.ExpectBegin() 160 mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{})) 161 mock.ExpectExec("INSERT .*").WillReturnError(fmt.Errorf("pop")) 162 mock.ExpectRollback() 163 err := s.UpsertSubscription(context.Background(), &fftypes.Subscription{SubscriptionRef: fftypes.SubscriptionRef{Name: "name1"}}, true) 164 assert.Regexp(t, "FF10116", err) 165 assert.NoError(t, mock.ExpectationsWereMet()) 166 } 167 168 func TestUpsertSubscriptionFailUpdate(t *testing.T) { 169 s, mock := newMockProvider().init() 170 mock.ExpectBegin() 171 mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"name"}). 172 AddRow("name1")) 173 mock.ExpectExec("UPDATE .*").WillReturnError(fmt.Errorf("pop")) 174 mock.ExpectRollback() 175 err := s.UpsertSubscription(context.Background(), &fftypes.Subscription{SubscriptionRef: fftypes.SubscriptionRef{Name: "name1"}}, true) 176 assert.Regexp(t, "FF10117", err) 177 assert.NoError(t, mock.ExpectationsWereMet()) 178 } 179 180 func TestUpsertSubscriptionFailCommit(t *testing.T) { 181 s, mock := newMockProvider().init() 182 mock.ExpectBegin() 183 mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"name"})) 184 mock.ExpectExec("INSERT .*").WillReturnResult(sqlmock.NewResult(1, 1)) 185 mock.ExpectCommit().WillReturnError(fmt.Errorf("pop")) 186 err := s.UpsertSubscription(context.Background(), &fftypes.Subscription{SubscriptionRef: fftypes.SubscriptionRef{Name: "name1"}}, true) 187 assert.Regexp(t, "FF10119", err) 188 assert.NoError(t, mock.ExpectationsWereMet()) 189 } 190 191 func TestGetSubscriptionByIDSelectFail(t *testing.T) { 192 s, mock := newMockProvider().init() 193 mock.ExpectQuery("SELECT .*").WillReturnError(fmt.Errorf("pop")) 194 _, err := s.GetSubscriptionByName(context.Background(), "ns1", "name1") 195 assert.Regexp(t, "FF10115", err) 196 assert.NoError(t, mock.ExpectationsWereMet()) 197 } 198 199 func TestGetSubscriptionByIDNotFound(t *testing.T) { 200 s, mock := newMockProvider().init() 201 mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"namespace", "name"})) 202 msg, err := s.GetSubscriptionByName(context.Background(), "ns1", "name1") 203 assert.NoError(t, err) 204 assert.Nil(t, msg) 205 assert.NoError(t, mock.ExpectationsWereMet()) 206 } 207 208 func TestGetSubscriptionByIDScanFail(t *testing.T) { 209 s, mock := newMockProvider().init() 210 mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"namespace"}).AddRow("only one")) 211 _, err := s.GetSubscriptionByName(context.Background(), "ns1", "name1") 212 assert.Regexp(t, "FF10121", err) 213 assert.NoError(t, mock.ExpectationsWereMet()) 214 } 215 216 func TestGetSubscriptionQueryFail(t *testing.T) { 217 s, mock := newMockProvider().init() 218 mock.ExpectQuery("SELECT .*").WillReturnError(fmt.Errorf("pop")) 219 f := database.SubscriptionQueryFactory.NewFilter(context.Background()).Eq("name", "") 220 _, err := s.GetSubscriptions(context.Background(), f) 221 assert.Regexp(t, "FF10115", err) 222 assert.NoError(t, mock.ExpectationsWereMet()) 223 } 224 225 func TestGetSubscriptionBuildQueryFail(t *testing.T) { 226 s, _ := newMockProvider().init() 227 f := database.SubscriptionQueryFactory.NewFilter(context.Background()).Eq("name", map[bool]bool{true: false}) 228 _, err := s.GetSubscriptions(context.Background(), f) 229 assert.Regexp(t, "FF10149.*type", err) 230 } 231 232 func TestGetSubscriptionReadMessageFail(t *testing.T) { 233 s, mock := newMockProvider().init() 234 mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"ntype"}).AddRow("only one")) 235 f := database.SubscriptionQueryFactory.NewFilter(context.Background()).Eq("name", "") 236 _, err := s.GetSubscriptions(context.Background(), f) 237 assert.Regexp(t, "FF10121", err) 238 assert.NoError(t, mock.ExpectationsWereMet()) 239 } 240 241 func TestSubscriptionUpdateBeginFail(t *testing.T) { 242 s, mock := newMockProvider().init() 243 mock.ExpectBegin().WillReturnError(fmt.Errorf("pop")) 244 u := database.SubscriptionQueryFactory.NewUpdate(context.Background()).Set("name", "anything") 245 err := s.UpdateSubscription(context.Background(), "ns1", "name1", u) 246 assert.Regexp(t, "FF10114", err) 247 } 248 249 func TestSubscriptionUpdateBuildQueryFail(t *testing.T) { 250 s, mock := newMockProvider().init() 251 mock.ExpectBegin() 252 u := database.SubscriptionQueryFactory.NewUpdate(context.Background()).Set("name", map[bool]bool{true: false}) 253 err := s.UpdateSubscription(context.Background(), "ns1", "name1", u) 254 assert.Regexp(t, "FF10149.*name", err) 255 } 256 257 func TestSubscriptionUpdateFail(t *testing.T) { 258 s, mock := newMockProvider().init() 259 mock.ExpectBegin() 260 mock.ExpectExec("UPDATE .*").WillReturnError(fmt.Errorf("pop")) 261 mock.ExpectRollback() 262 u := database.SubscriptionQueryFactory.NewUpdate(context.Background()).Set("name", fftypes.NewUUID()) 263 err := s.UpdateSubscription(context.Background(), "ns1", "name1", u) 264 assert.Regexp(t, "FF10117", err) 265 } 266 267 func TestSubscriptionDeleteBeginFail(t *testing.T) { 268 s, mock := newMockProvider().init() 269 mock.ExpectBegin().WillReturnError(fmt.Errorf("pop")) 270 err := s.DeleteSubscriptionByID(context.Background(), fftypes.NewUUID()) 271 assert.Regexp(t, "FF10114", err) 272 } 273 274 func TestSubscriptionDeleteFail(t *testing.T) { 275 s, mock := newMockProvider().init() 276 mock.ExpectBegin() 277 mock.ExpectExec("DELETE .*").WillReturnError(fmt.Errorf("pop")) 278 err := s.DeleteSubscriptionByID(context.Background(), fftypes.NewUUID()) 279 assert.Regexp(t, "FF10118", err) 280 }