github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/internal/database/sqlcommon/namespace_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 TestNamespacesE2EWithDB(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 namespace entry
    40  	namespace := &fftypes.Namespace{
    41  		ID:      nil, // generated for us
    42  		Message: fftypes.NewUUID(),
    43  		Type:    fftypes.NamespaceTypeLocal,
    44  		Name:    "namespace1",
    45  		Created: fftypes.Now(),
    46  	}
    47  	err := s.UpsertNamespace(ctx, namespace, true)
    48  	assert.NoError(t, err)
    49  
    50  	// Check we get the exact same namespace back
    51  	namespaceRead, err := s.GetNamespace(ctx, namespace.Name)
    52  	assert.NoError(t, err)
    53  	assert.NotNil(t, namespaceRead)
    54  	namespaceJson, _ := json.Marshal(&namespace)
    55  	namespaceReadJson, _ := json.Marshal(&namespaceRead)
    56  	assert.Equal(t, string(namespaceJson), string(namespaceReadJson))
    57  
    58  	// Rejects attempt to update ID
    59  	err = s.UpsertNamespace(context.Background(), &fftypes.Namespace{
    60  		ID:   fftypes.NewUUID(),
    61  		Name: "namespace1",
    62  	}, true)
    63  	assert.Equal(t, database.IDMismatch, err)
    64  
    65  	// Update the namespace (this is testing what's possible at the database layer,
    66  	// and does not account for the verification that happens at the higher level)
    67  	namespaceUpdated := &fftypes.Namespace{
    68  		ID:          nil, // as long as we don't specify one we're fine
    69  		Message:     fftypes.NewUUID(),
    70  		Type:        fftypes.NamespaceTypeBroadcast,
    71  		Name:        "namespace1",
    72  		Description: "description1",
    73  		Created:     fftypes.Now(),
    74  	}
    75  	err = s.UpsertNamespace(context.Background(), namespaceUpdated, true)
    76  	assert.NoError(t, err)
    77  
    78  	// Check we get the exact same data back - note the removal of one of the namespace elements
    79  	namespaceRead, err = s.GetNamespace(ctx, namespace.Name)
    80  	assert.NoError(t, err)
    81  	namespaceJson, _ = json.Marshal(&namespaceUpdated)
    82  	namespaceReadJson, _ = json.Marshal(&namespaceRead)
    83  	assert.Equal(t, string(namespaceJson), string(namespaceReadJson))
    84  
    85  	// Query back the namespace
    86  	fb := database.NamespaceQueryFactory.NewFilter(ctx)
    87  	filter := fb.And(
    88  		fb.Eq("type", string(namespaceUpdated.Type)),
    89  		fb.Eq("name", namespaceUpdated.Name),
    90  	)
    91  	namespaceRes, err := s.GetNamespaces(ctx, filter)
    92  	assert.NoError(t, err)
    93  	assert.Equal(t, 1, len(namespaceRes))
    94  	namespaceReadJson, _ = json.Marshal(namespaceRes[0])
    95  	assert.Equal(t, string(namespaceJson), string(namespaceReadJson))
    96  
    97  	// Update
    98  	updateTime := fftypes.Now()
    99  	up := database.NamespaceQueryFactory.NewUpdate(ctx).Set("created", updateTime)
   100  	err = s.UpdateNamespace(ctx, namespaceUpdated.ID, up)
   101  	assert.NoError(t, err)
   102  
   103  	// Test find updated value
   104  	filter = fb.And(
   105  		fb.Eq("name", namespaceUpdated.Name),
   106  		fb.Eq("created", updateTime.String()),
   107  	)
   108  	namespaces, err := s.GetNamespaces(ctx, filter)
   109  	assert.NoError(t, err)
   110  	assert.Equal(t, 1, len(namespaces))
   111  
   112  	// Delete
   113  	err = s.DeleteNamespace(ctx, namespaceUpdated.ID)
   114  	assert.NoError(t, err)
   115  	namespaces, err = s.GetNamespaces(ctx, filter)
   116  	assert.NoError(t, err)
   117  	assert.Equal(t, 0, len(namespaces))
   118  }
   119  
   120  func TestUpsertNamespaceFailBegin(t *testing.T) {
   121  	s, mock := newMockProvider().init()
   122  	mock.ExpectBegin().WillReturnError(fmt.Errorf("pop"))
   123  	err := s.UpsertNamespace(context.Background(), &fftypes.Namespace{}, true)
   124  	assert.Regexp(t, "FF10114", err)
   125  	assert.NoError(t, mock.ExpectationsWereMet())
   126  }
   127  
   128  func TestUpsertNamespaceFailSelect(t *testing.T) {
   129  	s, mock := newMockProvider().init()
   130  	mock.ExpectBegin()
   131  	mock.ExpectQuery("SELECT .*").WillReturnError(fmt.Errorf("pop"))
   132  	mock.ExpectRollback()
   133  	err := s.UpsertNamespace(context.Background(), &fftypes.Namespace{Name: "name1"}, true)
   134  	assert.Regexp(t, "FF10115", err)
   135  	assert.NoError(t, mock.ExpectationsWereMet())
   136  }
   137  
   138  func TestUpsertNamespaceFailInsert(t *testing.T) {
   139  	s, mock := newMockProvider().init()
   140  	mock.ExpectBegin()
   141  	mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{}))
   142  	mock.ExpectExec("INSERT .*").WillReturnError(fmt.Errorf("pop"))
   143  	mock.ExpectRollback()
   144  	err := s.UpsertNamespace(context.Background(), &fftypes.Namespace{Name: "name1"}, true)
   145  	assert.Regexp(t, "FF10116", err)
   146  	assert.NoError(t, mock.ExpectationsWereMet())
   147  }
   148  
   149  func TestUpsertNamespaceFailUpdate(t *testing.T) {
   150  	s, mock := newMockProvider().init()
   151  	mock.ExpectBegin()
   152  	mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"name"}).
   153  		AddRow("name1"))
   154  	mock.ExpectExec("UPDATE .*").WillReturnError(fmt.Errorf("pop"))
   155  	mock.ExpectRollback()
   156  	err := s.UpsertNamespace(context.Background(), &fftypes.Namespace{Name: "name1"}, true)
   157  	assert.Regexp(t, "FF10117", err)
   158  	assert.NoError(t, mock.ExpectationsWereMet())
   159  }
   160  
   161  func TestUpsertNamespaceFailCommit(t *testing.T) {
   162  	s, mock := newMockProvider().init()
   163  	mock.ExpectBegin()
   164  	mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"name"}))
   165  	mock.ExpectExec("INSERT .*").WillReturnResult(sqlmock.NewResult(1, 1))
   166  	mock.ExpectCommit().WillReturnError(fmt.Errorf("pop"))
   167  	err := s.UpsertNamespace(context.Background(), &fftypes.Namespace{Name: "name1"}, true)
   168  	assert.Regexp(t, "FF10119", err)
   169  	assert.NoError(t, mock.ExpectationsWereMet())
   170  }
   171  
   172  func TestGetNamespaceByIDSelectFail(t *testing.T) {
   173  	s, mock := newMockProvider().init()
   174  	mock.ExpectQuery("SELECT .*").WillReturnError(fmt.Errorf("pop"))
   175  	_, err := s.GetNamespace(context.Background(), "name1")
   176  	assert.Regexp(t, "FF10115", err)
   177  	assert.NoError(t, mock.ExpectationsWereMet())
   178  }
   179  
   180  func TestGetNamespaceByIDNotFound(t *testing.T) {
   181  	s, mock := newMockProvider().init()
   182  	mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"ntype", "namespace", "name"}))
   183  	msg, err := s.GetNamespace(context.Background(), "name1")
   184  	assert.NoError(t, err)
   185  	assert.Nil(t, msg)
   186  	assert.NoError(t, mock.ExpectationsWereMet())
   187  }
   188  
   189  func TestGetNamespaceByIDScanFail(t *testing.T) {
   190  	s, mock := newMockProvider().init()
   191  	mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"ntype"}).AddRow("only one"))
   192  	_, err := s.GetNamespace(context.Background(), "name1")
   193  	assert.Regexp(t, "FF10121", err)
   194  	assert.NoError(t, mock.ExpectationsWereMet())
   195  }
   196  
   197  func TestGetNamespaceQueryFail(t *testing.T) {
   198  	s, mock := newMockProvider().init()
   199  	mock.ExpectQuery("SELECT .*").WillReturnError(fmt.Errorf("pop"))
   200  	f := database.NamespaceQueryFactory.NewFilter(context.Background()).Eq("type", "")
   201  	_, err := s.GetNamespaces(context.Background(), f)
   202  	assert.Regexp(t, "FF10115", err)
   203  	assert.NoError(t, mock.ExpectationsWereMet())
   204  }
   205  
   206  func TestGetNamespaceBuildQueryFail(t *testing.T) {
   207  	s, _ := newMockProvider().init()
   208  	f := database.NamespaceQueryFactory.NewFilter(context.Background()).Eq("type", map[bool]bool{true: false})
   209  	_, err := s.GetNamespaces(context.Background(), f)
   210  	assert.Regexp(t, "FF10149.*type", err)
   211  }
   212  
   213  func TestGetNamespaceReadMessageFail(t *testing.T) {
   214  	s, mock := newMockProvider().init()
   215  	mock.ExpectQuery("SELECT .*").WillReturnRows(sqlmock.NewRows([]string{"ntype"}).AddRow("only one"))
   216  	f := database.NamespaceQueryFactory.NewFilter(context.Background()).Eq("type", "")
   217  	_, err := s.GetNamespaces(context.Background(), f)
   218  	assert.Regexp(t, "FF10121", err)
   219  	assert.NoError(t, mock.ExpectationsWereMet())
   220  }
   221  
   222  func TestNamespaceUpdateBeginFail(t *testing.T) {
   223  	s, mock := newMockProvider().init()
   224  	mock.ExpectBegin().WillReturnError(fmt.Errorf("pop"))
   225  	u := database.NamespaceQueryFactory.NewUpdate(context.Background()).Set("name", "anything")
   226  	err := s.UpdateNamespace(context.Background(), fftypes.NewUUID(), u)
   227  	assert.Regexp(t, "FF10114", err)
   228  }
   229  
   230  func TestNamespaceUpdateBuildQueryFail(t *testing.T) {
   231  	s, mock := newMockProvider().init()
   232  	mock.ExpectBegin()
   233  	u := database.NamespaceQueryFactory.NewUpdate(context.Background()).Set("name", map[bool]bool{true: false})
   234  	err := s.UpdateNamespace(context.Background(), fftypes.NewUUID(), u)
   235  	assert.Regexp(t, "FF10149.*name", err)
   236  }
   237  
   238  func TestNamespaceUpdateFail(t *testing.T) {
   239  	s, mock := newMockProvider().init()
   240  	mock.ExpectBegin()
   241  	mock.ExpectExec("UPDATE .*").WillReturnError(fmt.Errorf("pop"))
   242  	mock.ExpectRollback()
   243  	u := database.NamespaceQueryFactory.NewUpdate(context.Background()).Set("name", fftypes.NewUUID())
   244  	err := s.UpdateNamespace(context.Background(), fftypes.NewUUID(), u)
   245  	assert.Regexp(t, "FF10117", err)
   246  }
   247  
   248  func TestNamespaceDeleteBeginFail(t *testing.T) {
   249  	s, mock := newMockProvider().init()
   250  	mock.ExpectBegin().WillReturnError(fmt.Errorf("pop"))
   251  	err := s.DeleteNamespace(context.Background(), fftypes.NewUUID())
   252  	assert.Regexp(t, "FF10114", err)
   253  }
   254  
   255  func TestNamespaceDeleteFail(t *testing.T) {
   256  	s, mock := newMockProvider().init()
   257  	mock.ExpectBegin()
   258  	mock.ExpectExec("DELETE .*").WillReturnError(fmt.Errorf("pop"))
   259  	mock.ExpectRollback()
   260  	err := s.DeleteNamespace(context.Background(), fftypes.NewUUID())
   261  	assert.Regexp(t, "FF10118", err)
   262  }