code.vegaprotocol.io/vega@v0.79.0/core/teams/snapshot_test.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package teams_test
    17  
    18  import (
    19  	"testing"
    20  	"time"
    21  
    22  	"code.vegaprotocol.io/vega/core/types"
    23  	vgrand "code.vegaprotocol.io/vega/libs/rand"
    24  	vgtest "code.vegaprotocol.io/vega/libs/test"
    25  	"code.vegaprotocol.io/vega/paths"
    26  
    27  	"github.com/stretchr/testify/assert"
    28  	"github.com/stretchr/testify/require"
    29  )
    30  
    31  func TestTakingAndRestoringSnapshotSucceeds(t *testing.T) {
    32  	ctx := vgtest.VegaContext("chainid", 100)
    33  
    34  	vegaPath := paths.New(t.TempDir())
    35  	now := time.Now()
    36  
    37  	te1 := newEngine(t)
    38  	snapshotEngine1 := newSnapshotEngine(t, vegaPath, now, te1.engine)
    39  	closeSnapshotEngine1 := vgtest.OnlyOnce(snapshotEngine1.Close)
    40  	defer closeSnapshotEngine1()
    41  
    42  	require.NoError(t, snapshotEngine1.Start(ctx))
    43  
    44  	teamID1 := newTeamID(t)
    45  	referrer1 := newPartyID(t)
    46  	name1 := vgrand.RandomStr(5)
    47  	teamURL1 := "https://" + name1 + ".io"
    48  	avatarURL1 := "https://avatar." + name1 + ".io"
    49  
    50  	expectTeamCreatedEvent(t, te1)
    51  	team1CreationDate := time.Now()
    52  	te1.timeService.EXPECT().GetTimeNow().Return(team1CreationDate).Times(1)
    53  
    54  	require.NoError(t, te1.engine.CreateTeam(ctx, referrer1, teamID1, createTeamCmd(t, name1, teamURL1, avatarURL1)))
    55  
    56  	teamID2 := newTeamID(t)
    57  	referrer2 := newPartyID(t)
    58  	name2 := vgrand.RandomStr(5)
    59  	teamURL2 := "https://" + name2 + ".io"
    60  	avatarURL2 := "https://avatar." + name2 + ".io"
    61  
    62  	expectTeamCreatedEvent(t, te1)
    63  	team2CreationDate := time.Now()
    64  	te1.timeService.EXPECT().GetTimeNow().Return(team2CreationDate).Times(1)
    65  	require.NoError(t, te1.engine.CreateTeam(ctx, referrer2, teamID2, createTeamCmd(t, name2, teamURL2, avatarURL2)))
    66  
    67  	referee1 := newPartyID(t)
    68  	expectRefereeJoinedTeamEvent(t, te1)
    69  	referee1JoiningDate := time.Now()
    70  	te1.timeService.EXPECT().GetTimeNow().Return(referee1JoiningDate).Times(1)
    71  	require.NoError(t, te1.engine.JoinTeam(ctx, referee1, joinTeamCmd(t, teamID1)))
    72  
    73  	referee2 := newPartyID(t)
    74  
    75  	expectRefereeJoinedTeamEvent(t, te1)
    76  	referee2JoiningDate := time.Now()
    77  	te1.timeService.EXPECT().GetTimeNow().Return(referee2JoiningDate).Times(1)
    78  	require.NoError(t, te1.engine.JoinTeam(ctx, referee2, joinTeamCmd(t, teamID1)))
    79  
    80  	// This will occur on next epoch, after the snapshot. This help to ensure
    81  	// team switches are properly snapshot.
    82  	require.NoError(t, te1.engine.JoinTeam(ctx, referee2, joinTeamCmd(t, teamID2)))
    83  	require.True(t, te1.engine.IsTeamMember(referee2))
    84  
    85  	referee3 := newPartyID(t)
    86  
    87  	// Closing the team2 to check the allow list is properly snapshot.
    88  	expectTeamUpdatedEvent(t, te1)
    89  	require.NoError(t, te1.engine.UpdateTeam(ctx, referrer2, teamID2, updateTeamCmd(t, name2, teamURL2, avatarURL2, true, []string{referee3.String()})))
    90  
    91  	// Take a snapshot.
    92  	hash1, err := snapshotEngine1.SnapshotNow(ctx)
    93  	require.NoError(t, err)
    94  
    95  	expectRefereeSwitchedTeamEvent(t, te1)
    96  	referee2JoiningDate2 := time.Now()
    97  	nextEpoch(t, ctx, te1, referee2JoiningDate2)
    98  
    99  	expectRefereeJoinedTeamEvent(t, te1)
   100  	referee3JoiningDate := time.Now()
   101  	te1.timeService.EXPECT().GetTimeNow().Return(referee3JoiningDate).Times(1)
   102  	require.NoError(t, te1.engine.JoinTeam(ctx, referee3, joinTeamCmd(t, teamID2)))
   103  
   104  	assertEqualTeams(t, []types.Team{
   105  		{
   106  			ID: teamID1,
   107  			Referrer: &types.Membership{
   108  				PartyID:        referrer1,
   109  				JoinedAt:       team1CreationDate,
   110  				StartedAtEpoch: te1.currentEpoch - 1,
   111  			},
   112  			Referees: []*types.Membership{
   113  				{
   114  					PartyID:        referee1,
   115  					JoinedAt:       referee1JoiningDate,
   116  					StartedAtEpoch: te1.currentEpoch - 1,
   117  				},
   118  			},
   119  			Name:      name1,
   120  			TeamURL:   teamURL1,
   121  			AvatarURL: avatarURL1,
   122  			CreatedAt: team1CreationDate,
   123  		}, {
   124  			ID: teamID2,
   125  			Referrer: &types.Membership{
   126  				PartyID:        referrer2,
   127  				JoinedAt:       team2CreationDate,
   128  				StartedAtEpoch: te1.currentEpoch - 1,
   129  			},
   130  			Referees: []*types.Membership{
   131  				{
   132  					PartyID:        referee2,
   133  					JoinedAt:       referee2JoiningDate2,
   134  					StartedAtEpoch: te1.currentEpoch,
   135  				},
   136  				{
   137  					PartyID:        referee3,
   138  					JoinedAt:       referee3JoiningDate,
   139  					StartedAtEpoch: te1.currentEpoch,
   140  				},
   141  			},
   142  			Name:      name2,
   143  			TeamURL:   teamURL2,
   144  			AvatarURL: avatarURL2,
   145  			CreatedAt: team2CreationDate,
   146  			Closed:    true,
   147  			AllowList: []types.PartyID{referee3},
   148  		},
   149  	}, te1.engine.ListTeams())
   150  
   151  	state1 := map[string][]byte{}
   152  	for _, key := range te1.engine.Keys() {
   153  		state, additionalProvider, err := te1.engine.GetState(key)
   154  		require.NoError(t, err)
   155  		assert.Empty(t, additionalProvider)
   156  		state1[key] = state
   157  	}
   158  
   159  	closeSnapshotEngine1()
   160  
   161  	// Reload the engine using the previous snapshot.
   162  
   163  	te2 := newEngine(t)
   164  	snapshotEngine2 := newSnapshotEngine(t, vegaPath, now, te2.engine)
   165  	defer snapshotEngine2.Close()
   166  
   167  	// This triggers the state restoration from the local snapshot.
   168  	require.NoError(t, snapshotEngine2.Start(ctx))
   169  
   170  	// Comparing the hash after restoration, to ensure it produces the same result.
   171  	hash2, _, _ := snapshotEngine2.Info()
   172  	require.Equal(t, hash1, hash2)
   173  
   174  	expectRefereeSwitchedTeamEvent(t, te2)
   175  	nextEpoch(t, ctx, te2, referee2JoiningDate2)
   176  
   177  	expectRefereeJoinedTeamEvent(t, te2)
   178  	te2.timeService.EXPECT().GetTimeNow().Return(referee3JoiningDate).Times(1)
   179  	require.NoError(t, te2.engine.JoinTeam(ctx, referee3, joinTeamCmd(t, teamID2)))
   180  
   181  	assertEqualTeams(t, []types.Team{
   182  		{
   183  			ID: teamID1,
   184  			Referrer: &types.Membership{
   185  				PartyID:        referrer1,
   186  				JoinedAt:       team1CreationDate,
   187  				StartedAtEpoch: te2.currentEpoch - 1,
   188  			},
   189  			Referees: []*types.Membership{
   190  				{
   191  					PartyID:        referee1,
   192  					JoinedAt:       referee1JoiningDate,
   193  					StartedAtEpoch: te2.currentEpoch - 1,
   194  				},
   195  			},
   196  			Name:      name1,
   197  			TeamURL:   teamURL1,
   198  			AvatarURL: avatarURL1,
   199  			CreatedAt: team1CreationDate,
   200  		}, {
   201  			ID: teamID2,
   202  			Referrer: &types.Membership{
   203  				PartyID:        referrer2,
   204  				JoinedAt:       team2CreationDate,
   205  				StartedAtEpoch: te2.currentEpoch - 1,
   206  			},
   207  			Name:      name2,
   208  			TeamURL:   teamURL2,
   209  			AvatarURL: avatarURL2,
   210  			Referees: []*types.Membership{
   211  				{
   212  					PartyID:        referee2,
   213  					JoinedAt:       referee2JoiningDate2,
   214  					StartedAtEpoch: te2.currentEpoch,
   215  				},
   216  				{
   217  					PartyID:        referee3,
   218  					JoinedAt:       referee3JoiningDate,
   219  					StartedAtEpoch: te2.currentEpoch,
   220  				},
   221  			},
   222  			CreatedAt: team2CreationDate,
   223  			Closed:    true,
   224  			AllowList: []types.PartyID{referee3},
   225  		},
   226  	}, te2.engine.ListTeams())
   227  
   228  	state2 := map[string][]byte{}
   229  	for _, key := range te2.engine.Keys() {
   230  		state, additionalProvider, err := te2.engine.GetState(key)
   231  		require.NoError(t, err)
   232  		assert.Empty(t, additionalProvider)
   233  		state2[key] = state
   234  	}
   235  
   236  	for key := range state1 {
   237  		assert.Equalf(t, state1[key], state2[key], "Key %q does not have the same data", key)
   238  	}
   239  }