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  }