github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/internal/database/sqlcommon/nonce_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 TestNoncesE2EWithDB(t *testing.T) {
    33  	log.SetLevel("trace")
    34  
    35  	s := newQLTestProvider(t)
    36  	defer s.Close()
    37  	ctx := context.Background()
    38  
    39  	// Create a new nonce entry
    40  	nonceZero := &fftypes.Nonce{
    41  		Context: fftypes.NewRandB32(),
    42  		Group:   fftypes.NewRandB32(),
    43  		Topic:   "topic12345",
    44  	}
    45  	err := s.UpsertNonceNext(ctx, nonceZero)
    46  	assert.NoError(t, err)
    47  
    48  	// Check we get the exact same nonce back
    49  	nonceRead, err := s.GetNonce(ctx, nonceZero.Context)
    50  	assert.NoError(t, err)
    51  	assert.NotNil(t, nonceRead)
    52  	nonceJson, _ := json.Marshal(&nonceZero)
    53  	nonceReadJson, _ := json.Marshal(&nonceRead)
    54  	assert.Equal(t, string(nonceJson), string(nonceReadJson))
    55  
    56  	// Update the nonce (this is testing what's possible at the database layer,
    57  	// and does not account for the verification that happens at the higher level)
    58  	var nonceUpdated fftypes.Nonce
    59  	nonceUpdated = *nonceZero
    60  
    61  	// Increment a couple of times
    62  	err = s.UpsertNonceNext(context.Background(), &nonceUpdated)
    63  	assert.NoError(t, err)
    64  	assert.Equal(t, int64(1), nonceUpdated.Nonce)
    65  	err = s.UpsertNonceNext(context.Background(), &nonceUpdated)
    66  	assert.NoError(t, err)
    67  	assert.Equal(t, int64(2), nonceUpdated.Nonce)
    68  
    69  	// Check we get the exact same data back
    70  	nonceRead, err = s.GetNonce(ctx, nonceUpdated.Context)
    71  	assert.NoError(t, err)
    72  	nonceJson, _ = json.Marshal(&nonceUpdated)
    73  	nonceReadJson, _ = json.Marshal(&nonceRead)
    74  	assert.Equal(t, string(nonceJson), string(nonceReadJson))
    75  
    76  	// Query back the nonce
    77  	fb := database.NonceQueryFactory.NewFilter(ctx)
    78  	filter := fb.And(
    79  		fb.Eq("context", nonceUpdated.Context),
    80  		fb.Eq("nonce", nonceUpdated.Nonce),
    81  		fb.Eq("group", nonceUpdated.Group),
    82  		fb.Eq("topic", nonceUpdated.Topic),
    83  	)
    84  	nonceRes, err := s.GetNonces(ctx, filter)
    85  	assert.NoError(t, err)
    86  	assert.Equal(t, 1, len(nonceRes))
    87  	nonceReadJson, _ = json.Marshal(nonceRes[0])
    88  	assert.Equal(t, string(nonceJson), string(nonceReadJson))
    89  
    90  	// Test delete
    91  	err = s.DeleteNonce(ctx, nonceUpdated.Context)
    92  	assert.NoError(t, err)
    93  	nonces, err := s.GetNonces(ctx, filter)
    94  	assert.NoError(t, err)
    95  	assert.Equal(t, 0, len(nonces))
    96  
    97  }
    98  
    99  func TestUpsertNonceFailBegin(t *testing.T) {
   100  	s, mock := newMockProvider().init()
   101  	mock.ExpectBegin().WillReturnError(fmt.Errorf("pop"))
   102  	err := s.UpsertNonceNext(context.Background(), &fftypes.Nonce{})
   103  	assert.Regexp(t, "FF10114", err)
   104  	assert.NoError(t, mock.ExpectationsWereMet())
   105  }
   106  
   107  func TestUpsertNonceFailSelect(t *testing.T) {
   108  	s, mock := newMockProvider().init()
   109  	mock.ExpectBegin()
   110  	mock.ExpectQuery("SELECT .*").WillReturnError(fmt.Errorf("pop"))
   111  	mock.ExpectRollback()
   112  	err := s.UpsertNonceNext(context.Background(), &fftypes.Nonce{Context: fftypes.NewRandB32()})
   113  	assert.Regexp(t, "FF10115", err)
   114  	assert.NoError(t, mock.ExpectationsWereMet())
   115  }
   116  
   117  func TestUpsertNonceFailInsert(t *testing.T) {
   118  	s, mock := newMockProvider().init()
   119  	mock.ExpectBegin()
   120  	mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{}))
   121  	mock.ExpectExec("INSERT .*").WillReturnError(fmt.Errorf("pop"))
   122  	mock.ExpectRollback()
   123  	err := s.UpsertNonceNext(context.Background(), &fftypes.Nonce{Context: fftypes.NewRandB32()})
   124  	assert.Regexp(t, "FF10116", err)
   125  	assert.NoError(t, mock.ExpectationsWereMet())
   126  }
   127  
   128  func TestUpsertNonceFailScan(t *testing.T) {
   129  	s, mock := newMockProvider().init()
   130  	mock.ExpectBegin()
   131  	mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{}).AddRow())
   132  	mock.ExpectRollback()
   133  	err := s.UpsertNonceNext(context.Background(), &fftypes.Nonce{Context: fftypes.NewRandB32()})
   134  	assert.Regexp(t, "FF10121", err)
   135  	assert.NoError(t, mock.ExpectationsWereMet())
   136  }
   137  
   138  func TestUpsertNonceFailUpdate(t *testing.T) {
   139  	s, mock := newMockProvider().init()
   140  	mock.ExpectBegin()
   141  	mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"nonce", "sequence"}).AddRow(int64(12345), int64(11111)))
   142  	mock.ExpectExec("UPDATE .*").WillReturnError(fmt.Errorf("pop"))
   143  	mock.ExpectRollback()
   144  	err := s.UpsertNonceNext(context.Background(), &fftypes.Nonce{Context: fftypes.NewRandB32()})
   145  	assert.Regexp(t, "FF10117", err)
   146  	assert.NoError(t, mock.ExpectationsWereMet())
   147  }
   148  
   149  func TestGetNonceSelectFail(t *testing.T) {
   150  	s, mock := newMockProvider().init()
   151  	mock.ExpectQuery("SELECT .*").WillReturnError(fmt.Errorf("pop"))
   152  	_, err := s.GetNonce(context.Background(), fftypes.NewRandB32())
   153  	assert.Regexp(t, "FF10115", err)
   154  	assert.NoError(t, mock.ExpectationsWereMet())
   155  }
   156  
   157  func TestGetNonceNotFound(t *testing.T) {
   158  	s, mock := newMockProvider().init()
   159  	mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"context", "nonce", "group_hash", "topic"}))
   160  	msg, err := s.GetNonce(context.Background(), fftypes.NewRandB32())
   161  	assert.NoError(t, err)
   162  	assert.Nil(t, msg)
   163  	assert.NoError(t, mock.ExpectationsWereMet())
   164  }
   165  
   166  func TestGetNonceScanFail(t *testing.T) {
   167  	s, mock := newMockProvider().init()
   168  	mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"context"}).AddRow("only one"))
   169  	_, err := s.GetNonce(context.Background(), fftypes.NewRandB32())
   170  	assert.Regexp(t, "FF10121", err)
   171  	assert.NoError(t, mock.ExpectationsWereMet())
   172  }
   173  
   174  func TestGetNonceQueryFail(t *testing.T) {
   175  	s, mock := newMockProvider().init()
   176  	mock.ExpectQuery("SELECT .*").WillReturnError(fmt.Errorf("pop"))
   177  	f := database.NonceQueryFactory.NewFilter(context.Background()).Eq("context", "")
   178  	_, err := s.GetNonces(context.Background(), f)
   179  	assert.Regexp(t, "FF10115", err)
   180  	assert.NoError(t, mock.ExpectationsWereMet())
   181  }
   182  
   183  func TestGetNonceBuildQueryFail(t *testing.T) {
   184  	s, _ := newMockProvider().init()
   185  	f := database.NonceQueryFactory.NewFilter(context.Background()).Eq("context", map[bool]bool{true: false})
   186  	_, err := s.GetNonces(context.Background(), f)
   187  	assert.Regexp(t, "FF10149.*context", err)
   188  }
   189  
   190  func TestGetNonceReadMessageFail(t *testing.T) {
   191  	s, mock := newMockProvider().init()
   192  	mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"context"}).AddRow("only one"))
   193  	f := database.NonceQueryFactory.NewFilter(context.Background()).Eq("topic", "")
   194  	_, err := s.GetNonces(context.Background(), f)
   195  	assert.Regexp(t, "FF10121", err)
   196  	assert.NoError(t, mock.ExpectationsWereMet())
   197  }
   198  
   199  func TestNonceDeleteBeginFail(t *testing.T) {
   200  	s, mock := newMockProvider().init()
   201  	mock.ExpectBegin().WillReturnError(fmt.Errorf("pop"))
   202  	err := s.DeleteNonce(context.Background(), fftypes.NewRandB32())
   203  	assert.Regexp(t, "FF10114", err)
   204  }
   205  
   206  func TestNonceDeleteFail(t *testing.T) {
   207  	s, mock := newMockProvider().init()
   208  	mock.ExpectBegin()
   209  	mock.ExpectExec("DELETE .*").WillReturnError(fmt.Errorf("pop"))
   210  	mock.ExpectRollback()
   211  	err := s.DeleteNonce(context.Background(), fftypes.NewRandB32())
   212  	assert.Regexp(t, "FF10118", err)
   213  }