github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/internal/privatemessaging/groupmanager_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 privatemessaging
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"testing"
    23  
    24  	"github.com/kaleido-io/firefly/mocks/databasemocks"
    25  	"github.com/kaleido-io/firefly/mocks/datamocks"
    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 TestGroupInitSealFail(t *testing.T) {
    33  
    34  	pm, cancel := newTestPrivateMessaging(t)
    35  	defer cancel()
    36  
    37  	err := pm.groupInit(pm.ctx, &fftypes.Identity{}, nil)
    38  	assert.Regexp(t, "FF10137", err)
    39  }
    40  
    41  func TestGroupInitWriteGroupFail(t *testing.T) {
    42  
    43  	pm, cancel := newTestPrivateMessaging(t)
    44  	defer cancel()
    45  
    46  	mdi := pm.database.(*databasemocks.Plugin)
    47  	mdi.On("UpsertGroup", mock.Anything, mock.Anything, true).Return(fmt.Errorf("pop"))
    48  
    49  	err := pm.groupInit(pm.ctx, &fftypes.Identity{}, &fftypes.Group{})
    50  	assert.Regexp(t, "pop", err)
    51  }
    52  
    53  func TestGroupInitWriteDataFail(t *testing.T) {
    54  
    55  	pm, cancel := newTestPrivateMessaging(t)
    56  	defer cancel()
    57  
    58  	mdi := pm.database.(*databasemocks.Plugin)
    59  	mdi.On("UpsertGroup", mock.Anything, mock.Anything, true).Return(nil)
    60  	mdi.On("UpsertData", mock.Anything, mock.Anything, true, false).Return(fmt.Errorf("pop"))
    61  
    62  	err := pm.groupInit(pm.ctx, &fftypes.Identity{}, &fftypes.Group{})
    63  	assert.Regexp(t, "pop", err)
    64  }
    65  
    66  func TestResolveInitGroupMissingData(t *testing.T) {
    67  	pm, cancel := newTestPrivateMessaging(t)
    68  	defer cancel()
    69  
    70  	mdm := pm.data.(*datamocks.Manager)
    71  	mdm.On("GetMessageData", pm.ctx, mock.Anything, true).Return([]*fftypes.Data{}, false, nil)
    72  
    73  	_, err := pm.ResolveInitGroup(pm.ctx, &fftypes.Message{
    74  		Header: fftypes.MessageHeader{
    75  			ID:        fftypes.NewUUID(),
    76  			Namespace: fftypes.SystemNamespace,
    77  			Tag:       string(fftypes.SystemTagDefineGroup),
    78  			Group:     fftypes.NewRandB32(),
    79  			Author:    "author1",
    80  		},
    81  	})
    82  	assert.NoError(t, err)
    83  
    84  }
    85  
    86  func TestResolveInitGroupBadData(t *testing.T) {
    87  	pm, cancel := newTestPrivateMessaging(t)
    88  	defer cancel()
    89  
    90  	mdm := pm.data.(*datamocks.Manager)
    91  	mdm.On("GetMessageData", pm.ctx, mock.Anything, true).Return([]*fftypes.Data{
    92  		{ID: fftypes.NewUUID(), Value: fftypes.Byteable(`!json`)},
    93  	}, true, nil)
    94  
    95  	_, err := pm.ResolveInitGroup(pm.ctx, &fftypes.Message{
    96  		Header: fftypes.MessageHeader{
    97  			ID:        fftypes.NewUUID(),
    98  			Namespace: fftypes.SystemNamespace,
    99  			Tag:       string(fftypes.SystemTagDefineGroup),
   100  			Group:     fftypes.NewRandB32(),
   101  			Author:    "author1",
   102  		},
   103  	})
   104  	assert.NoError(t, err)
   105  
   106  }
   107  
   108  func TestResolveInitGroupBadValidation(t *testing.T) {
   109  	pm, cancel := newTestPrivateMessaging(t)
   110  	defer cancel()
   111  
   112  	mdm := pm.data.(*datamocks.Manager)
   113  	mdm.On("GetMessageData", pm.ctx, mock.Anything, true).Return([]*fftypes.Data{
   114  		{ID: fftypes.NewUUID(), Value: fftypes.Byteable(`{}`)},
   115  	}, true, nil)
   116  
   117  	_, err := pm.ResolveInitGroup(pm.ctx, &fftypes.Message{
   118  		Header: fftypes.MessageHeader{
   119  			ID:        fftypes.NewUUID(),
   120  			Namespace: fftypes.SystemNamespace,
   121  			Tag:       string(fftypes.SystemTagDefineGroup),
   122  			Group:     fftypes.NewRandB32(),
   123  			Author:    "author1",
   124  		},
   125  	})
   126  	assert.NoError(t, err)
   127  
   128  }
   129  
   130  func TestResolveInitGroupBadGroupID(t *testing.T) {
   131  	pm, cancel := newTestPrivateMessaging(t)
   132  	defer cancel()
   133  
   134  	group := &fftypes.Group{
   135  		GroupIdentity: fftypes.GroupIdentity{
   136  			Name:      "group1",
   137  			Namespace: "ns1",
   138  			Members: fftypes.Members{
   139  				{Identity: "abce12345", Node: fftypes.NewUUID()},
   140  			},
   141  		},
   142  	}
   143  	group.Seal()
   144  	assert.NoError(t, group.Validate(pm.ctx, true))
   145  	b, _ := json.Marshal(&group)
   146  
   147  	mdm := pm.data.(*datamocks.Manager)
   148  	mdm.On("GetMessageData", pm.ctx, mock.Anything, true).Return([]*fftypes.Data{
   149  		{ID: fftypes.NewUUID(), Value: fftypes.Byteable(b)},
   150  	}, true, nil)
   151  
   152  	_, err := pm.ResolveInitGroup(pm.ctx, &fftypes.Message{
   153  		Header: fftypes.MessageHeader{
   154  			ID:        fftypes.NewUUID(),
   155  			Namespace: fftypes.SystemNamespace,
   156  			Tag:       string(fftypes.SystemTagDefineGroup),
   157  			Group:     fftypes.NewRandB32(),
   158  			Author:    "author1",
   159  		},
   160  	})
   161  	assert.NoError(t, err)
   162  
   163  }
   164  
   165  func TestResolveInitGroupUpsertFail(t *testing.T) {
   166  	pm, cancel := newTestPrivateMessaging(t)
   167  	defer cancel()
   168  
   169  	group := &fftypes.Group{
   170  		GroupIdentity: fftypes.GroupIdentity{
   171  			Name:      "group1",
   172  			Namespace: "ns1",
   173  			Members: fftypes.Members{
   174  				{Identity: "abce12345", Node: fftypes.NewUUID()},
   175  			},
   176  		},
   177  	}
   178  	group.Seal()
   179  	assert.NoError(t, group.Validate(pm.ctx, true))
   180  	b, _ := json.Marshal(&group)
   181  
   182  	mdm := pm.data.(*datamocks.Manager)
   183  	mdm.On("GetMessageData", pm.ctx, mock.Anything, true).Return([]*fftypes.Data{
   184  		{ID: fftypes.NewUUID(), Value: fftypes.Byteable(b)},
   185  	}, true, nil)
   186  	mdi := pm.database.(*databasemocks.Plugin)
   187  	mdi.On("UpsertGroup", pm.ctx, mock.Anything, true).Return(fmt.Errorf("pop"))
   188  
   189  	_, err := pm.ResolveInitGroup(pm.ctx, &fftypes.Message{
   190  		Header: fftypes.MessageHeader{
   191  			ID:        fftypes.NewUUID(),
   192  			Namespace: fftypes.SystemNamespace,
   193  			Tag:       string(fftypes.SystemTagDefineGroup),
   194  			Group:     group.Hash,
   195  			Author:    "author1",
   196  		},
   197  	})
   198  	assert.EqualError(t, err, "pop")
   199  
   200  }
   201  
   202  func TestResolveInitGroupNewOk(t *testing.T) {
   203  	pm, cancel := newTestPrivateMessaging(t)
   204  	defer cancel()
   205  
   206  	group := &fftypes.Group{
   207  		GroupIdentity: fftypes.GroupIdentity{
   208  			Name:      "group1",
   209  			Namespace: "ns1",
   210  			Members: fftypes.Members{
   211  				{Identity: "abce12345", Node: fftypes.NewUUID()},
   212  			},
   213  		},
   214  	}
   215  	group.Seal()
   216  	assert.NoError(t, group.Validate(pm.ctx, true))
   217  	b, _ := json.Marshal(&group)
   218  
   219  	mdm := pm.data.(*datamocks.Manager)
   220  	mdm.On("GetMessageData", pm.ctx, mock.Anything, true).Return([]*fftypes.Data{
   221  		{ID: fftypes.NewUUID(), Value: fftypes.Byteable(b)},
   222  	}, true, nil)
   223  	mdi := pm.database.(*databasemocks.Plugin)
   224  	mdi.On("UpsertGroup", pm.ctx, mock.Anything, true).Return(nil)
   225  	mdi.On("UpsertEvent", pm.ctx, mock.Anything, false).Return(nil)
   226  
   227  	group, err := pm.ResolveInitGroup(pm.ctx, &fftypes.Message{
   228  		Header: fftypes.MessageHeader{
   229  			ID:        fftypes.NewUUID(),
   230  			Namespace: fftypes.SystemNamespace,
   231  			Tag:       string(fftypes.SystemTagDefineGroup),
   232  			Group:     group.Hash,
   233  			Author:    "author1",
   234  		},
   235  	})
   236  	assert.NoError(t, err)
   237  
   238  }
   239  
   240  func TestResolveInitGroupNewEventFail(t *testing.T) {
   241  	pm, cancel := newTestPrivateMessaging(t)
   242  	defer cancel()
   243  
   244  	group := &fftypes.Group{
   245  		GroupIdentity: fftypes.GroupIdentity{
   246  			Name:      "group1",
   247  			Namespace: "ns1",
   248  			Members: fftypes.Members{
   249  				{Identity: "abce12345", Node: fftypes.NewUUID()},
   250  			},
   251  		},
   252  	}
   253  	group.Seal()
   254  	assert.NoError(t, group.Validate(pm.ctx, true))
   255  	b, _ := json.Marshal(&group)
   256  
   257  	mdm := pm.data.(*datamocks.Manager)
   258  	mdm.On("GetMessageData", pm.ctx, mock.Anything, true).Return([]*fftypes.Data{
   259  		{ID: fftypes.NewUUID(), Value: fftypes.Byteable(b)},
   260  	}, true, nil)
   261  	mdi := pm.database.(*databasemocks.Plugin)
   262  	mdi.On("UpsertGroup", pm.ctx, mock.Anything, true).Return(nil)
   263  	mdi.On("UpsertEvent", pm.ctx, mock.Anything, false).Return(fmt.Errorf("pop"))
   264  
   265  	_, err := pm.ResolveInitGroup(pm.ctx, &fftypes.Message{
   266  		Header: fftypes.MessageHeader{
   267  			ID:        fftypes.NewUUID(),
   268  			Namespace: fftypes.SystemNamespace,
   269  			Tag:       string(fftypes.SystemTagDefineGroup),
   270  			Group:     group.Hash,
   271  			Author:    "author1",
   272  		},
   273  	})
   274  	assert.EqualError(t, err, "pop")
   275  
   276  }
   277  
   278  func TestResolveInitGroupExistingOK(t *testing.T) {
   279  	pm, cancel := newTestPrivateMessaging(t)
   280  	defer cancel()
   281  
   282  	mdi := pm.database.(*databasemocks.Plugin)
   283  	mdi.On("UpsertGroup", pm.ctx, mock.Anything, true).Return(nil)
   284  	mdi.On("GetGroupByHash", pm.ctx, mock.Anything).Return(&fftypes.Group{}, nil)
   285  
   286  	_, err := pm.ResolveInitGroup(pm.ctx, &fftypes.Message{
   287  		Header: fftypes.MessageHeader{
   288  			ID:        fftypes.NewUUID(),
   289  			Namespace: "ns1",
   290  			Tag:       "mytag",
   291  			Group:     fftypes.NewRandB32(),
   292  			Author:    "author1",
   293  		},
   294  	})
   295  	assert.NoError(t, err)
   296  }
   297  
   298  func TestResolveInitGroupExistingFail(t *testing.T) {
   299  	pm, cancel := newTestPrivateMessaging(t)
   300  	defer cancel()
   301  
   302  	mdi := pm.database.(*databasemocks.Plugin)
   303  	mdi.On("GetGroupByHash", pm.ctx, mock.Anything).Return(nil, fmt.Errorf("pop"))
   304  
   305  	_, err := pm.ResolveInitGroup(pm.ctx, &fftypes.Message{
   306  		Header: fftypes.MessageHeader{
   307  			ID:        fftypes.NewUUID(),
   308  			Namespace: "ns1",
   309  			Tag:       "mytag",
   310  			Group:     fftypes.NewRandB32(),
   311  			Author:    "author1",
   312  		},
   313  	})
   314  	assert.EqualError(t, err, "pop")
   315  }
   316  
   317  func TestResolveInitGroupExistingNotFound(t *testing.T) {
   318  	pm, cancel := newTestPrivateMessaging(t)
   319  	defer cancel()
   320  
   321  	mdi := pm.database.(*databasemocks.Plugin)
   322  	mdi.On("GetGroupByHash", pm.ctx, mock.Anything).Return(nil, nil)
   323  
   324  	group, err := pm.ResolveInitGroup(pm.ctx, &fftypes.Message{
   325  		Header: fftypes.MessageHeader{
   326  			ID:        fftypes.NewUUID(),
   327  			Namespace: "ns1",
   328  			Tag:       "mytag",
   329  			Group:     fftypes.NewRandB32(),
   330  			Author:    "author1",
   331  		},
   332  	})
   333  	assert.NoError(t, err)
   334  	assert.Nil(t, group)
   335  }
   336  
   337  func TestGetGroupByIDOk(t *testing.T) {
   338  	pm, cancel := newTestPrivateMessaging(t)
   339  	defer cancel()
   340  
   341  	groupID := fftypes.NewRandB32()
   342  	mdi := pm.database.(*databasemocks.Plugin)
   343  	mdi.On("GetGroupByHash", pm.ctx, mock.Anything).Return(&fftypes.Group{Hash: groupID}, nil)
   344  
   345  	group, err := pm.GetGroupByID(pm.ctx, groupID.String())
   346  	assert.NoError(t, err)
   347  	assert.Equal(t, *groupID, *group.Hash)
   348  }
   349  
   350  func TestGetGroupByIDBadID(t *testing.T) {
   351  	pm, cancel := newTestPrivateMessaging(t)
   352  	defer cancel()
   353  	_, err := pm.GetGroupByID(pm.ctx, "!wrong")
   354  	assert.Regexp(t, "FF10232", err)
   355  }
   356  
   357  func TestGetGroupsOk(t *testing.T) {
   358  	pm, cancel := newTestPrivateMessaging(t)
   359  	defer cancel()
   360  
   361  	mdi := pm.database.(*databasemocks.Plugin)
   362  	mdi.On("GetGroups", pm.ctx, mock.Anything).Return([]*fftypes.Group{}, nil)
   363  
   364  	fb := database.GroupQueryFactory.NewFilter(pm.ctx)
   365  	groups, err := pm.GetGroups(pm.ctx, fb.And(fb.Eq("description", "mygroup")))
   366  	assert.NoError(t, err)
   367  	assert.Empty(t, groups)
   368  }
   369  
   370  func TestGetGroupNodesCache(t *testing.T) {
   371  	pm, cancel := newTestPrivateMessaging(t)
   372  	defer cancel()
   373  
   374  	node1 := fftypes.NewUUID()
   375  	group := &fftypes.Group{
   376  		GroupIdentity: fftypes.GroupIdentity{
   377  			Members: fftypes.Members{
   378  				&fftypes.Member{Node: node1},
   379  			},
   380  		},
   381  	}
   382  	group.Seal()
   383  
   384  	mdi := pm.database.(*databasemocks.Plugin)
   385  	mdi.On("GetGroupByHash", pm.ctx, mock.Anything).Return(group, nil).Once()
   386  	mdi.On("GetNodeByID", pm.ctx, mock.Anything).Return(&fftypes.Node{
   387  		ID: node1,
   388  	}, nil).Once()
   389  
   390  	nodes, err := pm.getGroupNodes(pm.ctx, group.Hash)
   391  	assert.NoError(t, err)
   392  	assert.Equal(t, *node1, *nodes[0].ID)
   393  
   394  	// Note this validates the cache as we only mocked the calls once
   395  	nodes, err = pm.getGroupNodes(pm.ctx, group.Hash)
   396  	assert.NoError(t, err)
   397  	assert.Equal(t, *node1, *nodes[0].ID)
   398  }
   399  
   400  func TestGetGroupNodesGetGroupFail(t *testing.T) {
   401  	pm, cancel := newTestPrivateMessaging(t)
   402  	defer cancel()
   403  
   404  	groupID := fftypes.NewRandB32()
   405  	mdi := pm.database.(*databasemocks.Plugin)
   406  	mdi.On("GetGroupByHash", pm.ctx, mock.Anything).Return(nil, fmt.Errorf("pop"))
   407  
   408  	_, err := pm.getGroupNodes(pm.ctx, groupID)
   409  	assert.EqualError(t, err, "pop")
   410  }
   411  
   412  func TestGetGroupNodesGetGroupNotFound(t *testing.T) {
   413  	pm, cancel := newTestPrivateMessaging(t)
   414  	defer cancel()
   415  
   416  	groupID := fftypes.NewRandB32()
   417  	mdi := pm.database.(*databasemocks.Plugin)
   418  	mdi.On("GetGroupByHash", pm.ctx, mock.Anything).Return(nil, nil)
   419  
   420  	_, err := pm.getGroupNodes(pm.ctx, groupID)
   421  	assert.Regexp(t, "FF10226", err)
   422  }
   423  
   424  func TestGetGroupNodesNodeLookupFail(t *testing.T) {
   425  	pm, cancel := newTestPrivateMessaging(t)
   426  	defer cancel()
   427  
   428  	node1 := fftypes.NewUUID()
   429  	group := &fftypes.Group{
   430  		GroupIdentity: fftypes.GroupIdentity{
   431  			Members: fftypes.Members{
   432  				&fftypes.Member{Node: node1},
   433  			},
   434  		},
   435  	}
   436  	group.Seal()
   437  
   438  	mdi := pm.database.(*databasemocks.Plugin)
   439  	mdi.On("GetGroupByHash", pm.ctx, mock.Anything).Return(group, nil).Once()
   440  	mdi.On("GetNodeByID", pm.ctx, uuidMatches(node1)).Return(nil, fmt.Errorf("pop")).Once()
   441  
   442  	_, err := pm.getGroupNodes(pm.ctx, group.Hash)
   443  	assert.EqualError(t, err, "pop")
   444  }
   445  
   446  func TestGetGroupNodesNodeLookupNotFound(t *testing.T) {
   447  	pm, cancel := newTestPrivateMessaging(t)
   448  	defer cancel()
   449  
   450  	node1 := fftypes.NewUUID()
   451  	group := &fftypes.Group{
   452  		GroupIdentity: fftypes.GroupIdentity{
   453  			Members: fftypes.Members{
   454  				&fftypes.Member{Node: node1},
   455  			},
   456  		},
   457  	}
   458  
   459  	mdi := pm.database.(*databasemocks.Plugin)
   460  	mdi.On("GetGroupByHash", pm.ctx, mock.Anything).Return(group, nil).Once()
   461  	mdi.On("GetNodeByID", pm.ctx, uuidMatches(node1)).Return(nil, nil).Once()
   462  
   463  	_, err := pm.getGroupNodes(pm.ctx, group.Hash)
   464  	assert.Regexp(t, "FF10224", err)
   465  }