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 }