go.temporal.io/server@v1.23.0/common/archiver/filestore/history_archiver_test.go (about)

     1  // The MIT License
     2  //
     3  // Copyright (c) 2020 Temporal Technologies Inc.  All rights reserved.
     4  //
     5  // Copyright (c) 2020 Uber Technologies, Inc.
     6  //
     7  // Permission is hereby granted, free of charge, to any person obtaining a copy
     8  // of this software and associated documentation files (the "Software"), to deal
     9  // in the Software without restriction, including without limitation the rights
    10  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    11  // copies of the Software, and to permit persons to whom the Software is
    12  // furnished to do so, subject to the following conditions:
    13  //
    14  // The above copyright notice and this permission notice shall be included in
    15  // all copies or substantial portions of the Software.
    16  //
    17  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    18  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    19  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    20  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    21  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    22  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    23  // THE SOFTWARE.
    24  
    25  package filestore
    26  
    27  import (
    28  	"context"
    29  	"errors"
    30  	"os"
    31  	"path"
    32  	"testing"
    33  	"time"
    34  
    35  	enumspb "go.temporal.io/api/enums/v1"
    36  	"google.golang.org/protobuf/types/known/timestamppb"
    37  
    38  	"go.temporal.io/server/tests/testutils"
    39  
    40  	"github.com/golang/mock/gomock"
    41  	"github.com/stretchr/testify/require"
    42  	"github.com/stretchr/testify/suite"
    43  	historypb "go.temporal.io/api/history/v1"
    44  	"go.temporal.io/api/serviceerror"
    45  
    46  	archiverspb "go.temporal.io/server/api/archiver/v1"
    47  	"go.temporal.io/server/common"
    48  	"go.temporal.io/server/common/archiver"
    49  	"go.temporal.io/server/common/config"
    50  	"go.temporal.io/server/common/log"
    51  )
    52  
    53  const (
    54  	testNamespaceID          = "test-namespace-id"
    55  	testNamespace            = "test-namespace"
    56  	testWorkflowID           = "test-workflow-id"
    57  	testRunID                = "test-run-id"
    58  	testNextEventID          = 1800
    59  	testCloseFailoverVersion = int64(100)
    60  	testPageSize             = 100
    61  
    62  	testFileModeStr = "0666"
    63  	testDirModeStr  = "0766"
    64  )
    65  
    66  var (
    67  	testBranchToken = []byte{1, 2, 3}
    68  )
    69  
    70  type historyArchiverSuite struct {
    71  	*require.Assertions
    72  	suite.Suite
    73  
    74  	container          *archiver.HistoryBootstrapContainer
    75  	testArchivalURI    archiver.URI
    76  	testGetDirectory   string
    77  	historyBatchesV1   []*historypb.History
    78  	historyBatchesV100 []*historypb.History
    79  }
    80  
    81  func TestHistoryArchiverSuite(t *testing.T) {
    82  	suite.Run(t, new(historyArchiverSuite))
    83  }
    84  
    85  func (s *historyArchiverSuite) SetupSuite() {
    86  	var err error
    87  	s.testGetDirectory, err = os.MkdirTemp("", "TestGet")
    88  	s.Require().NoError(err)
    89  	s.setupHistoryDirectory()
    90  	s.testArchivalURI, err = archiver.NewURI("file:///a/b/c")
    91  	s.Require().NoError(err)
    92  }
    93  
    94  func (s *historyArchiverSuite) TearDownSuite() {
    95  	if err := os.RemoveAll(s.testGetDirectory); err != nil {
    96  		s.Fail("Failed to remove test directory %v: %v", s.testGetDirectory, err)
    97  	}
    98  }
    99  
   100  func (s *historyArchiverSuite) SetupTest() {
   101  	s.Assertions = require.New(s.T())
   102  	s.container = &archiver.HistoryBootstrapContainer{
   103  		Logger: log.NewNoopLogger(),
   104  	}
   105  }
   106  
   107  func (s *historyArchiverSuite) TestValidateURI() {
   108  	testCases := []struct {
   109  		URI         string
   110  		expectedErr error
   111  	}{
   112  		{
   113  			URI:         "wrongscheme:///a/b/c",
   114  			expectedErr: archiver.ErrURISchemeMismatch,
   115  		},
   116  		{
   117  			URI:         "file://",
   118  			expectedErr: errEmptyDirectoryPath,
   119  		},
   120  		{
   121  			URI:         "file:///a/b/c",
   122  			expectedErr: nil,
   123  		},
   124  	}
   125  
   126  	historyArchiver := s.newTestHistoryArchiver(nil)
   127  	for _, tc := range testCases {
   128  		URI, err := archiver.NewURI(tc.URI)
   129  		s.NoError(err)
   130  		s.Equal(tc.expectedErr, historyArchiver.ValidateURI(URI))
   131  	}
   132  }
   133  
   134  func (s *historyArchiverSuite) TestArchive_Fail_InvalidURI() {
   135  	historyArchiver := s.newTestHistoryArchiver(nil)
   136  	request := &archiver.ArchiveHistoryRequest{
   137  		NamespaceID:          testNamespaceID,
   138  		Namespace:            testNamespace,
   139  		WorkflowID:           testWorkflowID,
   140  		RunID:                testRunID,
   141  		BranchToken:          testBranchToken,
   142  		NextEventID:          testNextEventID,
   143  		CloseFailoverVersion: testCloseFailoverVersion,
   144  	}
   145  	URI, err := archiver.NewURI("wrongscheme://")
   146  	s.NoError(err)
   147  	err = historyArchiver.Archive(context.Background(), URI, request)
   148  	s.Error(err)
   149  }
   150  
   151  func (s *historyArchiverSuite) TestArchive_Fail_InvalidRequest() {
   152  	historyArchiver := s.newTestHistoryArchiver(nil)
   153  	request := &archiver.ArchiveHistoryRequest{
   154  		NamespaceID:          testNamespaceID,
   155  		Namespace:            testNamespace,
   156  		WorkflowID:           "", // an invalid request
   157  		RunID:                testRunID,
   158  		BranchToken:          testBranchToken,
   159  		NextEventID:          testNextEventID,
   160  		CloseFailoverVersion: testCloseFailoverVersion,
   161  	}
   162  	err := historyArchiver.Archive(context.Background(), s.testArchivalURI, request)
   163  	s.Error(err)
   164  }
   165  
   166  func (s *historyArchiverSuite) TestArchive_Fail_ErrorOnReadHistory() {
   167  	mockCtrl := gomock.NewController(s.T())
   168  	defer mockCtrl.Finish()
   169  	historyIterator := archiver.NewMockHistoryIterator(mockCtrl)
   170  	gomock.InOrder(
   171  		historyIterator.EXPECT().HasNext().Return(true),
   172  		historyIterator.EXPECT().Next(gomock.Any()).Return(nil, errors.New("some random error")),
   173  	)
   174  
   175  	historyArchiver := s.newTestHistoryArchiver(historyIterator)
   176  	request := &archiver.ArchiveHistoryRequest{
   177  		NamespaceID:          testNamespaceID,
   178  		Namespace:            testNamespace,
   179  		WorkflowID:           testWorkflowID,
   180  		RunID:                testRunID,
   181  		BranchToken:          testBranchToken,
   182  		NextEventID:          testNextEventID,
   183  		CloseFailoverVersion: testCloseFailoverVersion,
   184  	}
   185  	err := historyArchiver.Archive(context.Background(), s.testArchivalURI, request)
   186  	s.Error(err)
   187  }
   188  
   189  func (s *historyArchiverSuite) TestArchive_Fail_TimeoutWhenReadingHistory() {
   190  	mockCtrl := gomock.NewController(s.T())
   191  	defer mockCtrl.Finish()
   192  	historyIterator := archiver.NewMockHistoryIterator(mockCtrl)
   193  	gomock.InOrder(
   194  		historyIterator.EXPECT().HasNext().Return(true),
   195  		historyIterator.EXPECT().Next(gomock.Any()).Return(nil, serviceerror.NewResourceExhausted(enumspb.RESOURCE_EXHAUSTED_CAUSE_RPS_LIMIT, "")),
   196  	)
   197  
   198  	historyArchiver := s.newTestHistoryArchiver(historyIterator)
   199  	request := &archiver.ArchiveHistoryRequest{
   200  		NamespaceID:          testNamespaceID,
   201  		Namespace:            testNamespace,
   202  		WorkflowID:           testWorkflowID,
   203  		RunID:                testRunID,
   204  		BranchToken:          testBranchToken,
   205  		NextEventID:          testNextEventID,
   206  		CloseFailoverVersion: testCloseFailoverVersion,
   207  	}
   208  	err := historyArchiver.Archive(getCanceledContext(), s.testArchivalURI, request)
   209  	s.Error(err)
   210  }
   211  
   212  func (s *historyArchiverSuite) TestArchive_Fail_HistoryMutated() {
   213  	mockCtrl := gomock.NewController(s.T())
   214  	defer mockCtrl.Finish()
   215  	historyIterator := archiver.NewMockHistoryIterator(mockCtrl)
   216  	historyBatches := []*historypb.History{
   217  		{
   218  			Events: []*historypb.HistoryEvent{
   219  				{
   220  					EventId:   common.FirstEventID + 1,
   221  					EventTime: timestamppb.New(time.Now().UTC()),
   222  					Version:   testCloseFailoverVersion + 1,
   223  				},
   224  			},
   225  		},
   226  	}
   227  	historyBlob := &archiverspb.HistoryBlob{
   228  		Header: &archiverspb.HistoryBlobHeader{
   229  			IsLast: true,
   230  		},
   231  		Body: historyBatches,
   232  	}
   233  	gomock.InOrder(
   234  		historyIterator.EXPECT().HasNext().Return(true),
   235  		historyIterator.EXPECT().Next(gomock.Any()).Return(historyBlob, nil),
   236  	)
   237  
   238  	historyArchiver := s.newTestHistoryArchiver(historyIterator)
   239  	request := &archiver.ArchiveHistoryRequest{
   240  		NamespaceID:          testNamespaceID,
   241  		Namespace:            testNamespace,
   242  		WorkflowID:           testWorkflowID,
   243  		RunID:                testRunID,
   244  		BranchToken:          testBranchToken,
   245  		NextEventID:          testNextEventID,
   246  		CloseFailoverVersion: testCloseFailoverVersion,
   247  	}
   248  	err := historyArchiver.Archive(context.Background(), s.testArchivalURI, request)
   249  	s.Error(err)
   250  }
   251  
   252  func (s *historyArchiverSuite) TestArchive_Fail_NonRetryableErrorOption() {
   253  	mockCtrl := gomock.NewController(s.T())
   254  	defer mockCtrl.Finish()
   255  	historyIterator := archiver.NewMockHistoryIterator(mockCtrl)
   256  	gomock.InOrder(
   257  		historyIterator.EXPECT().HasNext().Return(true),
   258  		historyIterator.EXPECT().Next(gomock.Any()).Return(nil, errors.New("some random error")),
   259  	)
   260  
   261  	historyArchiver := s.newTestHistoryArchiver(historyIterator)
   262  	request := &archiver.ArchiveHistoryRequest{
   263  		NamespaceID:          testNamespaceID,
   264  		Namespace:            testNamespace,
   265  		WorkflowID:           testWorkflowID,
   266  		RunID:                testRunID,
   267  		BranchToken:          testBranchToken,
   268  		NextEventID:          testNextEventID,
   269  		CloseFailoverVersion: testCloseFailoverVersion,
   270  	}
   271  	nonRetryableErr := errors.New("some non-retryable error")
   272  	err := historyArchiver.Archive(context.Background(), s.testArchivalURI, request, archiver.GetNonRetryableErrorOption(nonRetryableErr))
   273  	s.Equal(nonRetryableErr, err)
   274  }
   275  
   276  func (s *historyArchiverSuite) TestArchive_Skip() {
   277  	mockCtrl := gomock.NewController(s.T())
   278  	defer mockCtrl.Finish()
   279  	historyIterator := archiver.NewMockHistoryIterator(mockCtrl)
   280  	historyBlob := &archiverspb.HistoryBlob{
   281  		Header: &archiverspb.HistoryBlobHeader{
   282  			IsLast: false,
   283  		},
   284  		Body: []*historypb.History{
   285  			{
   286  				Events: []*historypb.HistoryEvent{
   287  					{
   288  						EventId:   common.FirstEventID,
   289  						EventTime: timestamppb.New(time.Now().UTC()),
   290  						Version:   testCloseFailoverVersion,
   291  					},
   292  				},
   293  			},
   294  		},
   295  	}
   296  	gomock.InOrder(
   297  		historyIterator.EXPECT().HasNext().Return(true),
   298  		historyIterator.EXPECT().Next(gomock.Any()).Return(historyBlob, nil),
   299  		historyIterator.EXPECT().HasNext().Return(true),
   300  		historyIterator.EXPECT().Next(gomock.Any()).Return(nil, serviceerror.NewNotFound("workflow not found")),
   301  	)
   302  
   303  	historyArchiver := s.newTestHistoryArchiver(historyIterator)
   304  	request := &archiver.ArchiveHistoryRequest{
   305  		NamespaceID:          testNamespaceID,
   306  		Namespace:            testNamespace,
   307  		WorkflowID:           testWorkflowID,
   308  		RunID:                testRunID,
   309  		BranchToken:          testBranchToken,
   310  		NextEventID:          testNextEventID,
   311  		CloseFailoverVersion: testCloseFailoverVersion,
   312  	}
   313  	err := historyArchiver.Archive(context.Background(), s.testArchivalURI, request)
   314  	s.NoError(err)
   315  }
   316  
   317  func (s *historyArchiverSuite) TestArchive_Success() {
   318  	mockCtrl := gomock.NewController(s.T())
   319  	defer mockCtrl.Finish()
   320  	historyIterator := archiver.NewMockHistoryIterator(mockCtrl)
   321  	historyBatches := []*historypb.History{
   322  		{
   323  			Events: []*historypb.HistoryEvent{
   324  				{
   325  					EventId:   common.FirstEventID + 1,
   326  					EventTime: timestamppb.New(time.Now().UTC()),
   327  					Version:   testCloseFailoverVersion,
   328  				},
   329  				{
   330  					EventId:   common.FirstEventID + 2,
   331  					EventTime: timestamppb.New(time.Now().UTC()),
   332  					Version:   testCloseFailoverVersion,
   333  				},
   334  			},
   335  		},
   336  		{
   337  			Events: []*historypb.HistoryEvent{
   338  				{
   339  					EventId:   testNextEventID - 1,
   340  					EventTime: timestamppb.New(time.Now().UTC()),
   341  					Version:   testCloseFailoverVersion,
   342  				},
   343  			},
   344  		},
   345  	}
   346  	historyBlob := &archiverspb.HistoryBlob{
   347  		Header: &archiverspb.HistoryBlobHeader{
   348  			IsLast: true,
   349  		},
   350  		Body: historyBatches,
   351  	}
   352  	gomock.InOrder(
   353  		historyIterator.EXPECT().HasNext().Return(true),
   354  		historyIterator.EXPECT().Next(gomock.Any()).Return(historyBlob, nil),
   355  		historyIterator.EXPECT().HasNext().Return(false),
   356  	)
   357  
   358  	dir := testutils.MkdirTemp(s.T(), "", "TestArchiveSingleRead")
   359  
   360  	historyArchiver := s.newTestHistoryArchiver(historyIterator)
   361  	request := &archiver.ArchiveHistoryRequest{
   362  		NamespaceID:          testNamespaceID,
   363  		Namespace:            testNamespace,
   364  		WorkflowID:           testWorkflowID,
   365  		RunID:                testRunID,
   366  		BranchToken:          testBranchToken,
   367  		NextEventID:          testNextEventID,
   368  		CloseFailoverVersion: testCloseFailoverVersion,
   369  	}
   370  	URI, err := archiver.NewURI("file://" + dir)
   371  	s.NoError(err)
   372  	err = historyArchiver.Archive(context.Background(), URI, request)
   373  	s.NoError(err)
   374  
   375  	expectedFilename := constructHistoryFilename(testNamespaceID, testWorkflowID, testRunID, testCloseFailoverVersion)
   376  	s.assertFileExists(path.Join(dir, expectedFilename))
   377  }
   378  
   379  func (s *historyArchiverSuite) TestGet_Fail_InvalidURI() {
   380  	historyArchiver := s.newTestHistoryArchiver(nil)
   381  	request := &archiver.GetHistoryRequest{
   382  		NamespaceID: testNamespaceID,
   383  		WorkflowID:  testWorkflowID,
   384  		RunID:       testRunID,
   385  		PageSize:    100,
   386  	}
   387  	URI, err := archiver.NewURI("wrongscheme://")
   388  	s.NoError(err)
   389  	response, err := historyArchiver.Get(context.Background(), URI, request)
   390  	s.Nil(response)
   391  	s.Error(err)
   392  }
   393  
   394  func (s *historyArchiverSuite) TestGet_Fail_InvalidRequest() {
   395  	historyArchiver := s.newTestHistoryArchiver(nil)
   396  	request := &archiver.GetHistoryRequest{
   397  		NamespaceID: testNamespaceID,
   398  		WorkflowID:  testWorkflowID,
   399  		RunID:       testRunID,
   400  		PageSize:    0, // pageSize should be greater than 0
   401  	}
   402  	response, err := historyArchiver.Get(context.Background(), s.testArchivalURI, request)
   403  	s.Nil(response)
   404  	s.Error(err)
   405  	s.IsType(&serviceerror.InvalidArgument{}, err)
   406  }
   407  
   408  func (s *historyArchiverSuite) TestGet_Fail_DirectoryNotExist() {
   409  	historyArchiver := s.newTestHistoryArchiver(nil)
   410  	request := &archiver.GetHistoryRequest{
   411  		NamespaceID: testNamespaceID,
   412  		WorkflowID:  testWorkflowID,
   413  		RunID:       testRunID,
   414  		PageSize:    testPageSize,
   415  	}
   416  	response, err := historyArchiver.Get(context.Background(), s.testArchivalURI, request)
   417  	s.Nil(response)
   418  	s.Error(err)
   419  	s.IsType(&serviceerror.NotFound{}, err)
   420  }
   421  
   422  func (s *historyArchiverSuite) TestGet_Fail_InvalidToken() {
   423  	historyArchiver := s.newTestHistoryArchiver(nil)
   424  	request := &archiver.GetHistoryRequest{
   425  		NamespaceID:   testNamespaceID,
   426  		WorkflowID:    testWorkflowID,
   427  		RunID:         testRunID,
   428  		PageSize:      testPageSize,
   429  		NextPageToken: []byte{'r', 'a', 'n', 'd', 'o', 'm'},
   430  	}
   431  	URI, err := archiver.NewURI("file:///")
   432  	s.NoError(err)
   433  	response, err := historyArchiver.Get(context.Background(), URI, request)
   434  	s.Nil(response)
   435  	s.Error(err)
   436  	s.IsType(&serviceerror.InvalidArgument{}, err)
   437  }
   438  
   439  func (s *historyArchiverSuite) TestGet_Fail_FileNotExist() {
   440  	historyArchiver := s.newTestHistoryArchiver(nil)
   441  	testCloseFailoverVersion := testCloseFailoverVersion
   442  	request := &archiver.GetHistoryRequest{
   443  		NamespaceID:          testNamespaceID,
   444  		WorkflowID:           testWorkflowID,
   445  		RunID:                testRunID,
   446  		PageSize:             testPageSize,
   447  		CloseFailoverVersion: &testCloseFailoverVersion,
   448  	}
   449  	URI, err := archiver.NewURI("file:///")
   450  	s.NoError(err)
   451  	response, err := historyArchiver.Get(context.Background(), URI, request)
   452  	s.Nil(response)
   453  	s.Error(err)
   454  	s.IsType(&serviceerror.NotFound{}, err)
   455  }
   456  
   457  func (s *historyArchiverSuite) TestGet_Success_PickHighestVersion() {
   458  	historyArchiver := s.newTestHistoryArchiver(nil)
   459  	request := &archiver.GetHistoryRequest{
   460  		NamespaceID: testNamespaceID,
   461  		WorkflowID:  testWorkflowID,
   462  		RunID:       testRunID,
   463  		PageSize:    testPageSize,
   464  	}
   465  	URI, err := archiver.NewURI("file://" + s.testGetDirectory)
   466  	s.NoError(err)
   467  	response, err := historyArchiver.Get(context.Background(), URI, request)
   468  	s.NoError(err)
   469  	s.Nil(response.NextPageToken)
   470  	s.Equal(s.historyBatchesV100, response.HistoryBatches)
   471  }
   472  
   473  func (s *historyArchiverSuite) TestGet_Success_UseProvidedVersion() {
   474  	historyArchiver := s.newTestHistoryArchiver(nil)
   475  	testCloseFailoverVersion := int64(1)
   476  	request := &archiver.GetHistoryRequest{
   477  		NamespaceID:          testNamespaceID,
   478  		WorkflowID:           testWorkflowID,
   479  		RunID:                testRunID,
   480  		PageSize:             testPageSize,
   481  		CloseFailoverVersion: &testCloseFailoverVersion,
   482  	}
   483  	URI, err := archiver.NewURI("file://" + s.testGetDirectory)
   484  	s.NoError(err)
   485  	response, err := historyArchiver.Get(context.Background(), URI, request)
   486  	s.NoError(err)
   487  	s.Nil(response.NextPageToken)
   488  	s.Equal(s.historyBatchesV1, response.HistoryBatches)
   489  }
   490  
   491  func (s *historyArchiverSuite) TestGet_Success_SmallPageSize() {
   492  	historyArchiver := s.newTestHistoryArchiver(nil)
   493  	testCloseFailoverVersion := int64(100)
   494  	request := &archiver.GetHistoryRequest{
   495  		NamespaceID:          testNamespaceID,
   496  		WorkflowID:           testWorkflowID,
   497  		RunID:                testRunID,
   498  		PageSize:             1,
   499  		CloseFailoverVersion: &testCloseFailoverVersion,
   500  	}
   501  	var combinedHistory []*historypb.History
   502  
   503  	URI, err := archiver.NewURI("file://" + s.testGetDirectory)
   504  	s.NoError(err)
   505  	response, err := historyArchiver.Get(context.Background(), URI, request)
   506  	s.NoError(err)
   507  	s.NotNil(response)
   508  	s.NotNil(response.NextPageToken)
   509  	s.NotNil(response.HistoryBatches)
   510  	s.Len(response.HistoryBatches, 1)
   511  	combinedHistory = append(combinedHistory, response.HistoryBatches...)
   512  
   513  	request.NextPageToken = response.NextPageToken
   514  	response, err = historyArchiver.Get(context.Background(), URI, request)
   515  	s.NoError(err)
   516  	s.NotNil(response)
   517  	s.Nil(response.NextPageToken)
   518  	s.NotNil(response.HistoryBatches)
   519  	s.Len(response.HistoryBatches, 1)
   520  	combinedHistory = append(combinedHistory, response.HistoryBatches...)
   521  
   522  	s.Equal(s.historyBatchesV100, combinedHistory)
   523  }
   524  
   525  func (s *historyArchiverSuite) TestArchiveAndGet() {
   526  	mockCtrl := gomock.NewController(s.T())
   527  	defer mockCtrl.Finish()
   528  	historyIterator := archiver.NewMockHistoryIterator(mockCtrl)
   529  	historyBlob := &archiverspb.HistoryBlob{
   530  		Header: &archiverspb.HistoryBlobHeader{
   531  			IsLast: true,
   532  		},
   533  		Body: s.historyBatchesV100,
   534  	}
   535  	gomock.InOrder(
   536  		historyIterator.EXPECT().HasNext().Return(true),
   537  		historyIterator.EXPECT().Next(gomock.Any()).Return(historyBlob, nil),
   538  		historyIterator.EXPECT().HasNext().Return(false),
   539  	)
   540  
   541  	dir := testutils.MkdirTemp(s.T(), "", "TestArchiveAndGet")
   542  
   543  	historyArchiver := s.newTestHistoryArchiver(historyIterator)
   544  	archiveRequest := &archiver.ArchiveHistoryRequest{
   545  		NamespaceID:          testNamespaceID,
   546  		Namespace:            testNamespace,
   547  		WorkflowID:           testWorkflowID,
   548  		RunID:                testRunID,
   549  		BranchToken:          testBranchToken,
   550  		NextEventID:          testNextEventID,
   551  		CloseFailoverVersion: testCloseFailoverVersion,
   552  	}
   553  	URI, err := archiver.NewURI("file://" + dir)
   554  	s.NoError(err)
   555  	err = historyArchiver.Archive(context.Background(), URI, archiveRequest)
   556  	s.NoError(err)
   557  
   558  	expectedFilename := constructHistoryFilename(testNamespaceID, testWorkflowID, testRunID, testCloseFailoverVersion)
   559  	s.assertFileExists(path.Join(dir, expectedFilename))
   560  
   561  	getRequest := &archiver.GetHistoryRequest{
   562  		NamespaceID: testNamespaceID,
   563  		WorkflowID:  testWorkflowID,
   564  		RunID:       testRunID,
   565  		PageSize:    testPageSize,
   566  	}
   567  	response, err := historyArchiver.Get(context.Background(), URI, getRequest)
   568  	s.NoError(err)
   569  	s.NotNil(response)
   570  	s.Nil(response.NextPageToken)
   571  	s.Equal(s.historyBatchesV100, response.HistoryBatches)
   572  }
   573  
   574  func (s *historyArchiverSuite) newTestHistoryArchiver(historyIterator archiver.HistoryIterator) *historyArchiver {
   575  	config := &config.FilestoreArchiver{
   576  		FileMode: testFileModeStr,
   577  		DirMode:  testDirModeStr,
   578  	}
   579  	archiver, err := newHistoryArchiver(s.container, config, historyIterator)
   580  	s.NoError(err)
   581  	return archiver
   582  }
   583  
   584  func (s *historyArchiverSuite) setupHistoryDirectory() {
   585  	now := timestamppb.New(time.Date(2020, 8, 22, 1, 2, 3, 4, time.UTC))
   586  	s.historyBatchesV1 = []*historypb.History{
   587  		{
   588  			Events: []*historypb.HistoryEvent{
   589  				{
   590  					EventId:   testNextEventID - 1,
   591  					EventTime: now,
   592  					Version:   1,
   593  				},
   594  			},
   595  		},
   596  	}
   597  
   598  	s.historyBatchesV100 = []*historypb.History{
   599  		{
   600  			Events: []*historypb.HistoryEvent{
   601  				{
   602  					EventId:   common.FirstEventID + 1,
   603  					EventTime: now,
   604  					Version:   testCloseFailoverVersion,
   605  				},
   606  				{
   607  					EventId:   common.FirstEventID + 1,
   608  					EventTime: now,
   609  					Version:   testCloseFailoverVersion,
   610  				},
   611  			},
   612  		},
   613  		{
   614  			Events: []*historypb.HistoryEvent{
   615  				{
   616  					EventId:   testNextEventID - 1,
   617  					EventTime: now,
   618  					Version:   testCloseFailoverVersion,
   619  				},
   620  			},
   621  		},
   622  	}
   623  
   624  	s.writeHistoryBatchesForGetTest(s.historyBatchesV1, int64(1))
   625  	s.writeHistoryBatchesForGetTest(s.historyBatchesV100, testCloseFailoverVersion)
   626  }
   627  
   628  func (s *historyArchiverSuite) writeHistoryBatchesForGetTest(historyBatches []*historypb.History, version int64) {
   629  	data, err := encodeHistories(historyBatches)
   630  	s.Require().NoError(err)
   631  	filename := constructHistoryFilename(testNamespaceID, testWorkflowID, testRunID, version)
   632  	err = writeFile(path.Join(s.testGetDirectory, filename), data, testFileMode)
   633  	s.Require().NoError(err)
   634  }
   635  
   636  func (s *historyArchiverSuite) assertFileExists(filepath string) {
   637  	exists, err := fileExists(filepath)
   638  	s.NoError(err)
   639  	s.True(exists)
   640  }
   641  
   642  func getCanceledContext() context.Context {
   643  	ctx, cancel := context.WithCancel(context.Background())
   644  	cancel()
   645  	return ctx
   646  }