go.uber.org/cadence@v1.2.9/internal/session_test.go (about)

     1  // Copyright (c) 2017 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package internal
    22  
    23  import (
    24  	"context"
    25  	"errors"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/stretchr/testify/mock"
    30  	"github.com/stretchr/testify/require"
    31  	"github.com/stretchr/testify/suite"
    32  )
    33  
    34  type SessionTestSuite struct {
    35  	*require.Assertions
    36  	suite.Suite
    37  	WorkflowTestSuite
    38  	sessionOptions *SessionOptions
    39  }
    40  
    41  func (s *SessionTestSuite) SetupSuite() {
    42  	s.sessionOptions = &SessionOptions{
    43  		ExecutionTimeout: time.Minute,
    44  		CreationTimeout:  time.Minute,
    45  	}
    46  }
    47  
    48  func (s *SessionTestSuite) SetupTest() {
    49  	s.Assertions = require.New(s.T())
    50  }
    51  
    52  func TestSessionTestSuite(t *testing.T) {
    53  	suite.Run(t, new(SessionTestSuite))
    54  }
    55  
    56  func (s *SessionTestSuite) TestCreationCompletion() {
    57  	workflowFn := func(ctx Context) error {
    58  		ao := ActivityOptions{
    59  			ScheduleToStartTimeout: time.Minute,
    60  			StartToCloseTimeout:    time.Minute,
    61  			HeartbeatTimeout:       time.Second * 20,
    62  		}
    63  		ctx = WithActivityOptions(ctx, ao)
    64  		sessionCtx, err := CreateSession(ctx, s.sessionOptions)
    65  		if err != nil {
    66  			return err
    67  		}
    68  		info := GetSessionInfo(sessionCtx)
    69  		if info == nil || info.sessionState != sessionStateOpen {
    70  			return errors.New("session state should be open after creation")
    71  		}
    72  
    73  		CompleteSession(sessionCtx)
    74  
    75  		info = GetSessionInfo(sessionCtx)
    76  		if info == nil || info.sessionState != sessionStateClosed {
    77  			return errors.New("session state should be closed after completion")
    78  		}
    79  		return nil
    80  	}
    81  
    82  	env := newTestWorkflowEnv(s.T())
    83  	env.RegisterWorkflow(workflowFn)
    84  	env.OnActivity(sessionCreationActivityName, mock.Anything, mock.Anything).Return(sessionCreationActivity).Once()
    85  	env.OnActivity(sessionCompletionActivityName, mock.Anything, mock.Anything).Return(sessionCompletionActivity).Once()
    86  	env.ExecuteWorkflow(workflowFn)
    87  
    88  	s.True(env.IsWorkflowCompleted())
    89  	s.NoError(env.GetWorkflowError())
    90  	env.AssertExpectations(s.T())
    91  }
    92  
    93  func (s *SessionTestSuite) TestCreationWithOpenSessionContext() {
    94  	workflowFn := func(ctx Context) error {
    95  		sessionCtx := setSessionInfo(ctx, &SessionInfo{
    96  			SessionID:    "some random sessionID",
    97  			tasklist:     "some random tasklist",
    98  			sessionState: sessionStateOpen,
    99  		})
   100  		_, err := CreateSession(sessionCtx, s.sessionOptions)
   101  		return err
   102  	}
   103  
   104  	env := newTestWorkflowEnv(s.T())
   105  	env.ExecuteWorkflow(workflowFn)
   106  
   107  	s.True(env.IsWorkflowCompleted())
   108  	s.Equal(errFoundExistingOpenSession.Error(), env.GetWorkflowError().Error())
   109  	env.AssertExpectations(s.T())
   110  }
   111  
   112  func (s *SessionTestSuite) TestCreationWithClosedSessionContext() {
   113  	workflowFn := func(ctx Context) error {
   114  		ao := ActivityOptions{
   115  			ScheduleToStartTimeout: time.Minute,
   116  			StartToCloseTimeout:    time.Minute,
   117  			HeartbeatTimeout:       time.Second * 20,
   118  		}
   119  		ctx = WithActivityOptions(ctx, ao)
   120  		sessionCtx := setSessionInfo(ctx, &SessionInfo{
   121  			SessionID:    "some random sessionID",
   122  			tasklist:     "some random tasklist",
   123  			sessionState: sessionStateClosed,
   124  		})
   125  
   126  		sessionCtx, err := CreateSession(sessionCtx, s.sessionOptions)
   127  		if err != nil {
   128  			return err
   129  		}
   130  		CompleteSession(sessionCtx)
   131  		return nil
   132  	}
   133  
   134  	env := newTestWorkflowEnv(s.T())
   135  	env.RegisterWorkflow(workflowFn)
   136  	env.OnActivity(sessionCreationActivityName, mock.Anything, mock.Anything).Return(sessionCreationActivity).Once()
   137  	env.OnActivity(sessionCompletionActivityName, mock.Anything, mock.Anything).Return(sessionCompletionActivity).Once()
   138  	env.ExecuteWorkflow(workflowFn)
   139  
   140  	s.True(env.IsWorkflowCompleted())
   141  	s.NoError(env.GetWorkflowError())
   142  	env.AssertExpectations(s.T())
   143  }
   144  
   145  func (s *SessionTestSuite) TestCreationWithFailedSessionContext() {
   146  	workflowFn := func(ctx Context) error {
   147  		ao := ActivityOptions{
   148  			ScheduleToStartTimeout: time.Minute,
   149  			StartToCloseTimeout:    time.Minute,
   150  			HeartbeatTimeout:       time.Second * 20,
   151  		}
   152  		ctx = WithActivityOptions(ctx, ao)
   153  		sessionCtx := setSessionInfo(ctx, &SessionInfo{
   154  			SessionID:    "some random sessionID",
   155  			tasklist:     "some random tasklist",
   156  			sessionState: sessionStateFailed,
   157  		})
   158  
   159  		sessionCtx, err := CreateSession(sessionCtx, s.sessionOptions)
   160  		if err != nil {
   161  			return err
   162  		}
   163  		CompleteSession(sessionCtx)
   164  		return nil
   165  	}
   166  
   167  	env := newTestWorkflowEnv(s.T())
   168  	env.RegisterWorkflow(workflowFn)
   169  	env.OnActivity(sessionCreationActivityName, mock.Anything, mock.Anything).Return(sessionCreationActivity).Once()
   170  	env.OnActivity(sessionCompletionActivityName, mock.Anything, mock.Anything).Return(sessionCompletionActivity).Once()
   171  	env.ExecuteWorkflow(workflowFn)
   172  
   173  	s.True(env.IsWorkflowCompleted())
   174  	s.NoError(env.GetWorkflowError())
   175  	env.AssertExpectations(s.T())
   176  }
   177  
   178  func (s *SessionTestSuite) TestCompletionWithClosedSessionContext() {
   179  	workflowFn := func(ctx Context) error {
   180  		sessionCtx := setSessionInfo(ctx, &SessionInfo{
   181  			SessionID:    "some random sessionID",
   182  			tasklist:     "some random tasklist",
   183  			sessionState: sessionStateClosed,
   184  		})
   185  		CompleteSession(sessionCtx)
   186  		return nil
   187  	}
   188  
   189  	env := newTestWorkflowEnv(s.T())
   190  	env.RegisterWorkflow(workflowFn)
   191  	env.ExecuteWorkflow(workflowFn)
   192  
   193  	s.True(env.IsWorkflowCompleted())
   194  	s.NoError(env.GetWorkflowError())
   195  	env.AssertExpectations(s.T())
   196  }
   197  
   198  func (s *SessionTestSuite) TestCompletionWithFailedSessionContext() {
   199  	workflowFn := func(ctx Context) error {
   200  		sessionCtx := setSessionInfo(ctx, &SessionInfo{
   201  			SessionID:    "some random sessionID",
   202  			tasklist:     "some random tasklist",
   203  			sessionState: sessionStateFailed,
   204  		})
   205  		CompleteSession(sessionCtx)
   206  		return nil
   207  	}
   208  
   209  	env := newTestWorkflowEnv(s.T())
   210  	env.RegisterWorkflow(workflowFn)
   211  	env.ExecuteWorkflow(workflowFn)
   212  
   213  	s.True(env.IsWorkflowCompleted())
   214  	s.NoError(env.GetWorkflowError())
   215  	env.AssertExpectations(s.T())
   216  }
   217  
   218  func (s *SessionTestSuite) TestGetSessionInfo() {
   219  	workflowFn := func(ctx Context) error {
   220  		info := GetSessionInfo(ctx)
   221  		if info != nil {
   222  			return errors.New("GetSessionInfo should return nil when there's no session info")
   223  		}
   224  
   225  		sessionCtx := setSessionInfo(ctx, &SessionInfo{
   226  			SessionID:    "some random sessionID",
   227  			tasklist:     "some random tasklist",
   228  			sessionState: sessionStateFailed,
   229  		})
   230  		info = GetSessionInfo(sessionCtx)
   231  		if info == nil {
   232  			return errors.New("returned session info should not be nil")
   233  		}
   234  
   235  		newSessionInfo := &SessionInfo{
   236  			SessionID:    "another sessionID",
   237  			tasklist:     "another tasklist",
   238  			sessionState: sessionStateClosed,
   239  		}
   240  		sessionCtx = setSessionInfo(ctx, newSessionInfo)
   241  		info = GetSessionInfo(sessionCtx)
   242  		if info == nil {
   243  			return errors.New("returned session info should not be nil")
   244  		}
   245  		if info != newSessionInfo {
   246  			return errors.New("GetSessionInfo should return info for the most recent session in the context")
   247  		}
   248  		return nil
   249  	}
   250  
   251  	env := newTestWorkflowEnv(s.T())
   252  	env.RegisterWorkflow(workflowFn)
   253  	env.ExecuteWorkflow(workflowFn)
   254  
   255  	s.True(env.IsWorkflowCompleted())
   256  	s.NoError(env.GetWorkflowError())
   257  }
   258  
   259  func (s *SessionTestSuite) TestRecreation() {
   260  	workflowFn := func(ctx Context) error {
   261  		ao := ActivityOptions{
   262  			ScheduleToStartTimeout: time.Minute,
   263  			StartToCloseTimeout:    time.Minute,
   264  			HeartbeatTimeout:       time.Second * 20,
   265  		}
   266  		ctx = WithActivityOptions(ctx, ao)
   267  		sessionInfo := &SessionInfo{
   268  			SessionID:    "some random sessionID",
   269  			tasklist:     "some random tasklist",
   270  			sessionState: sessionStateFailed,
   271  		}
   272  
   273  		sessionCtx, err := RecreateSession(ctx, sessionInfo.GetRecreateToken(), s.sessionOptions)
   274  		if err != nil {
   275  			return err
   276  		}
   277  		CompleteSession(sessionCtx)
   278  		return nil
   279  	}
   280  
   281  	env := newTestWorkflowEnv(s.T())
   282  	env.RegisterWorkflow(workflowFn)
   283  	env.OnActivity(sessionCreationActivityName, mock.Anything, mock.Anything).Return(sessionCreationActivity).Once()
   284  	env.OnActivity(sessionCompletionActivityName, mock.Anything, mock.Anything).Return(sessionCompletionActivity).Once()
   285  	env.ExecuteWorkflow(workflowFn)
   286  
   287  	s.True(env.IsWorkflowCompleted())
   288  	s.NoError(env.GetWorkflowError())
   289  	env.AssertExpectations(s.T())
   290  }
   291  
   292  func (s *SessionTestSuite) TestMaxConcurrentSession_CreationOnly() {
   293  	maxConcurrentSessionExecutionSize := 3
   294  	workflowFn := func(ctx Context) error {
   295  		ao := ActivityOptions{
   296  			ScheduleToStartTimeout: time.Minute,
   297  			StartToCloseTimeout:    time.Minute,
   298  			HeartbeatTimeout:       time.Second * 20,
   299  		}
   300  		ctx = WithActivityOptions(ctx, ao)
   301  		for i := 0; i != maxConcurrentSessionExecutionSize+1; i++ {
   302  			if _, err := s.createSessionWithoutRetry(ctx); err != nil {
   303  				return err
   304  			}
   305  		}
   306  		return nil
   307  	}
   308  
   309  	env := newTestWorkflowEnv(s.T())
   310  	env.RegisterWorkflow(workflowFn)
   311  	env.SetWorkerOptions(WorkerOptions{
   312  		MaxConcurrentSessionExecutionSize: maxConcurrentSessionExecutionSize,
   313  	})
   314  	env.ExecuteWorkflow(workflowFn)
   315  
   316  	s.True(env.IsWorkflowCompleted())
   317  	s.Equal(errTooManySessionsMsg, env.GetWorkflowError().Error())
   318  }
   319  
   320  func (s *SessionTestSuite) TestMaxConcurrentSession_WithRecreation() {
   321  	maxConcurrentSessionExecutionSize := 3
   322  	workflowFn := func(ctx Context) error {
   323  		ao := ActivityOptions{
   324  			ScheduleToStartTimeout: time.Minute,
   325  			StartToCloseTimeout:    time.Minute,
   326  			HeartbeatTimeout:       time.Second * 20,
   327  		}
   328  		ctx = WithActivityOptions(ctx, ao)
   329  		sessionCtx, err := CreateSession(ctx, s.sessionOptions)
   330  		if err != nil {
   331  			return err
   332  		}
   333  		sessionInfo := GetSessionInfo(sessionCtx)
   334  		if sessionInfo == nil {
   335  			return errors.New("Returned session info should not be nil")
   336  		}
   337  
   338  		for i := 0; i != maxConcurrentSessionExecutionSize; i++ {
   339  			if i%2 == 0 {
   340  				_, err = s.createSessionWithoutRetry(ctx)
   341  			} else {
   342  				_, err = RecreateSession(ctx, sessionInfo.GetRecreateToken(), s.sessionOptions)
   343  			}
   344  			if err != nil {
   345  				return err
   346  			}
   347  		}
   348  		return nil
   349  	}
   350  
   351  	env := newTestWorkflowEnv(s.T())
   352  	env.RegisterWorkflow(workflowFn)
   353  	env.SetWorkerOptions(WorkerOptions{
   354  		MaxConcurrentSessionExecutionSize: maxConcurrentSessionExecutionSize,
   355  	})
   356  	env.OnActivity(sessionCreationActivityName, mock.Anything, mock.Anything).Return(sessionCreationActivity)
   357  	env.ExecuteWorkflow(workflowFn)
   358  
   359  	s.True(env.IsWorkflowCompleted())
   360  	s.Equal(errTooManySessionsMsg, env.GetWorkflowError().Error())
   361  	env.AssertExpectations(s.T())
   362  }
   363  
   364  func (s *SessionTestSuite) TestSessionTaskList() {
   365  	numActivities := 3
   366  	workflowFn := func(ctx Context) error {
   367  		ao := ActivityOptions{
   368  			ScheduleToStartTimeout: time.Minute,
   369  			StartToCloseTimeout:    time.Minute,
   370  			HeartbeatTimeout:       time.Second * 20,
   371  		}
   372  		ctx = WithActivityOptions(ctx, ao)
   373  		sessionCtx, err := CreateSession(ctx, s.sessionOptions)
   374  		if err != nil {
   375  			return err
   376  		}
   377  
   378  		for i := 0; i != numActivities; i++ {
   379  			if err := ExecuteActivity(sessionCtx, testSessionActivity, "a random name").Get(sessionCtx, nil); err != nil {
   380  				return err
   381  			}
   382  		}
   383  
   384  		CompleteSession(sessionCtx)
   385  		return nil
   386  	}
   387  
   388  	env := newTestWorkflowEnv(s.T())
   389  	env.RegisterActivity(testSessionActivity)
   390  
   391  	var taskListUsed []string
   392  	env.SetOnActivityStartedListener(func(activityInfo *ActivityInfo, ctx context.Context, args Values) {
   393  		taskListUsed = append(taskListUsed, activityInfo.TaskList)
   394  	})
   395  	resourceID := "testResourceID"
   396  	env.OnActivity(sessionCreationActivityName, mock.Anything, mock.Anything).Return(sessionCreationActivity).Once()
   397  	env.OnActivity(sessionCompletionActivityName, mock.Anything, mock.Anything).Return(sessionCompletionActivity).Once()
   398  	env.ExecuteWorkflow(workflowFn)
   399  
   400  	s.True(env.IsWorkflowCompleted())
   401  	s.NoError(env.GetWorkflowError())
   402  	s.Equal(getCreationTasklist(defaultTestTaskList), taskListUsed[0])
   403  	expectedTaskList := getResourceSpecificTasklist(resourceID)
   404  	for _, taskList := range taskListUsed[1:] {
   405  		s.Equal(expectedTaskList, taskList)
   406  	}
   407  	env.AssertExpectations(s.T())
   408  }
   409  
   410  func (s *SessionTestSuite) TestSessionRecreationTaskList() {
   411  	numActivities := 3
   412  	resourceID := "testResourceID"
   413  	resourceSpecificTaskList := getResourceSpecificTasklist(resourceID)
   414  	workflowFn := func(ctx Context) error {
   415  		ao := ActivityOptions{
   416  			ScheduleToStartTimeout: time.Minute,
   417  			StartToCloseTimeout:    time.Minute,
   418  			HeartbeatTimeout:       time.Second * 20,
   419  		}
   420  		ctx = WithActivityOptions(ctx, ao)
   421  
   422  		sessionInfo := &SessionInfo{
   423  			SessionID:    "testSessionID",
   424  			tasklist:     resourceSpecificTaskList,
   425  			sessionState: sessionStateClosed,
   426  		}
   427  		sessionCtx, err := RecreateSession(ctx, sessionInfo.GetRecreateToken(), s.sessionOptions)
   428  		if err != nil {
   429  			return err
   430  		}
   431  
   432  		for i := 0; i != numActivities; i++ {
   433  			if err := ExecuteActivity(sessionCtx, testSessionActivity, "a random name").Get(sessionCtx, nil); err != nil {
   434  				return err
   435  			}
   436  		}
   437  
   438  		CompleteSession(sessionCtx)
   439  		return nil
   440  	}
   441  
   442  	env := newTestWorkflowEnv(s.T())
   443  	env.RegisterActivity(testSessionActivity)
   444  
   445  	var taskListUsed []string
   446  	env.SetOnActivityStartedListener(func(activityInfo *ActivityInfo, ctx context.Context, args Values) {
   447  		taskListUsed = append(taskListUsed, activityInfo.TaskList)
   448  	})
   449  	env.OnActivity(sessionCreationActivityName, mock.Anything, mock.Anything).Return(sessionCreationActivity).Once()
   450  	env.OnActivity(sessionCompletionActivityName, mock.Anything, mock.Anything).Return(sessionCompletionActivity).Once()
   451  	env.ExecuteWorkflow(workflowFn)
   452  
   453  	s.True(env.IsWorkflowCompleted())
   454  	s.NoError(env.GetWorkflowError())
   455  	for _, taskList := range taskListUsed {
   456  		s.Equal(resourceSpecificTaskList, taskList)
   457  	}
   458  	env.AssertExpectations(s.T())
   459  }
   460  
   461  func (s *SessionTestSuite) TestExecuteActivityInFailedSession() {
   462  	workflowFn := func(ctx Context) error {
   463  		ao := ActivityOptions{
   464  			ScheduleToStartTimeout: time.Minute,
   465  			StartToCloseTimeout:    time.Minute,
   466  			HeartbeatTimeout:       time.Second * 20,
   467  		}
   468  		ctx = WithActivityOptions(ctx, ao)
   469  		sessionCtx := setSessionInfo(ctx, &SessionInfo{
   470  			SessionID:    "random sessionID",
   471  			tasklist:     "random tasklist",
   472  			sessionState: sessionStateFailed,
   473  		})
   474  
   475  		return ExecuteActivity(sessionCtx, testSessionActivity, "a random name").Get(sessionCtx, nil)
   476  	}
   477  
   478  	env := newTestWorkflowEnv(s.T())
   479  	env.RegisterWorkflow(workflowFn)
   480  	env.ExecuteWorkflow(workflowFn)
   481  
   482  	s.True(env.IsWorkflowCompleted())
   483  	s.Equal(ErrSessionFailed.Error(), env.GetWorkflowError().Error())
   484  }
   485  
   486  func (s *SessionTestSuite) TestExecuteActivityInClosedSession() {
   487  	workflowFn := func(ctx Context) error {
   488  		ao := ActivityOptions{
   489  			ScheduleToStartTimeout: time.Minute,
   490  			StartToCloseTimeout:    time.Minute,
   491  			HeartbeatTimeout:       time.Second * 20,
   492  		}
   493  		ctx = WithActivityOptions(ctx, ao)
   494  		sessionCtx := setSessionInfo(ctx, &SessionInfo{
   495  			SessionID:    "random sessionID",
   496  			tasklist:     "random tasklist",
   497  			sessionState: sessionStateClosed,
   498  		})
   499  
   500  		return ExecuteActivity(sessionCtx, testSessionActivity, "some random message").Get(sessionCtx, nil)
   501  	}
   502  
   503  	env := newTestWorkflowEnv(s.T())
   504  	env.RegisterWorkflow(workflowFn)
   505  	env.RegisterActivity(testSessionActivity)
   506  	var taskListUsed string
   507  	env.SetOnActivityStartedListener(func(activityInfo *ActivityInfo, ctx context.Context, args Values) {
   508  		taskListUsed = activityInfo.TaskList
   509  	})
   510  	env.ExecuteWorkflow(workflowFn)
   511  
   512  	s.True(env.IsWorkflowCompleted())
   513  	s.NoError(env.GetWorkflowError())
   514  	s.Equal(defaultTestTaskList, taskListUsed)
   515  }
   516  
   517  func (s *SessionTestSuite) TestSessionRecreateToken() {
   518  	testTasklist := "some random tasklist"
   519  
   520  	sessionInfo := &SessionInfo{
   521  		SessionID:    "testSessionID",
   522  		tasklist:     tasklist,
   523  		sessionState: sessionStateClosed,
   524  	}
   525  	token := sessionInfo.GetRecreateToken()
   526  	params, err := deserializeRecreateToken(token)
   527  	s.NoError(err)
   528  	s.Equal(testTasklist, params.Tasklist)
   529  }
   530  
   531  func (s *SessionTestSuite) TestInvalidRecreateToken() {
   532  	token := []byte("some invalid token")
   533  	sessionCtx, err := RecreateSession(Background(), token, s.sessionOptions)
   534  	s.Error(err)
   535  	s.Nil(sessionCtx)
   536  }
   537  
   538  func (s *SessionTestSuite) TestCompletionFailed() {
   539  	workflowFn := func(ctx Context) error {
   540  		ao := ActivityOptions{
   541  			ScheduleToStartTimeout: time.Minute,
   542  			StartToCloseTimeout:    time.Minute,
   543  			HeartbeatTimeout:       time.Second * 20,
   544  		}
   545  		ctx = WithActivityOptions(ctx, ao)
   546  		sessionCtx, err := CreateSession(ctx, s.sessionOptions)
   547  		if err != nil {
   548  			return err
   549  		}
   550  
   551  		CompleteSession(sessionCtx)
   552  
   553  		info := GetSessionInfo(sessionCtx)
   554  		if info == nil || info.sessionState != sessionStateClosed {
   555  			return errors.New("session state should be closed after completion even when completion activity failed")
   556  		}
   557  		return nil
   558  	}
   559  
   560  	env := newTestWorkflowEnv(s.T())
   561  	env.RegisterWorkflow(workflowFn)
   562  	env.OnActivity(sessionCreationActivityName, mock.Anything, mock.Anything).Return(sessionCreationActivity).Once()
   563  	env.OnActivity(sessionCompletionActivityName, mock.Anything, mock.Anything).Return(errors.New("some random error")).Once()
   564  	env.ExecuteWorkflow(workflowFn)
   565  
   566  	env.AssertExpectations(s.T())
   567  	s.True(env.IsWorkflowCompleted())
   568  	s.NoError(env.GetWorkflowError())
   569  	env.AssertExpectations(s.T())
   570  }
   571  
   572  func (s *SessionTestSuite) TestUserTimerWithinSession() {
   573  	workflowFn := func(ctx Context) error {
   574  		sessionCtx, err := CreateSession(ctx, s.sessionOptions)
   575  		if err != nil {
   576  			return err
   577  		}
   578  
   579  		defer CompleteSession(sessionCtx)
   580  
   581  		if err := NewTimer(sessionCtx, time.Hour).Get(sessionCtx, nil); err != nil {
   582  			return err
   583  		}
   584  		return nil
   585  	}
   586  
   587  	env := newTestWorkflowEnv(s.T())
   588  	env.RegisterWorkflow(workflowFn)
   589  	env.ExecuteWorkflow(workflowFn)
   590  
   591  	env.AssertExpectations(s.T())
   592  	s.True(env.IsWorkflowCompleted())
   593  	s.NoError(env.GetWorkflowError())
   594  }
   595  
   596  func (s *SessionTestSuite) TestActivityRetryWithinSession() {
   597  	workflowFn := func(ctx Context) error {
   598  		ao := ActivityOptions{
   599  			ScheduleToStartTimeout: time.Minute,
   600  			StartToCloseTimeout:    time.Minute,
   601  			HeartbeatTimeout:       time.Second * 20,
   602  			RetryPolicy: &RetryPolicy{
   603  				InitialInterval:          time.Second,
   604  				BackoffCoefficient:       2.0,
   605  				MaximumInterval:          time.Minute,
   606  				ExpirationInterval:       time.Minute * 10,
   607  				NonRetriableErrorReasons: []string{"bad-error"},
   608  			},
   609  		}
   610  		ctx = WithActivityOptions(ctx, ao)
   611  		sessionCtx, err := CreateSession(ctx, s.sessionOptions)
   612  		if err != nil {
   613  			return err
   614  		}
   615  
   616  		defer CompleteSession(sessionCtx)
   617  
   618  		if err := ExecuteActivity(sessionCtx, testSessionActivity, "").Get(sessionCtx, nil); err != nil {
   619  			return err
   620  		}
   621  		return nil
   622  	}
   623  
   624  	env := newTestWorkflowEnv(s.T())
   625  	env.RegisterActivity(testSessionActivity)
   626  	env.OnActivity(testSessionActivity, mock.Anything, mock.Anything).Return("", errors.New("some random error"))
   627  	env.ExecuteWorkflow(workflowFn)
   628  
   629  	env.AssertExpectations(s.T())
   630  	s.True(env.IsWorkflowCompleted())
   631  	s.Error(env.GetWorkflowError())
   632  }
   633  
   634  func (s *SessionTestSuite) createSessionWithoutRetry(ctx Context) (Context, error) {
   635  	options := getActivityOptions(ctx)
   636  	baseTasklist := options.TaskListName
   637  	if baseTasklist == "" {
   638  		baseTasklist = options.OriginalTaskListName
   639  	}
   640  	return createSession(ctx, getCreationTasklist(baseTasklist), s.sessionOptions, false)
   641  }
   642  
   643  func testSessionActivity(ctx context.Context, name string) (string, error) {
   644  	return "Hello" + name + "!", nil
   645  }