go.temporal.io/server@v1.23.0/common/archiver/gcloud/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 gcloud
    26  
    27  import (
    28  	"context"
    29  	"errors"
    30  	"testing"
    31  	"time"
    32  
    33  	"github.com/golang/mock/gomock"
    34  	"github.com/stretchr/testify/require"
    35  	"github.com/stretchr/testify/suite"
    36  	enumspb "go.temporal.io/api/enums/v1"
    37  	historypb "go.temporal.io/api/history/v1"
    38  	"go.temporal.io/api/serviceerror"
    39  	"google.golang.org/protobuf/types/known/timestamppb"
    40  
    41  	archiverspb "go.temporal.io/server/api/archiver/v1"
    42  	"go.temporal.io/server/common"
    43  	"go.temporal.io/server/common/archiver"
    44  	"go.temporal.io/server/common/archiver/gcloud/connector"
    45  	"go.temporal.io/server/common/convert"
    46  	"go.temporal.io/server/common/log"
    47  	"go.temporal.io/server/common/metrics"
    48  )
    49  
    50  const (
    51  	testNamespaceID               = "test-namespace-id"
    52  	testNamespace                 = "test-namespace"
    53  	testWorkflowID                = "test-workflow-id"
    54  	testRunID                     = "test-run-id"
    55  	testNextEventID               = 1800
    56  	testCloseFailoverVersion      = 100
    57  	testPageSize                  = 100
    58  	exampleOldHistoryRecord       = `[{"events":[{"eventId":1,"eventTime": "2020-07-30T00:30:03.082421843Z","eventType":"WorkflowExecutionStarted","version":-24,"taskId":5242897,"workflowExecutionStartedEventAttributes":{"workflowType":{"name":"MobileOnlyWorkflow::processMobileOnly"},"taskQueue":{"name":"MobileOnly"},"input":null,"workflowExecutionTimeout":"300s","workflowTaskTimeout":"60s","originalExecutionRunId":"1fd5d4c8-1590-4a0a-8027-535e8729de8e","identity":"","firstExecutionRunId":"1fd5d4c8-1590-4a0a-8027-535e8729de8e","attempt":1,"firstWorkflowTaskBackoff":"0s"}}]}]`
    59  	exampleNewHistoryRecord       = `[{"events":[{"eventId":1,"eventTime": "2020-07-30T00:30:03.082421843Z","eventType":"EVENT_TYPE_WORKFLOW_EXECUTION_STARTED","version":-24,"taskId":5242897,"workflowExecutionStartedEventAttributes":{"workflowType":{"name":"MobileOnlyWorkflow::processMobileOnly"},"taskQueue":{"name":"MobileOnly"},"input":null,"workflowExecutionTimeout":"300s","workflowTaskTimeout":"60s","originalExecutionRunId":"1fd5d4c8-1590-4a0a-8027-535e8729de8e","identity":"","firstExecutionRunId":"1fd5d4c8-1590-4a0a-8027-535e8729de8e","attempt":1,"firstWorkflowTaskBackoff":"0s"}}]}]`
    60  	twoEventsExampleHistoryRecord = `[{"events":[{"eventId":1,"eventTime": "2020-07-30T00:30:03.082421843Z","eventType":"WorkflowExecutionStarted","version":-24,"taskId":5242897,"workflowExecutionStartedEventAttributes":{"workflowType":{"name":"MobileOnlyWorkflow::processMobileOnly"},"taskQueue":{"name":"MobileOnly"},"input":null,"workflowExecutionTimeout":"300s","workflowTaskTimeout":"60s","originalExecutionRunId":"1fd5d4c8-1590-4a0a-8027-535e8729de8e","identity":"","firstExecutionRunId":"1fd5d4c8-1590-4a0a-8027-535e8729de8e","attempt":1,"firstWorkflowTaskBackoff":"0s"}},{"eventId":2,"eventTime": "2020-07-30T00:30:03.082421843Z","eventType":"WorkflowExecutionStarted","version":-24,"taskId":5242897,"workflowExecutionStartedEventAttributes":{"workflowType":{"name":"MobileOnlyWorkflow::processMobileOnly"},"taskQueue":{"name":"MobileOnly"},"input":null,"workflowExecutionTimeout":"300s","workflowTaskTimeout":"60s","originalExecutionRunId":"1fd5d4c8-1590-4a0a-8027-535e8729de8e","identity":"","firstExecutionRunId":"1fd5d4c8-1590-4a0a-8027-535e8729de8e","attempt":1,"firstWorkflowTaskBackoff":"0s"}}]}]`
    61  )
    62  
    63  var (
    64  	testBranchToken = []byte{1, 2, 3}
    65  )
    66  
    67  func (h *historyArchiverSuite) SetupTest() {
    68  	h.Assertions = require.New(h.T())
    69  	h.controller = gomock.NewController(h.T())
    70  	h.container = &archiver.HistoryBootstrapContainer{
    71  		Logger:         log.NewNoopLogger(),
    72  		MetricsHandler: metrics.NoopMetricsHandler,
    73  	}
    74  	h.testArchivalURI, _ = archiver.NewURI("gs://my-bucket-cad/temporal_archival/development")
    75  }
    76  
    77  func (h *historyArchiverSuite) TearDownTest() {
    78  	h.controller.Finish()
    79  }
    80  
    81  func TestHistoryArchiverSuite(t *testing.T) {
    82  	suite.Run(t, new(historyArchiverSuite))
    83  }
    84  
    85  type historyArchiverSuite struct {
    86  	*require.Assertions
    87  	suite.Suite
    88  
    89  	controller *gomock.Controller
    90  
    91  	container       *archiver.HistoryBootstrapContainer
    92  	testArchivalURI archiver.URI
    93  }
    94  
    95  func getCanceledContext() context.Context {
    96  	ctx, cancel := context.WithCancel(context.Background())
    97  	cancel()
    98  	return ctx
    99  }
   100  
   101  func (h *historyArchiverSuite) TestValidateURI() {
   102  	ctx := context.Background()
   103  	testCases := []struct {
   104  		URI         string
   105  		expectedErr error
   106  	}{
   107  		{
   108  			URI:         "wrongscheme:///a/b/c",
   109  			expectedErr: archiver.ErrURISchemeMismatch,
   110  		},
   111  		{
   112  			URI:         "gs:my-bucket-cad/temporal_archival/development",
   113  			expectedErr: archiver.ErrInvalidURI,
   114  		},
   115  		{
   116  			URI:         "gs://",
   117  			expectedErr: archiver.ErrInvalidURI,
   118  		},
   119  		{
   120  			URI:         "gs://my-bucket-cad",
   121  			expectedErr: archiver.ErrInvalidURI,
   122  		},
   123  		{
   124  			URI:         "gs:/my-bucket-cad/temporal_archival/development",
   125  			expectedErr: archiver.ErrInvalidURI,
   126  		},
   127  		{
   128  			URI:         "gs://my-bucket-cad/temporal_archival/development",
   129  			expectedErr: nil,
   130  		},
   131  	}
   132  
   133  	storageWrapper := connector.NewMockClient(h.controller)
   134  	storageWrapper.EXPECT().Exist(ctx, gomock.Any(), "").Return(false, nil)
   135  	historyArchiver := new(historyArchiver)
   136  	historyArchiver.gcloudStorage = storageWrapper
   137  	for _, tc := range testCases {
   138  		URI, err := archiver.NewURI(tc.URI)
   139  		h.NoError(err)
   140  		h.Equal(tc.expectedErr, historyArchiver.ValidateURI(URI))
   141  	}
   142  }
   143  
   144  func (h *historyArchiverSuite) TestArchive_Fail_InvalidURI() {
   145  	mockStorageClient := connector.NewMockGcloudStorageClient(h.controller)
   146  	storageWrapper, _ := connector.NewClientWithParams(mockStorageClient)
   147  
   148  	historyIterator := archiver.NewMockHistoryIterator(h.controller)
   149  
   150  	historyArchiver := newHistoryArchiver(h.container, historyIterator, storageWrapper)
   151  	request := &archiver.ArchiveHistoryRequest{
   152  		NamespaceID:          testNamespaceID,
   153  		Namespace:            testNamespace,
   154  		WorkflowID:           testWorkflowID,
   155  		RunID:                testRunID,
   156  		BranchToken:          testBranchToken,
   157  		NextEventID:          testNextEventID,
   158  		CloseFailoverVersion: testCloseFailoverVersion,
   159  	}
   160  	URI, err := archiver.NewURI("wrongscheme://")
   161  	h.NoError(err)
   162  	err = historyArchiver.Archive(context.Background(), URI, request)
   163  	h.Error(err)
   164  }
   165  
   166  func (h *historyArchiverSuite) TestArchive_Fail_InvalidRequest() {
   167  	ctx := context.Background()
   168  	storageWrapper := connector.NewMockClient(h.controller)
   169  	storageWrapper.EXPECT().Exist(ctx, h.testArchivalURI, "").Return(true, nil)
   170  
   171  	historyIterator := archiver.NewMockHistoryIterator(h.controller)
   172  
   173  	historyArchiver := newHistoryArchiver(h.container, historyIterator, storageWrapper)
   174  	request := &archiver.ArchiveHistoryRequest{
   175  		NamespaceID:          testNamespaceID,
   176  		Namespace:            testNamespace,
   177  		WorkflowID:           "",
   178  		RunID:                testRunID,
   179  		BranchToken:          testBranchToken,
   180  		NextEventID:          testNextEventID,
   181  		CloseFailoverVersion: testCloseFailoverVersion,
   182  	}
   183  
   184  	err := historyArchiver.Archive(ctx, h.testArchivalURI, request)
   185  	h.Error(err)
   186  }
   187  
   188  func (h *historyArchiverSuite) TestArchive_Fail_ErrorOnReadHistory() {
   189  	ctx := context.Background()
   190  	storageWrapper := connector.NewMockClient(h.controller)
   191  	storageWrapper.EXPECT().Exist(ctx, h.testArchivalURI, "").Return(true, nil)
   192  
   193  	historyIterator := archiver.NewMockHistoryIterator(h.controller)
   194  	gomock.InOrder(
   195  		historyIterator.EXPECT().HasNext().Return(true),
   196  		historyIterator.EXPECT().Next(gomock.Any()).Return(nil, errors.New("some random error")),
   197  	)
   198  
   199  	historyArchiver := newHistoryArchiver(h.container, historyIterator, storageWrapper)
   200  	request := &archiver.ArchiveHistoryRequest{
   201  		NamespaceID:          testNamespaceID,
   202  		Namespace:            testNamespace,
   203  		WorkflowID:           testWorkflowID,
   204  		RunID:                testRunID,
   205  		BranchToken:          testBranchToken,
   206  		NextEventID:          testNextEventID,
   207  		CloseFailoverVersion: testCloseFailoverVersion,
   208  	}
   209  	err := historyArchiver.Archive(ctx, h.testArchivalURI, request)
   210  	h.Error(err)
   211  }
   212  
   213  func (h *historyArchiverSuite) TestArchive_Fail_TimeoutWhenReadingHistory() {
   214  
   215  	ctx := getCanceledContext()
   216  	storageWrapper := connector.NewMockClient(h.controller)
   217  	storageWrapper.EXPECT().Exist(gomock.Any(), gomock.Any(), "").Return(true, nil)
   218  
   219  	historyIterator := archiver.NewMockHistoryIterator(h.controller)
   220  	gomock.InOrder(
   221  		historyIterator.EXPECT().HasNext().Return(true),
   222  		historyIterator.EXPECT().Next(gomock.Any()).Return(nil, serviceerror.NewResourceExhausted(enumspb.RESOURCE_EXHAUSTED_CAUSE_RPS_LIMIT, "")),
   223  	)
   224  
   225  	historyArchiver := newHistoryArchiver(h.container, historyIterator, storageWrapper)
   226  	request := &archiver.ArchiveHistoryRequest{
   227  		NamespaceID:          testNamespaceID,
   228  		Namespace:            testNamespace,
   229  		WorkflowID:           testWorkflowID,
   230  		RunID:                testRunID,
   231  		BranchToken:          testBranchToken,
   232  		NextEventID:          testNextEventID,
   233  		CloseFailoverVersion: testCloseFailoverVersion,
   234  	}
   235  	err := historyArchiver.Archive(ctx, h.testArchivalURI, request)
   236  	h.Error(err)
   237  }
   238  
   239  func (h *historyArchiverSuite) TestArchive_Fail_HistoryMutated() {
   240  	ctx := context.Background()
   241  	storageWrapper := connector.NewMockClient(h.controller)
   242  	storageWrapper.EXPECT().Exist(ctx, h.testArchivalURI, "").Return(true, nil)
   243  
   244  	historyIterator := archiver.NewMockHistoryIterator(h.controller)
   245  	historyBatches := []*historypb.History{
   246  		{
   247  			Events: []*historypb.HistoryEvent{
   248  				{
   249  					EventId:   common.FirstEventID + 1,
   250  					EventTime: timestamppb.New(time.Now().UTC()),
   251  					Version:   testCloseFailoverVersion + 1,
   252  				},
   253  			},
   254  		},
   255  	}
   256  	historyBlob := &archiverspb.HistoryBlob{
   257  		Header: &archiverspb.HistoryBlobHeader{
   258  			IsLast: true,
   259  		},
   260  		Body: historyBatches,
   261  	}
   262  	gomock.InOrder(
   263  		historyIterator.EXPECT().HasNext().Return(true),
   264  		historyIterator.EXPECT().Next(gomock.Any()).Return(historyBlob, nil),
   265  	)
   266  
   267  	historyArchiver := newHistoryArchiver(h.container, historyIterator, storageWrapper)
   268  	request := &archiver.ArchiveHistoryRequest{
   269  		NamespaceID:          testNamespaceID,
   270  		Namespace:            testNamespace,
   271  		WorkflowID:           testWorkflowID,
   272  		RunID:                testRunID,
   273  		BranchToken:          testBranchToken,
   274  		NextEventID:          testNextEventID,
   275  		CloseFailoverVersion: testCloseFailoverVersion,
   276  	}
   277  	err := historyArchiver.Archive(ctx, h.testArchivalURI, request)
   278  	h.Error(err)
   279  }
   280  
   281  func (h *historyArchiverSuite) TestArchive_Fail_NonRetryableErrorOption() {
   282  
   283  	ctx := context.Background()
   284  	storageWrapper := connector.NewMockClient(h.controller)
   285  	storageWrapper.EXPECT().Exist(ctx, h.testArchivalURI, "").Return(true, nil)
   286  
   287  	historyIterator := archiver.NewMockHistoryIterator(h.controller)
   288  	gomock.InOrder(
   289  		historyIterator.EXPECT().HasNext().Return(true),
   290  		historyIterator.EXPECT().Next(gomock.Any()).Return(nil, errors.New("upload non-retryable error")),
   291  	)
   292  
   293  	historyArchiver := newHistoryArchiver(h.container, historyIterator, storageWrapper)
   294  	request := &archiver.ArchiveHistoryRequest{
   295  		NamespaceID:          testNamespaceID,
   296  		Namespace:            testNamespace,
   297  		WorkflowID:           testWorkflowID,
   298  		RunID:                testRunID,
   299  		BranchToken:          testBranchToken,
   300  		NextEventID:          testNextEventID,
   301  		CloseFailoverVersion: testCloseFailoverVersion,
   302  	}
   303  	err := historyArchiver.Archive(ctx, h.testArchivalURI, request, archiver.GetNonRetryableErrorOption(errUploadNonRetryable))
   304  	h.Equal(errUploadNonRetryable, err)
   305  }
   306  
   307  func (h *historyArchiverSuite) TestArchive_Skip() {
   308  	ctx := context.Background()
   309  
   310  	storageWrapper := connector.NewMockClient(h.controller)
   311  	storageWrapper.EXPECT().Exist(ctx, h.testArchivalURI, "").Return(true, nil)
   312  	storageWrapper.EXPECT().Exist(ctx, h.testArchivalURI, gomock.Any()).Return(false, nil)
   313  	storageWrapper.EXPECT().Upload(ctx, h.testArchivalURI, gomock.Any(), gomock.Any()).Return(nil)
   314  
   315  	historyIterator := archiver.NewMockHistoryIterator(h.controller)
   316  	historyBlob := &archiverspb.HistoryBlob{
   317  		Header: &archiverspb.HistoryBlobHeader{
   318  			IsLast: false,
   319  		},
   320  		Body: []*historypb.History{
   321  			{
   322  				Events: []*historypb.HistoryEvent{
   323  					{
   324  						EventId:   common.FirstEventID,
   325  						EventTime: timestamppb.New(time.Now().UTC()),
   326  						Version:   testCloseFailoverVersion,
   327  					},
   328  				},
   329  			},
   330  		},
   331  	}
   332  	gomock.InOrder(
   333  		historyIterator.EXPECT().HasNext().Return(true),
   334  		historyIterator.EXPECT().Next(gomock.Any()).Return(historyBlob, nil),
   335  		historyIterator.EXPECT().HasNext().Return(true),
   336  		historyIterator.EXPECT().Next(gomock.Any()).Return(nil, serviceerror.NewNotFound("workflow not found")),
   337  	)
   338  
   339  	historyArchiver := newHistoryArchiver(h.container, historyIterator, storageWrapper)
   340  	request := &archiver.ArchiveHistoryRequest{
   341  		NamespaceID:          testNamespaceID,
   342  		Namespace:            testNamespace,
   343  		WorkflowID:           testWorkflowID,
   344  		RunID:                testRunID,
   345  		BranchToken:          testBranchToken,
   346  		NextEventID:          testNextEventID,
   347  		CloseFailoverVersion: testCloseFailoverVersion,
   348  	}
   349  	err := historyArchiver.Archive(ctx, h.testArchivalURI, request)
   350  	h.NoError(err)
   351  }
   352  
   353  func (h *historyArchiverSuite) TestArchive_Success() {
   354  
   355  	ctx := context.Background()
   356  
   357  	storageWrapper := connector.NewMockClient(h.controller)
   358  	storageWrapper.EXPECT().Exist(ctx, h.testArchivalURI, gomock.Any()).Return(false, nil).Times(2)
   359  	storageWrapper.EXPECT().Upload(ctx, h.testArchivalURI, gomock.Any(), gomock.Any()).Return(nil)
   360  
   361  	historyIterator := archiver.NewMockHistoryIterator(h.controller)
   362  	historyBatches := []*historypb.History{
   363  		{
   364  			Events: []*historypb.HistoryEvent{
   365  				{
   366  					EventId:   common.FirstEventID + 1,
   367  					EventTime: timestamppb.New(time.Now().UTC()),
   368  					Version:   testCloseFailoverVersion,
   369  				},
   370  				{
   371  					EventId:   common.FirstEventID + 2,
   372  					EventTime: timestamppb.New(time.Now().UTC()),
   373  					Version:   testCloseFailoverVersion,
   374  				},
   375  			},
   376  		},
   377  		{
   378  			Events: []*historypb.HistoryEvent{
   379  				{
   380  					EventId:   testNextEventID - 1,
   381  					EventTime: timestamppb.New(time.Now().UTC()),
   382  					Version:   testCloseFailoverVersion,
   383  				},
   384  			},
   385  		},
   386  	}
   387  	historyBlob := &archiverspb.HistoryBlob{
   388  		Header: &archiverspb.HistoryBlobHeader{
   389  			IsLast: true,
   390  		},
   391  		Body: historyBatches,
   392  	}
   393  	gomock.InOrder(
   394  		historyIterator.EXPECT().HasNext().Return(true),
   395  		historyIterator.EXPECT().Next(gomock.Any()).Return(historyBlob, nil),
   396  		historyIterator.EXPECT().HasNext().Return(false),
   397  	)
   398  
   399  	historyArchiver := newHistoryArchiver(h.container, historyIterator, storageWrapper)
   400  
   401  	request := &archiver.ArchiveHistoryRequest{
   402  		NamespaceID:          testNamespaceID,
   403  		Namespace:            testNamespace,
   404  		WorkflowID:           testWorkflowID,
   405  		RunID:                testRunID,
   406  		BranchToken:          testBranchToken,
   407  		NextEventID:          testNextEventID,
   408  		CloseFailoverVersion: testCloseFailoverVersion,
   409  	}
   410  
   411  	err := historyArchiver.Archive(ctx, h.testArchivalURI, request)
   412  	h.NoError(err)
   413  }
   414  
   415  func (h *historyArchiverSuite) TestGet_Fail_InvalidURI() {
   416  	ctx := context.Background()
   417  	mockStorageClient := connector.NewMockGcloudStorageClient(h.controller)
   418  	storageWrapper, _ := connector.NewClientWithParams(mockStorageClient)
   419  	historyIterator := archiver.NewMockHistoryIterator(h.controller)
   420  	historyArchiver := newHistoryArchiver(h.container, historyIterator, storageWrapper)
   421  
   422  	request := &archiver.GetHistoryRequest{
   423  		NamespaceID: testNamespaceID,
   424  		WorkflowID:  testWorkflowID,
   425  		RunID:       testRunID,
   426  		PageSize:    100,
   427  	}
   428  	URI, err := archiver.NewURI("wrongscheme://")
   429  	h.NoError(err)
   430  	response, err := historyArchiver.Get(ctx, URI, request)
   431  	h.Nil(response)
   432  	h.Error(err)
   433  }
   434  
   435  func (h *historyArchiverSuite) TestGet_Fail_InvalidToken() {
   436  	ctx := context.Background()
   437  	mockStorageClient := connector.NewMockGcloudStorageClient(h.controller)
   438  	storageWrapper, _ := connector.NewClientWithParams(mockStorageClient)
   439  	historyIterator := archiver.NewMockHistoryIterator(h.controller)
   440  	historyArchiver := newHistoryArchiver(h.container, historyIterator, storageWrapper)
   441  	request := &archiver.GetHistoryRequest{
   442  		NamespaceID:   testNamespaceID,
   443  		WorkflowID:    testWorkflowID,
   444  		RunID:         testRunID,
   445  		PageSize:      testPageSize,
   446  		NextPageToken: []byte{'r', 'a', 'n', 'd', 'o', 'm'},
   447  	}
   448  	URI, err := archiver.NewURI("gs:///")
   449  	h.NoError(err)
   450  	response, err := historyArchiver.Get(ctx, URI, request)
   451  	h.Nil(response)
   452  	h.Error(err)
   453  	h.IsType(&serviceerror.InvalidArgument{}, err)
   454  }
   455  
   456  func (h *historyArchiverSuite) TestGet_Success_PickHighestVersion() {
   457  	ctx := context.Background()
   458  	storageWrapper := connector.NewMockClient(h.controller)
   459  	storageWrapper.EXPECT().Exist(ctx, h.testArchivalURI, "").Return(true, nil)
   460  	storageWrapper.EXPECT().Query(ctx, h.testArchivalURI, gomock.Any()).Return([]string{"905702227796330300141628222723188294514017512010591354159_-24_0.history", "905702227796330300141628222723188294514017512010591354159_-25_0.history"}, nil)
   461  	storageWrapper.EXPECT().Get(ctx, h.testArchivalURI, "141323698701063509081739672280485489488911532452831150339470_-24_0.history").Return([]byte(exampleNewHistoryRecord), nil)
   462  	historyIterator := archiver.NewMockHistoryIterator(h.controller)
   463  	historyArchiver := newHistoryArchiver(h.container, historyIterator, storageWrapper)
   464  	request := &archiver.GetHistoryRequest{
   465  		NamespaceID: testNamespaceID,
   466  		WorkflowID:  testWorkflowID,
   467  		RunID:       testRunID,
   468  		PageSize:    testPageSize,
   469  	}
   470  
   471  	response, err := historyArchiver.Get(ctx, h.testArchivalURI, request)
   472  	h.NoError(err)
   473  	h.Nil(response.NextPageToken)
   474  }
   475  
   476  func (h *historyArchiverSuite) TestGet_Success_PickHighestVersion_OldJSON() {
   477  	ctx := context.Background()
   478  	storageWrapper := connector.NewMockClient(h.controller)
   479  	storageWrapper.EXPECT().Exist(ctx, h.testArchivalURI, "").Return(true, nil)
   480  	storageWrapper.EXPECT().Query(ctx, h.testArchivalURI, gomock.Any()).Return([]string{"905702227796330300141628222723188294514017512010591354159_-24_0.history", "905702227796330300141628222723188294514017512010591354159_-25_0.history"}, nil)
   481  	storageWrapper.EXPECT().Get(ctx, h.testArchivalURI, "141323698701063509081739672280485489488911532452831150339470_-24_0.history").Return([]byte(exampleOldHistoryRecord), nil)
   482  	historyIterator := archiver.NewMockHistoryIterator(h.controller)
   483  	historyArchiver := newHistoryArchiver(h.container, historyIterator, storageWrapper)
   484  	request := &archiver.GetHistoryRequest{
   485  		NamespaceID: testNamespaceID,
   486  		WorkflowID:  testWorkflowID,
   487  		RunID:       testRunID,
   488  		PageSize:    testPageSize,
   489  	}
   490  
   491  	response, err := historyArchiver.Get(ctx, h.testArchivalURI, request)
   492  	h.NoError(err)
   493  	h.Nil(response.NextPageToken)
   494  }
   495  
   496  func (h *historyArchiverSuite) TestGet_Success_UseProvidedVersion() {
   497  	ctx := context.Background()
   498  	storageWrapper := connector.NewMockClient(h.controller)
   499  	storageWrapper.EXPECT().Exist(ctx, h.testArchivalURI, "").Return(true, nil)
   500  	storageWrapper.EXPECT().Query(ctx, h.testArchivalURI, "141323698701063509081739672280485489488911532452831150339470").Return([]string{"905702227796330300141628222723188294514017512010591354159_-24_0.history", "905702227796330300141628222723188294514017512010591354159_-25_0.history"}, nil)
   501  	storageWrapper.EXPECT().Get(ctx, h.testArchivalURI, "141323698701063509081739672280485489488911532452831150339470_-25_0.history").Return([]byte(exampleNewHistoryRecord), nil)
   502  	historyIterator := archiver.NewMockHistoryIterator(h.controller)
   503  	historyArchiver := newHistoryArchiver(h.container, historyIterator, storageWrapper)
   504  	request := &archiver.GetHistoryRequest{
   505  		NamespaceID:          testNamespaceID,
   506  		WorkflowID:           testWorkflowID,
   507  		RunID:                testRunID,
   508  		PageSize:             testPageSize,
   509  		CloseFailoverVersion: convert.Int64Ptr(-25),
   510  	}
   511  
   512  	response, err := historyArchiver.Get(ctx, h.testArchivalURI, request)
   513  	h.NoError(err)
   514  	h.Nil(response.NextPageToken)
   515  }
   516  
   517  func (h *historyArchiverSuite) TestGet_Success_PageSize() {
   518  	ctx := context.Background()
   519  	storageWrapper := connector.NewMockClient(h.controller)
   520  	storageWrapper.EXPECT().Exist(ctx, h.testArchivalURI, "").Return(true, nil)
   521  	storageWrapper.EXPECT().Query(ctx, h.testArchivalURI, "141323698701063509081739672280485489488911532452831150339470").Return([]string{"905702227796330300141628222723188294514017512010591354159_-24_0.history", "905702227796330300141628222723188294514017512010591354159_-24_1.history", "905702227796330300141628222723188294514017512010591354159_-24_2.history", "905702227796330300141628222723188294514017512010591354159_-24_3.history", "905702227796330300141628222723188294514017512010591354159_-25_0.history"}, nil)
   522  	storageWrapper.EXPECT().Get(ctx, h.testArchivalURI, "141323698701063509081739672280485489488911532452831150339470_-24_0.history").Return([]byte(exampleNewHistoryRecord), nil)
   523  	storageWrapper.EXPECT().Get(ctx, h.testArchivalURI, "141323698701063509081739672280485489488911532452831150339470_-24_1.history").Return([]byte(exampleNewHistoryRecord), nil)
   524  
   525  	historyIterator := archiver.NewMockHistoryIterator(h.controller)
   526  	historyArchiver := newHistoryArchiver(h.container, historyIterator, storageWrapper)
   527  	request := &archiver.GetHistoryRequest{
   528  		NamespaceID: testNamespaceID,
   529  		WorkflowID:  testWorkflowID,
   530  		RunID:       testRunID,
   531  		PageSize:    2,
   532  	}
   533  
   534  	response, err := historyArchiver.Get(ctx, h.testArchivalURI, request)
   535  	h.NoError(err)
   536  	h.NotNil(response.NextPageToken)
   537  	h.EqualValues(len(response.HistoryBatches), 2)
   538  }
   539  
   540  func (h *historyArchiverSuite) TestGet_Success_FromToken() {
   541  	ctx := context.Background()
   542  	storageWrapper := connector.NewMockClient(h.controller)
   543  	storageWrapper.EXPECT().Exist(ctx, h.testArchivalURI, "").Return(true, nil)
   544  	storageWrapper.EXPECT().Get(ctx, h.testArchivalURI, "141323698701063509081739672280485489488911532452831150339470_-24_2.history").Return([]byte(exampleNewHistoryRecord), nil)
   545  	storageWrapper.EXPECT().Get(ctx, h.testArchivalURI, "141323698701063509081739672280485489488911532452831150339470_-24_3.history").Return([]byte(twoEventsExampleHistoryRecord), nil)
   546  	storageWrapper.EXPECT().Get(ctx, h.testArchivalURI, "141323698701063509081739672280485489488911532452831150339470_-24_4.history").Return([]byte(exampleNewHistoryRecord), nil)
   547  
   548  	historyIterator := archiver.NewMockHistoryIterator(h.controller)
   549  	historyArchiver := newHistoryArchiver(h.container, historyIterator, storageWrapper)
   550  
   551  	token := &getHistoryToken{
   552  		CloseFailoverVersion: -24,
   553  		HighestPart:          5,
   554  		CurrentPart:          2,
   555  		BatchIdxOffset:       0,
   556  	}
   557  
   558  	nextPageToken, err := serializeToken(token)
   559  	h.NoError(err)
   560  
   561  	request := &archiver.GetHistoryRequest{
   562  		NamespaceID:   testNamespaceID,
   563  		WorkflowID:    testWorkflowID,
   564  		RunID:         testRunID,
   565  		PageSize:      4,
   566  		NextPageToken: nextPageToken,
   567  	}
   568  
   569  	h.NoError(err)
   570  	response, err := historyArchiver.Get(ctx, h.testArchivalURI, request)
   571  	h.NoError(err)
   572  	h.NotNil(response.NextPageToken)
   573  
   574  	token, err = deserializeGetHistoryToken(response.NextPageToken)
   575  	h.NoError(err)
   576  
   577  	h.EqualValues(5, token.HighestPart)
   578  	h.EqualValues(5, token.CurrentPart)
   579  	h.EqualValues(3, len(response.HistoryBatches))
   580  	numOfEvents := 0
   581  	for _, batch := range response.HistoryBatches {
   582  		numOfEvents += len(batch.Events)
   583  	}
   584  
   585  	h.EqualValues(4, numOfEvents)
   586  }
   587  
   588  func (h *historyArchiverSuite) TestGet_NoHistory() {
   589  
   590  	ctx := context.Background()
   591  	storageWrapper := connector.NewMockClient(h.controller)
   592  	storageWrapper.EXPECT().Exist(ctx, h.testArchivalURI, "").Return(true, nil)
   593  	storageWrapper.EXPECT().Query(ctx, h.testArchivalURI, "141323698701063509081739672280485489488911532452831150339470").Return([]string{}, nil)
   594  
   595  	historyIterator := archiver.NewMockHistoryIterator(h.controller)
   596  	historyArchiver := newHistoryArchiver(h.container, historyIterator, storageWrapper)
   597  	request := &archiver.GetHistoryRequest{
   598  		NamespaceID: testNamespaceID,
   599  		WorkflowID:  testWorkflowID,
   600  		RunID:       testRunID,
   601  		PageSize:    2,
   602  	}
   603  
   604  	_, err := historyArchiver.Get(ctx, h.testArchivalURI, request)
   605  	h.Assert().IsType(&serviceerror.NotFound{}, err)
   606  }