go.temporal.io/server@v1.23.0/common/archiver/history_iterator_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 archiver
    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  	taskqueuepb "go.temporal.io/api/taskqueue/v1"
    40  	"google.golang.org/protobuf/types/known/durationpb"
    41  	"google.golang.org/protobuf/types/known/timestamppb"
    42  
    43  	archiverspb "go.temporal.io/server/api/archiver/v1"
    44  	"go.temporal.io/server/common"
    45  	"go.temporal.io/server/common/persistence"
    46  )
    47  
    48  const (
    49  	testNamespaceID                  = "test-namespace-id"
    50  	testNamespace                    = "test-namespace"
    51  	testWorkflowID                   = "test-workflow-id"
    52  	testRunID                        = "test-run-id"
    53  	testShardID                      = int32(1)
    54  	testNextEventID                  = 1800
    55  	testCloseFailoverVersion         = 100
    56  	testDefaultPersistencePageSize   = 250
    57  	testDefaultTargetHistoryBlobSize = 2 * 1024 * 124
    58  	testDefaultHistoryEventSize      = 50
    59  )
    60  
    61  var (
    62  	testBranchToken = []byte{1, 2, 3}
    63  )
    64  
    65  type (
    66  	HistoryIteratorSuite struct {
    67  		*require.Assertions
    68  		suite.Suite
    69  
    70  		controller       *gomock.Controller
    71  		mockExecutionMgr *persistence.MockExecutionManager
    72  	}
    73  
    74  	page struct {
    75  		firstbatchIdx             int
    76  		numBatches                int
    77  		firstEventFailoverVersion int64
    78  		lastEventFailoverVersion  int64
    79  	}
    80  
    81  	testSizeEstimator struct{}
    82  )
    83  
    84  func (e *testSizeEstimator) EstimateSize(v interface{}) (int, error) {
    85  	historyBatch, ok := v.(*historypb.History)
    86  	if !ok {
    87  		return -1, errors.New("test size estimator only estimate the size of history batches")
    88  	}
    89  	return testDefaultHistoryEventSize * len(historyBatch.Events), nil
    90  }
    91  
    92  func newTestSizeEstimator() SizeEstimator {
    93  	return &testSizeEstimator{}
    94  }
    95  
    96  func TestHistoryIteratorSuite(t *testing.T) {
    97  	suite.Run(t, new(HistoryIteratorSuite))
    98  }
    99  
   100  func (s *HistoryIteratorSuite) SetupTest() {
   101  	s.Assertions = require.New(s.T())
   102  	s.controller = gomock.NewController(s.T())
   103  	s.mockExecutionMgr = persistence.NewMockExecutionManager(s.controller)
   104  }
   105  
   106  func (s *HistoryIteratorSuite) TearDownTest() {
   107  	s.controller.Finish()
   108  }
   109  
   110  func (s *HistoryIteratorSuite) TestReadHistory_Failed_EventsV2() {
   111  	s.mockExecutionMgr.EXPECT().ReadHistoryBranchByBatch(gomock.Any(), gomock.Any()).Return(nil, errors.New("got error reading history branch"))
   112  	itr := s.constructTestHistoryIterator(s.mockExecutionMgr, testDefaultTargetHistoryBlobSize, nil)
   113  	history, err := itr.readHistory(context.Background(), common.FirstEventID)
   114  	s.Error(err)
   115  	s.Nil(history)
   116  }
   117  
   118  func (s *HistoryIteratorSuite) TestReadHistory_Success_EventsV2() {
   119  	resp := persistence.ReadHistoryBranchByBatchResponse{
   120  		History:       []*historypb.History{},
   121  		NextPageToken: []byte{},
   122  	}
   123  	s.mockExecutionMgr.EXPECT().ReadHistoryBranchByBatch(gomock.Any(), gomock.Any()).Return(&resp, nil)
   124  	itr := s.constructTestHistoryIterator(s.mockExecutionMgr, testDefaultTargetHistoryBlobSize, nil)
   125  	history, err := itr.readHistory(context.Background(), common.FirstEventID)
   126  	s.NoError(err)
   127  	s.Len(history, 0)
   128  }
   129  
   130  // In the following test:
   131  //   batchInfo represents # of events for each history batch.
   132  //   page represents the metadata of the set of history batches that should be requested by the iterator
   133  //   and returned by the history manager. Each page specifies the index of the first history batch it should
   134  //   return, # of batches to return and first/last event failover version for the set of batches returned.
   135  //   Note that is possible that a history batch is contained in multiple pages.
   136  
   137  func (s *HistoryIteratorSuite) TestReadHistoryBatches_Fail_FirstCallToReadHistoryGivesError() {
   138  	batchInfo := []int{1}
   139  	pages := []page{
   140  		{
   141  			firstbatchIdx:             0,
   142  			numBatches:                1,
   143  			firstEventFailoverVersion: 1,
   144  			lastEventFailoverVersion:  1,
   145  		},
   146  	}
   147  	s.initMockExecutionManager(batchInfo, 0, false, pages...)
   148  	itr := s.constructTestHistoryIterator(s.mockExecutionMgr, testDefaultTargetHistoryBlobSize, nil)
   149  	startingIteratorState := s.copyIteratorState(itr)
   150  	events, nextIterState, err := itr.readHistoryBatches(context.Background(), common.FirstEventID)
   151  	s.Error(err)
   152  	s.Nil(events)
   153  	s.False(nextIterState.FinishedIteration)
   154  	s.Zero(nextIterState.NextEventID)
   155  	s.assertStateMatches(startingIteratorState, itr)
   156  }
   157  
   158  func (s *HistoryIteratorSuite) TestReadHistoryBatches_Fail_NonFirstCallToReadHistoryGivesError() {
   159  	batchInfo := []int{1, 1}
   160  	pages := []page{
   161  		{
   162  			firstbatchIdx:             0,
   163  			numBatches:                1,
   164  			firstEventFailoverVersion: 1,
   165  			lastEventFailoverVersion:  1,
   166  		},
   167  		{
   168  			firstbatchIdx:             1,
   169  			numBatches:                1,
   170  			firstEventFailoverVersion: 1,
   171  			lastEventFailoverVersion:  1,
   172  		},
   173  	}
   174  	s.initMockExecutionManager(batchInfo, 1, false, pages...)
   175  	itr := s.constructTestHistoryIterator(s.mockExecutionMgr, testDefaultTargetHistoryBlobSize, nil)
   176  	startingIteratorState := s.copyIteratorState(itr)
   177  	events, nextIterState, err := itr.readHistoryBatches(context.Background(), common.FirstEventID)
   178  	s.Error(err)
   179  	s.Nil(events)
   180  	s.False(nextIterState.FinishedIteration)
   181  	s.Zero(nextIterState.NextEventID)
   182  	s.assertStateMatches(startingIteratorState, itr)
   183  }
   184  
   185  func (s *HistoryIteratorSuite) TestReadHistoryBatches_Success_ReadToHistoryEnd() {
   186  	batchInfo := []int{1, 2, 1, 1, 1, 3, 3, 1, 3}
   187  	pages := []page{
   188  		{
   189  			firstbatchIdx:             0,
   190  			numBatches:                3,
   191  			firstEventFailoverVersion: 1,
   192  			lastEventFailoverVersion:  1,
   193  		},
   194  		{
   195  			firstbatchIdx:             3,
   196  			numBatches:                2,
   197  			firstEventFailoverVersion: 1,
   198  			lastEventFailoverVersion:  1,
   199  		},
   200  		{
   201  			firstbatchIdx:             5,
   202  			numBatches:                4,
   203  			firstEventFailoverVersion: 1,
   204  			lastEventFailoverVersion:  1,
   205  		},
   206  	}
   207  	s.initMockExecutionManager(batchInfo, -1, true, pages...)
   208  	// ensure target history batches size is greater than total history length to ensure all of history is read
   209  	itr := s.constructTestHistoryIterator(s.mockExecutionMgr, 20*testDefaultHistoryEventSize, nil)
   210  	startingIteratorState := s.copyIteratorState(itr)
   211  	history, nextIterState, err := itr.readHistoryBatches(context.Background(), common.FirstEventID)
   212  	s.NoError(err)
   213  	s.NotNil(history)
   214  	s.Len(history, 9)
   215  	s.True(nextIterState.FinishedIteration)
   216  	s.Zero(nextIterState.NextEventID)
   217  	s.assertStateMatches(startingIteratorState, itr)
   218  }
   219  
   220  func (s *HistoryIteratorSuite) TestReadHistoryBatches_Success_TargetSizeSatisfiedWithoutReadingToEnd() {
   221  	batchInfo := []int{1, 2, 1, 1, 1, 3, 3, 1, 3}
   222  	pages := []page{
   223  		{
   224  			firstbatchIdx:             0,
   225  			numBatches:                3,
   226  			firstEventFailoverVersion: 1,
   227  			lastEventFailoverVersion:  1,
   228  		},
   229  		{
   230  			firstbatchIdx:             3,
   231  			numBatches:                2,
   232  			firstEventFailoverVersion: 1,
   233  			lastEventFailoverVersion:  1,
   234  		},
   235  		{
   236  			firstbatchIdx:             5,
   237  			numBatches:                4,
   238  			firstEventFailoverVersion: 1,
   239  			lastEventFailoverVersion:  1,
   240  		},
   241  	}
   242  	s.initMockExecutionManager(batchInfo, -1, false, pages...)
   243  	// ensure target history batches is smaller than full length of history so that not all of history is read
   244  	itr := s.constructTestHistoryIterator(s.mockExecutionMgr, 11*testDefaultHistoryEventSize, nil)
   245  	startingIteratorState := s.copyIteratorState(itr)
   246  	history, nextIterState, err := itr.readHistoryBatches(context.Background(), common.FirstEventID)
   247  	s.NoError(err)
   248  	s.NotNil(history)
   249  	s.Len(history, 7)
   250  	s.False(nextIterState.FinishedIteration)
   251  	s.Equal(int64(13), nextIterState.NextEventID)
   252  	s.assertStateMatches(startingIteratorState, itr)
   253  }
   254  
   255  func (s *HistoryIteratorSuite) TestReadHistoryBatches_Success_ReadExactlyToHistoryEnd() {
   256  	batchInfo := []int{1, 2, 1, 1, 1, 3, 3, 1, 3}
   257  	pages := []page{
   258  		{
   259  			firstbatchIdx:             0,
   260  			numBatches:                3,
   261  			firstEventFailoverVersion: 1,
   262  			lastEventFailoverVersion:  1,
   263  		},
   264  		{
   265  			firstbatchIdx:             3,
   266  			numBatches:                2,
   267  			firstEventFailoverVersion: 1,
   268  			lastEventFailoverVersion:  1,
   269  		},
   270  		{
   271  			firstbatchIdx:             5,
   272  			numBatches:                4,
   273  			firstEventFailoverVersion: 1,
   274  			lastEventFailoverVersion:  1,
   275  		},
   276  	}
   277  	s.initMockExecutionManager(batchInfo, -1, true, pages...)
   278  	// ensure target history batches size is equal to the full length of history so that all of history is read
   279  	itr := s.constructTestHistoryIterator(s.mockExecutionMgr, 16*testDefaultHistoryEventSize, nil)
   280  	startingIteratorState := s.copyIteratorState(itr)
   281  	history, nextIterState, err := itr.readHistoryBatches(context.Background(), common.FirstEventID)
   282  	s.NoError(err)
   283  	s.NotNil(history)
   284  	s.Len(history, 9)
   285  	s.True(nextIterState.FinishedIteration)
   286  	s.Zero(nextIterState.NextEventID)
   287  	s.assertStateMatches(startingIteratorState, itr)
   288  }
   289  
   290  func (s *HistoryIteratorSuite) TestReadHistoryBatches_Success_ReadPageMultipleTimes() {
   291  	batchInfo := []int{1, 3, 2}
   292  	pages := []page{
   293  		{
   294  			firstbatchIdx:             0,
   295  			numBatches:                3,
   296  			firstEventFailoverVersion: 1,
   297  			lastEventFailoverVersion:  1,
   298  		},
   299  		{
   300  			firstbatchIdx:             2,
   301  			numBatches:                1,
   302  			firstEventFailoverVersion: 1,
   303  			lastEventFailoverVersion:  1,
   304  		},
   305  	}
   306  	s.initMockExecutionManager(batchInfo, -1, true, pages...)
   307  	// ensure target history batches is very small so that one page needs multiple read
   308  	itr := s.constructTestHistoryIterator(s.mockExecutionMgr, 2*testDefaultHistoryEventSize, nil)
   309  	startingIteratorState := s.copyIteratorState(itr)
   310  	history, nextIterState, err := itr.readHistoryBatches(context.Background(), common.FirstEventID)
   311  	s.NoError(err)
   312  	s.NotNil(history)
   313  	s.Len(history, 2)
   314  	s.False(nextIterState.FinishedIteration)
   315  	s.Equal(int64(5), nextIterState.NextEventID)
   316  	s.assertStateMatches(startingIteratorState, itr)
   317  
   318  	history, nextIterState, err = itr.readHistoryBatches(context.Background(), nextIterState.NextEventID)
   319  	s.NoError(err)
   320  	s.NotNil(history)
   321  	s.Len(history, 1)
   322  	s.True(nextIterState.FinishedIteration)
   323  	s.Zero(nextIterState.NextEventID)
   324  	s.assertStateMatches(startingIteratorState, itr)
   325  }
   326  
   327  func (s *HistoryIteratorSuite) TestNext_Fail_IteratorDepleted() {
   328  	batchInfo := []int{1, 3, 2, 1, 2, 3, 4}
   329  	pages := []page{
   330  		{
   331  			firstbatchIdx:             0,
   332  			numBatches:                2,
   333  			firstEventFailoverVersion: 1,
   334  			lastEventFailoverVersion:  1,
   335  		},
   336  		{
   337  			firstbatchIdx:             2,
   338  			numBatches:                1,
   339  			firstEventFailoverVersion: 1,
   340  			lastEventFailoverVersion:  2,
   341  		},
   342  		{
   343  			firstbatchIdx:             3,
   344  			numBatches:                4,
   345  			firstEventFailoverVersion: 2,
   346  			lastEventFailoverVersion:  5,
   347  		},
   348  	}
   349  	s.initMockExecutionManager(batchInfo, -1, true, pages...)
   350  	// set target history batches such that a single call to next will read all of history
   351  	itr := s.constructTestHistoryIterator(s.mockExecutionMgr, 16*testDefaultHistoryEventSize, nil)
   352  	blob, err := itr.Next(context.Background())
   353  	s.Nil(err)
   354  
   355  	expectedIteratorState := historyIteratorState{
   356  		// when iteration is finished page token is not advanced
   357  		FinishedIteration: true,
   358  		NextEventID:       0,
   359  	}
   360  	s.assertStateMatches(expectedIteratorState, itr)
   361  	s.NotNil(blob)
   362  	expectedHeader := &archiverspb.HistoryBlobHeader{
   363  		Namespace:            testNamespace,
   364  		NamespaceId:          testNamespaceID,
   365  		WorkflowId:           testWorkflowID,
   366  		RunId:                testRunID,
   367  		IsLast:               true,
   368  		FirstFailoverVersion: 1,
   369  		LastFailoverVersion:  5,
   370  		FirstEventId:         common.FirstEventID,
   371  		LastEventId:          16,
   372  		EventCount:           16,
   373  	}
   374  	s.Equal(expectedHeader, blob.Header)
   375  	s.Len(blob.Body, 7)
   376  	s.NoError(err)
   377  	s.False(itr.HasNext())
   378  
   379  	blob, err = itr.Next(context.Background())
   380  	s.Equal(err, errIteratorDepleted)
   381  	s.Nil(blob)
   382  	s.assertStateMatches(expectedIteratorState, itr)
   383  }
   384  
   385  func (s *HistoryIteratorSuite) TestNext_Fail_ReturnErrOnSecondCallToNext() {
   386  	batchInfo := []int{1, 3, 2, 1, 3, 2}
   387  	pages := []page{
   388  		{
   389  			firstbatchIdx:             0,
   390  			numBatches:                2,
   391  			firstEventFailoverVersion: 1,
   392  			lastEventFailoverVersion:  1,
   393  		},
   394  		{
   395  			firstbatchIdx:             2,
   396  			numBatches:                1,
   397  			firstEventFailoverVersion: 1,
   398  			lastEventFailoverVersion:  1,
   399  		},
   400  		{
   401  			firstbatchIdx:             3,
   402  			numBatches:                2,
   403  			firstEventFailoverVersion: 1,
   404  			lastEventFailoverVersion:  1,
   405  		},
   406  		{
   407  			firstbatchIdx:             5,
   408  			numBatches:                1,
   409  			firstEventFailoverVersion: 1,
   410  			lastEventFailoverVersion:  1,
   411  		},
   412  	}
   413  	s.initMockExecutionManager(batchInfo, 3, false, pages...)
   414  	// set target blob size such that the first two pages are read for blob one without error, third page will return error
   415  	itr := s.constructTestHistoryIterator(s.mockExecutionMgr, 6*testDefaultHistoryEventSize, nil)
   416  	blob, err := itr.Next(context.Background())
   417  	s.NoError(err)
   418  	expectedIteratorState := historyIteratorState{
   419  		FinishedIteration: false,
   420  		NextEventID:       7,
   421  	}
   422  	s.assertStateMatches(expectedIteratorState, itr)
   423  	s.NotNil(blob)
   424  	expectedHeader := &archiverspb.HistoryBlobHeader{
   425  		Namespace:            testNamespace,
   426  		NamespaceId:          testNamespaceID,
   427  		WorkflowId:           testWorkflowID,
   428  		RunId:                testRunID,
   429  		IsLast:               false,
   430  		FirstFailoverVersion: 1,
   431  		LastFailoverVersion:  1,
   432  		FirstEventId:         common.FirstEventID,
   433  		LastEventId:          6,
   434  		EventCount:           6,
   435  	}
   436  	s.Equal(expectedHeader, blob.Header)
   437  	s.NoError(err)
   438  	s.True(itr.HasNext())
   439  
   440  	blob, err = itr.Next(context.Background())
   441  	s.Error(err)
   442  	s.Nil(blob)
   443  	s.assertStateMatches(expectedIteratorState, itr)
   444  }
   445  
   446  func (s *HistoryIteratorSuite) TestNext_Success_TenCallsToNext() {
   447  	var batchInfo []int
   448  	for i := 0; i < 100; i++ {
   449  		batchInfo = append(batchInfo, []int{1, 2, 3, 4, 4, 3, 2, 1}...)
   450  	}
   451  	var pages []page
   452  	for i := 0; i < 100; i++ {
   453  		p := page{
   454  			firstbatchIdx:             i * 8,
   455  			numBatches:                8,
   456  			firstEventFailoverVersion: 1,
   457  			lastEventFailoverVersion:  1,
   458  		}
   459  		pages = append(pages, p)
   460  	}
   461  	s.initMockExecutionManager(batchInfo, -1, true, pages...)
   462  	// set target blob size size such that every 10 persistence pages is one group of history batches
   463  	itr := s.constructTestHistoryIterator(s.mockExecutionMgr, 20*10*testDefaultHistoryEventSize, nil)
   464  	expectedIteratorState := historyIteratorState{
   465  		FinishedIteration: false,
   466  		NextEventID:       common.FirstEventID,
   467  	}
   468  	for i := 0; i < 10; i++ {
   469  		s.assertStateMatches(expectedIteratorState, itr)
   470  		s.True(itr.HasNext())
   471  		blob, err := itr.Next(context.Background())
   472  		s.NoError(err)
   473  		s.NotNil(blob)
   474  		expectedHeader := &archiverspb.HistoryBlobHeader{
   475  			Namespace:            testNamespace,
   476  			NamespaceId:          testNamespaceID,
   477  			WorkflowId:           testWorkflowID,
   478  			RunId:                testRunID,
   479  			IsLast:               false,
   480  			FirstFailoverVersion: 1,
   481  			LastFailoverVersion:  1,
   482  			FirstEventId:         common.FirstEventID + int64(i*200),
   483  			LastEventId:          int64(200 + (i * 200)),
   484  			EventCount:           200,
   485  		}
   486  		if i == 9 {
   487  			expectedHeader.IsLast = true
   488  		}
   489  		s.Equal(expectedHeader, blob.Header)
   490  
   491  		if i < 9 {
   492  			expectedIteratorState.FinishedIteration = false
   493  			expectedIteratorState.NextEventID = int64(200*(i+1) + 1)
   494  		} else {
   495  			expectedIteratorState.NextEventID = 0
   496  			expectedIteratorState.FinishedIteration = true
   497  		}
   498  	}
   499  	s.assertStateMatches(expectedIteratorState, itr)
   500  	s.False(itr.HasNext())
   501  }
   502  
   503  func (s *HistoryIteratorSuite) TestNext_Success_SameHistoryDifferentPage() {
   504  	batchInfo := []int{2, 4, 4, 3, 2, 1, 1, 2}
   505  	pages := []page{
   506  		{
   507  			firstbatchIdx:             0,
   508  			numBatches:                3,
   509  			firstEventFailoverVersion: 1,
   510  			lastEventFailoverVersion:  1,
   511  		},
   512  		{
   513  			firstbatchIdx:             2,
   514  			numBatches:                1,
   515  			firstEventFailoverVersion: 1,
   516  			lastEventFailoverVersion:  1,
   517  		},
   518  		{
   519  			firstbatchIdx:             3,
   520  			numBatches:                2,
   521  			firstEventFailoverVersion: 1,
   522  			lastEventFailoverVersion:  1,
   523  		},
   524  		{
   525  			firstbatchIdx:             4,
   526  			numBatches:                1,
   527  			firstEventFailoverVersion: 1,
   528  			lastEventFailoverVersion:  1,
   529  		},
   530  		{
   531  			firstbatchIdx:             5,
   532  			numBatches:                3,
   533  			firstEventFailoverVersion: 1,
   534  			lastEventFailoverVersion:  1,
   535  		},
   536  	}
   537  	eventsPerRead := 6
   538  	targetBlobSize := eventsPerRead * testDefaultHistoryEventSize
   539  	s.initMockExecutionManager(batchInfo, -1, true, pages...)
   540  	itr1 := s.constructTestHistoryIterator(s.mockExecutionMgr, targetBlobSize, nil)
   541  
   542  	pages = []page{
   543  		{
   544  			firstbatchIdx:             0,
   545  			numBatches:                1,
   546  			firstEventFailoverVersion: 1,
   547  			lastEventFailoverVersion:  1,
   548  		},
   549  		{
   550  			firstbatchIdx:             1,
   551  			numBatches:                3,
   552  			firstEventFailoverVersion: 1,
   553  			lastEventFailoverVersion:  1,
   554  		},
   555  		{
   556  			firstbatchIdx:             2,
   557  			numBatches:                1,
   558  			firstEventFailoverVersion: 1,
   559  			lastEventFailoverVersion:  1,
   560  		},
   561  		{
   562  			firstbatchIdx:             3,
   563  			numBatches:                5,
   564  			firstEventFailoverVersion: 1,
   565  			lastEventFailoverVersion:  1,
   566  		},
   567  		{
   568  			firstbatchIdx:             4,
   569  			numBatches:                4,
   570  			firstEventFailoverVersion: 1,
   571  			lastEventFailoverVersion:  1,
   572  		},
   573  	}
   574  	s.initMockExecutionManager(batchInfo, -1, true, pages...)
   575  	itr2 := s.constructTestHistoryIterator(s.mockExecutionMgr, targetBlobSize, nil)
   576  
   577  	totalPages := 3
   578  	expectedFirstEventID := []int64{1, 7, 14}
   579  	for i := 0; i != totalPages; i++ {
   580  		s.True(itr1.HasNext())
   581  		history1, err := itr1.Next(context.Background())
   582  		s.NoError(err)
   583  
   584  		s.True(itr2.HasNext())
   585  		history2, err := itr2.Next(context.Background())
   586  		s.NoError(err)
   587  
   588  		s.Equal(history1.Header, history2.Header)
   589  		s.Equal(len(history1.Body), len(history2.Body))
   590  		s.Equal(expectedFirstEventID[i], history1.Body[0].Events[0].GetEventId())
   591  		s.Equal(expectedFirstEventID[i], history2.Body[0].Events[0].GetEventId())
   592  	}
   593  	expectedIteratorState := historyIteratorState{
   594  		NextEventID:       0,
   595  		FinishedIteration: true,
   596  	}
   597  	s.assertStateMatches(expectedIteratorState, itr1)
   598  	s.assertStateMatches(expectedIteratorState, itr2)
   599  	s.False(itr1.HasNext())
   600  	s.False(itr2.HasNext())
   601  }
   602  
   603  func (s *HistoryIteratorSuite) TestNewIteratorWithState() {
   604  	itr := s.constructTestHistoryIterator(nil, testDefaultTargetHistoryBlobSize, nil)
   605  	testIteratorState := historyIteratorState{
   606  		FinishedIteration: true,
   607  		NextEventID:       4,
   608  	}
   609  	itr.historyIteratorState = testIteratorState
   610  	stateToken, err := itr.GetState()
   611  	s.NoError(err)
   612  
   613  	newItr := s.constructTestHistoryIterator(nil, testDefaultTargetHistoryBlobSize, stateToken)
   614  	s.assertStateMatches(testIteratorState, newItr)
   615  }
   616  
   617  func (s *HistoryIteratorSuite) initMockExecutionManager(batchInfo []int, returnErrorOnPage int, addNotExistCall bool, pages ...page) {
   618  	firstEventIDs := []int64{common.FirstEventID}
   619  	for i, batchSize := range batchInfo {
   620  		firstEventIDs = append(firstEventIDs, firstEventIDs[i]+int64(batchSize))
   621  	}
   622  
   623  	testShardId := testShardID
   624  	for i, p := range pages {
   625  		req := &persistence.ReadHistoryBranchRequest{
   626  			BranchToken: testBranchToken,
   627  			MinEventID:  firstEventIDs[p.firstbatchIdx],
   628  			MaxEventID:  common.EndEventID,
   629  			PageSize:    testDefaultPersistencePageSize,
   630  			ShardID:     testShardId,
   631  		}
   632  		if returnErrorOnPage == i {
   633  			s.mockExecutionMgr.EXPECT().ReadHistoryBranchByBatch(gomock.Any(), req).Return(nil, errors.New("got error getting workflow execution history"))
   634  			return
   635  		}
   636  
   637  		resp := &persistence.ReadHistoryBranchByBatchResponse{
   638  			History: s.constructHistoryBatches(batchInfo, p, firstEventIDs[p.firstbatchIdx]),
   639  		}
   640  		s.mockExecutionMgr.EXPECT().ReadHistoryBranchByBatch(gomock.Any(), req).Return(resp, nil).MaxTimes(2)
   641  	}
   642  
   643  	if addNotExistCall {
   644  		req := &persistence.ReadHistoryBranchRequest{
   645  			BranchToken: testBranchToken,
   646  			MinEventID:  firstEventIDs[len(firstEventIDs)-1],
   647  			MaxEventID:  common.EndEventID,
   648  			PageSize:    testDefaultPersistencePageSize,
   649  			ShardID:     testShardId,
   650  		}
   651  		s.mockExecutionMgr.EXPECT().ReadHistoryBranchByBatch(gomock.Any(), req).Return(nil, serviceerror.NewNotFound("Reach the end"))
   652  	}
   653  }
   654  
   655  func (s *HistoryIteratorSuite) copyIteratorState(itr *historyIterator) historyIteratorState {
   656  	return itr.historyIteratorState
   657  }
   658  
   659  func (s *HistoryIteratorSuite) assertStateMatches(expected historyIteratorState, itr *historyIterator) {
   660  	s.Equal(expected.NextEventID, itr.NextEventID)
   661  	s.Equal(expected.FinishedIteration, itr.FinishedIteration)
   662  }
   663  
   664  func (s *HistoryIteratorSuite) constructHistoryBatches(batchInfo []int, page page, firstEventID int64) []*historypb.History {
   665  	var batches []*historypb.History
   666  	eventsID := firstEventID
   667  	for batchIdx, numEvents := range batchInfo[page.firstbatchIdx : page.firstbatchIdx+page.numBatches] {
   668  		var events []*historypb.HistoryEvent
   669  		for i := 0; i < numEvents; i++ {
   670  			event := &historypb.HistoryEvent{
   671  				EventId: eventsID,
   672  				Version: page.firstEventFailoverVersion,
   673  			}
   674  			eventsID++
   675  			if batchIdx == page.numBatches-1 {
   676  				event.Version = page.lastEventFailoverVersion
   677  			}
   678  			events = append(events, event)
   679  		}
   680  		batches = append(batches, &historypb.History{
   681  			Events: events,
   682  		})
   683  	}
   684  	return batches
   685  }
   686  
   687  func (s *HistoryIteratorSuite) constructTestHistoryIterator(
   688  	mockExecutionMgr *persistence.MockExecutionManager,
   689  	targetHistoryBlobSize int,
   690  	initialState []byte,
   691  ) *historyIterator {
   692  	request := &ArchiveHistoryRequest{
   693  		ShardID:              testShardID,
   694  		NamespaceID:          testNamespaceID,
   695  		Namespace:            testNamespace,
   696  		WorkflowID:           testWorkflowID,
   697  		RunID:                testRunID,
   698  		BranchToken:          testBranchToken,
   699  		NextEventID:          testNextEventID,
   700  		CloseFailoverVersion: testCloseFailoverVersion,
   701  	}
   702  	itr := newHistoryIterator(request, mockExecutionMgr, targetHistoryBlobSize)
   703  	if initialState != nil {
   704  		err := itr.reset(initialState)
   705  		s.NoError(err)
   706  	}
   707  	itr.sizeEstimator = newTestSizeEstimator()
   708  	return itr
   709  }
   710  func (s *HistoryIteratorSuite) TestJSONSizeEstimator() {
   711  	e := NewJSONSizeEstimator()
   712  
   713  	historyEvent := &historypb.HistoryEvent{
   714  		EventId:   1,
   715  		EventTime: timestamppb.New(time.Date(1978, 8, 22, 12, 59, 59, 999999, time.UTC)),
   716  		TaskId:    1,
   717  		Version:   1,
   718  	}
   719  	historyEvent.EventType = enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED
   720  	historyEvent.Attributes = &historypb.HistoryEvent_WorkflowTaskScheduledEventAttributes{WorkflowTaskScheduledEventAttributes: &historypb.WorkflowTaskScheduledEventAttributes{
   721  		TaskQueue: &taskqueuepb.TaskQueue{
   722  			Name: "taskQueue",
   723  			Kind: enumspb.TASK_QUEUE_KIND_NORMAL,
   724  		},
   725  		StartToCloseTimeout: durationpb.New(10 * time.Second),
   726  		Attempt:             1,
   727  	}}
   728  
   729  	h := &historypb.History{
   730  		Events: []*historypb.HistoryEvent{
   731  			historyEvent,
   732  		},
   733  	}
   734  
   735  	size, err := e.EstimateSize(h)
   736  	s.NoError(err)
   737  
   738  	// The size seems to fluctuate between compiles using google's protoc toolchain. I'd like to delete this altogether
   739  	s.Contains([]int{295, 303}, size)
   740  }