go.temporal.io/server@v1.23.0/common/xdc/ndc_history_resender_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 xdc
    26  
    27  import (
    28  	"context"
    29  	"testing"
    30  	"time"
    31  
    32  	"github.com/golang/mock/gomock"
    33  	"github.com/pborman/uuid"
    34  	"github.com/stretchr/testify/require"
    35  	"github.com/stretchr/testify/suite"
    36  	commonpb "go.temporal.io/api/common/v1"
    37  	enumspb "go.temporal.io/api/enums/v1"
    38  	historypb "go.temporal.io/api/history/v1"
    39  	"google.golang.org/protobuf/types/known/timestamppb"
    40  
    41  	"go.temporal.io/server/api/adminservice/v1"
    42  	"go.temporal.io/server/api/adminservicemock/v1"
    43  	historyspb "go.temporal.io/server/api/history/v1"
    44  	"go.temporal.io/server/api/historyservice/v1"
    45  	"go.temporal.io/server/api/historyservicemock/v1"
    46  	persistencespb "go.temporal.io/server/api/persistence/v1"
    47  	"go.temporal.io/server/client"
    48  	"go.temporal.io/server/common"
    49  	"go.temporal.io/server/common/cluster"
    50  	"go.temporal.io/server/common/log"
    51  	"go.temporal.io/server/common/namespace"
    52  	"go.temporal.io/server/common/persistence/serialization"
    53  	"go.temporal.io/server/common/primitives/timestamp"
    54  	serviceerrors "go.temporal.io/server/common/serviceerror"
    55  )
    56  
    57  type (
    58  	nDCHistoryResenderSuite struct {
    59  		suite.Suite
    60  		*require.Assertions
    61  
    62  		controller          *gomock.Controller
    63  		mockClusterMetadata *cluster.MockMetadata
    64  		mockNamespaceCache  *namespace.MockRegistry
    65  		mockClientBean      *client.MockBean
    66  		mockAdminClient     *adminservicemock.MockAdminServiceClient
    67  		mockHistoryClient   *historyservicemock.MockHistoryServiceClient
    68  
    69  		namespaceID namespace.ID
    70  		namespace   namespace.Name
    71  
    72  		serializer serialization.Serializer
    73  		logger     log.Logger
    74  
    75  		rereplicator *NDCHistoryResenderImpl
    76  	}
    77  )
    78  
    79  func TestNDCHistoryResenderSuite(t *testing.T) {
    80  	s := new(nDCHistoryResenderSuite)
    81  	suite.Run(t, s)
    82  }
    83  
    84  func (s *nDCHistoryResenderSuite) SetupSuite() {
    85  }
    86  
    87  func (s *nDCHistoryResenderSuite) TearDownSuite() {
    88  
    89  }
    90  
    91  func (s *nDCHistoryResenderSuite) SetupTest() {
    92  	s.Assertions = require.New(s.T())
    93  
    94  	s.controller = gomock.NewController(s.T())
    95  	s.mockClusterMetadata = cluster.NewMockMetadata(s.controller)
    96  	s.mockClientBean = client.NewMockBean(s.controller)
    97  	s.mockAdminClient = adminservicemock.NewMockAdminServiceClient(s.controller)
    98  	s.mockHistoryClient = historyservicemock.NewMockHistoryServiceClient(s.controller)
    99  	s.mockNamespaceCache = namespace.NewMockRegistry(s.controller)
   100  
   101  	s.mockClientBean.EXPECT().GetRemoteAdminClient(gomock.Any()).Return(s.mockAdminClient, nil).AnyTimes()
   102  
   103  	s.logger = log.NewTestLogger()
   104  	s.mockClusterMetadata.EXPECT().IsGlobalNamespaceEnabled().Return(true).AnyTimes()
   105  
   106  	s.namespaceID = namespace.ID(uuid.New())
   107  	s.namespace = "some random namespace name"
   108  	namespaceEntry := namespace.NewGlobalNamespaceForTest(
   109  		&persistencespb.NamespaceInfo{Id: s.namespaceID.String(), Name: s.namespace.String()},
   110  		&persistencespb.NamespaceConfig{Retention: timestamp.DurationFromDays(1)},
   111  		&persistencespb.NamespaceReplicationConfig{
   112  			ActiveClusterName: cluster.TestCurrentClusterName,
   113  			Clusters: []string{
   114  				cluster.TestCurrentClusterName,
   115  				cluster.TestAlternativeClusterName,
   116  			},
   117  		},
   118  		1234,
   119  	)
   120  	s.mockNamespaceCache.EXPECT().GetNamespaceByID(s.namespaceID).Return(namespaceEntry, nil).AnyTimes()
   121  	s.mockNamespaceCache.EXPECT().GetNamespace(s.namespace).Return(namespaceEntry, nil).AnyTimes()
   122  	s.serializer = serialization.NewSerializer()
   123  
   124  	s.rereplicator = NewNDCHistoryResender(
   125  		s.mockNamespaceCache,
   126  		s.mockClientBean,
   127  		func(ctx context.Context, request *historyservice.ReplicateEventsV2Request) error {
   128  			_, err := s.mockHistoryClient.ReplicateEventsV2(ctx, request)
   129  			return err
   130  		},
   131  		serialization.NewSerializer(),
   132  		nil,
   133  		s.logger,
   134  	)
   135  }
   136  
   137  func (s *nDCHistoryResenderSuite) TearDownTest() {
   138  	s.controller.Finish()
   139  }
   140  
   141  func (s *nDCHistoryResenderSuite) TestSendSingleWorkflowHistory() {
   142  	workflowID := "some random workflow ID"
   143  	runID := uuid.New()
   144  	startEventID := int64(123)
   145  	startEventVersion := int64(100)
   146  	token := []byte{1}
   147  	pageSize := defaultPageSize
   148  	eventBatch := []*historypb.HistoryEvent{
   149  		{
   150  			EventId:   2,
   151  			Version:   123,
   152  			EventTime: timestamppb.New(time.Now().UTC()),
   153  			EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_SCHEDULED,
   154  		},
   155  		{
   156  			EventId:   3,
   157  			Version:   123,
   158  			EventTime: timestamppb.New(time.Now().UTC()),
   159  			EventType: enumspb.EVENT_TYPE_WORKFLOW_TASK_STARTED,
   160  		},
   161  	}
   162  	blob := s.serializeEvents(eventBatch)
   163  	versionHistoryItems := []*historyspb.VersionHistoryItem{
   164  		{
   165  			EventId: 1,
   166  			Version: 1,
   167  		},
   168  	}
   169  
   170  	s.mockAdminClient.EXPECT().GetWorkflowExecutionRawHistoryV2(
   171  		gomock.Any(),
   172  		&adminservice.GetWorkflowExecutionRawHistoryV2Request{
   173  			NamespaceId: s.namespaceID.String(),
   174  			Execution: &commonpb.WorkflowExecution{
   175  				WorkflowId: workflowID,
   176  				RunId:      runID,
   177  			},
   178  			StartEventId:      startEventID,
   179  			StartEventVersion: startEventVersion,
   180  			EndEventId:        common.EmptyEventID,
   181  			EndEventVersion:   common.EmptyVersion,
   182  			MaximumPageSize:   pageSize,
   183  			NextPageToken:     nil,
   184  		}).Return(&adminservice.GetWorkflowExecutionRawHistoryV2Response{
   185  		HistoryBatches: []*commonpb.DataBlob{blob},
   186  		NextPageToken:  token,
   187  		VersionHistory: &historyspb.VersionHistory{
   188  			Items: versionHistoryItems,
   189  		},
   190  	}, nil)
   191  
   192  	s.mockAdminClient.EXPECT().GetWorkflowExecutionRawHistoryV2(
   193  		gomock.Any(),
   194  		&adminservice.GetWorkflowExecutionRawHistoryV2Request{
   195  			NamespaceId: s.namespaceID.String(),
   196  			Execution: &commonpb.WorkflowExecution{
   197  				WorkflowId: workflowID,
   198  				RunId:      runID,
   199  			},
   200  			StartEventId:      startEventID,
   201  			StartEventVersion: startEventVersion,
   202  			EndEventId:        common.EmptyEventID,
   203  			EndEventVersion:   common.EmptyVersion,
   204  			MaximumPageSize:   pageSize,
   205  			NextPageToken:     token,
   206  		}).Return(&adminservice.GetWorkflowExecutionRawHistoryV2Response{
   207  		HistoryBatches: []*commonpb.DataBlob{blob},
   208  		NextPageToken:  nil,
   209  		VersionHistory: &historyspb.VersionHistory{
   210  			Items: versionHistoryItems,
   211  		},
   212  	}, nil)
   213  
   214  	s.mockHistoryClient.EXPECT().ReplicateEventsV2(
   215  		gomock.Any(),
   216  		&historyservice.ReplicateEventsV2Request{
   217  			NamespaceId: s.namespaceID.String(),
   218  			WorkflowExecution: &commonpb.WorkflowExecution{
   219  				WorkflowId: workflowID,
   220  				RunId:      runID,
   221  			},
   222  			VersionHistoryItems: versionHistoryItems,
   223  			Events:              blob,
   224  		}).Return(nil, nil).Times(2)
   225  
   226  	err := s.rereplicator.SendSingleWorkflowHistory(
   227  		context.Background(),
   228  		cluster.TestCurrentClusterName,
   229  		s.namespaceID,
   230  		workflowID,
   231  		runID,
   232  		startEventID,
   233  		startEventVersion,
   234  		common.EmptyEventID,
   235  		common.EmptyVersion,
   236  	)
   237  
   238  	s.Nil(err)
   239  }
   240  
   241  func (s *nDCHistoryResenderSuite) TestCreateReplicateRawEventsRequest() {
   242  	workflowID := "some random workflow ID"
   243  	runID := uuid.New()
   244  	blob := &commonpb.DataBlob{
   245  		EncodingType: enumspb.ENCODING_TYPE_PROTO3,
   246  		Data:         []byte("some random history blob"),
   247  	}
   248  	versionHistoryItems := []*historyspb.VersionHistoryItem{
   249  		{
   250  			EventId: 1,
   251  			Version: 1,
   252  		},
   253  	}
   254  
   255  	s.Equal(&historyservice.ReplicateEventsV2Request{
   256  		NamespaceId: s.namespaceID.String(),
   257  		WorkflowExecution: &commonpb.WorkflowExecution{
   258  			WorkflowId: workflowID,
   259  			RunId:      runID,
   260  		},
   261  		VersionHistoryItems: versionHistoryItems,
   262  		Events:              blob,
   263  	}, s.rereplicator.createReplicationRawRequest(
   264  		s.namespaceID,
   265  		workflowID,
   266  		runID,
   267  		blob,
   268  		versionHistoryItems))
   269  }
   270  
   271  func (s *nDCHistoryResenderSuite) TestSendReplicationRawRequest() {
   272  	workflowID := "some random workflow ID"
   273  	runID := uuid.New()
   274  	item := &historyspb.VersionHistoryItem{
   275  		EventId: 1,
   276  		Version: 1,
   277  	}
   278  	request := &historyservice.ReplicateEventsV2Request{
   279  		NamespaceId: s.namespaceID.String(),
   280  		WorkflowExecution: &commonpb.WorkflowExecution{
   281  			WorkflowId: workflowID,
   282  			RunId:      runID,
   283  		},
   284  		Events: &commonpb.DataBlob{
   285  			EncodingType: enumspb.ENCODING_TYPE_PROTO3,
   286  			Data:         []byte("some random history blob"),
   287  		},
   288  		VersionHistoryItems: []*historyspb.VersionHistoryItem{item},
   289  	}
   290  
   291  	s.mockHistoryClient.EXPECT().ReplicateEventsV2(gomock.Any(), request).Return(nil, nil)
   292  	err := s.rereplicator.sendReplicationRawRequest(context.Background(), request)
   293  	s.Nil(err)
   294  }
   295  
   296  func (s *nDCHistoryResenderSuite) TestSendReplicationRawRequest_Err() {
   297  	workflowID := "some random workflow ID"
   298  	runID := uuid.New()
   299  	item := &historyspb.VersionHistoryItem{
   300  		EventId: 1,
   301  		Version: 1,
   302  	}
   303  	request := &historyservice.ReplicateEventsV2Request{
   304  		NamespaceId: s.namespaceID.String(),
   305  		WorkflowExecution: &commonpb.WorkflowExecution{
   306  			WorkflowId: workflowID,
   307  			RunId:      runID,
   308  		},
   309  		Events: &commonpb.DataBlob{
   310  			EncodingType: enumspb.ENCODING_TYPE_PROTO3,
   311  			Data:         []byte("some random history blob"),
   312  		},
   313  		VersionHistoryItems: []*historyspb.VersionHistoryItem{item},
   314  	}
   315  	retryErr := serviceerrors.NewRetryReplication(
   316  		"",
   317  		s.namespaceID.String(),
   318  		workflowID,
   319  		runID,
   320  		common.EmptyEventID,
   321  		common.EmptyVersion,
   322  		common.EmptyEventID,
   323  		common.EmptyVersion,
   324  	)
   325  
   326  	s.mockHistoryClient.EXPECT().ReplicateEventsV2(gomock.Any(), request).Return(nil, retryErr)
   327  	err := s.rereplicator.sendReplicationRawRequest(context.Background(), request)
   328  	s.Equal(retryErr, err)
   329  }
   330  
   331  func (s *nDCHistoryResenderSuite) TestGetHistory() {
   332  	workflowID := "some random workflow ID"
   333  	runID := uuid.New()
   334  	startEventID := int64(123)
   335  	endEventID := int64(345)
   336  	version := int64(20)
   337  	nextTokenIn := []byte("some random next token in")
   338  	nextTokenOut := []byte("some random next token out")
   339  	pageSize := int32(59)
   340  	blob := []byte("some random events blob")
   341  
   342  	response := &adminservice.GetWorkflowExecutionRawHistoryV2Response{
   343  		HistoryBatches: []*commonpb.DataBlob{{
   344  			EncodingType: enumspb.ENCODING_TYPE_PROTO3,
   345  			Data:         blob,
   346  		}},
   347  		NextPageToken: nextTokenOut,
   348  	}
   349  	s.mockAdminClient.EXPECT().GetWorkflowExecutionRawHistoryV2(gomock.Any(), &adminservice.GetWorkflowExecutionRawHistoryV2Request{
   350  		NamespaceId: s.namespaceID.String(),
   351  		Execution: &commonpb.WorkflowExecution{
   352  			WorkflowId: workflowID,
   353  			RunId:      runID,
   354  		},
   355  		StartEventId:      startEventID,
   356  		StartEventVersion: version,
   357  		EndEventId:        endEventID,
   358  		EndEventVersion:   version,
   359  		MaximumPageSize:   pageSize,
   360  		NextPageToken:     nextTokenIn,
   361  	}).Return(response, nil)
   362  
   363  	out, err := s.rereplicator.getHistory(
   364  		context.Background(),
   365  		cluster.TestCurrentClusterName,
   366  		s.namespaceID,
   367  		workflowID,
   368  		runID,
   369  		startEventID,
   370  		version,
   371  		endEventID,
   372  		version,
   373  		nextTokenIn,
   374  		pageSize)
   375  	s.Nil(err)
   376  	s.Equal(response, out)
   377  }
   378  
   379  func (s *nDCHistoryResenderSuite) serializeEvents(events []*historypb.HistoryEvent) *commonpb.DataBlob {
   380  	blob, err := s.serializer.SerializeEvents(events, enumspb.ENCODING_TYPE_PROTO3)
   381  	s.Nil(err)
   382  	return &commonpb.DataBlob{
   383  		EncodingType: enumspb.ENCODING_TYPE_PROTO3,
   384  		Data:         blob.Data,
   385  	}
   386  }