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

     1  // Copyright (c) 2017-2020 Uber Technologies Inc.
     2  // Portions of the Software are attributed to Copyright (c) 2020 Temporal Technologies Inc.
     3  //
     4  // Permission is hereby granted, free of charge, to any person obtaining a copy
     5  // of this software and associated documentation files (the "Software"), to deal
     6  // in the Software without restriction, including without limitation the rights
     7  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     8  // copies of the Software, and to permit persons to whom the Software is
     9  // furnished to do so, subject to the following conditions:
    10  //
    11  // The above copyright notice and this permission notice shall be included in
    12  // all copies or substantial portions of the Software.
    13  //
    14  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    15  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    16  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    17  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    18  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    19  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    20  // THE SOFTWARE.
    21  
    22  package internal
    23  
    24  import (
    25  	"errors"
    26  	"fmt"
    27  	"runtime"
    28  	"strings"
    29  	"testing"
    30  	"time"
    31  
    32  	"github.com/stretchr/testify/assert"
    33  	"github.com/stretchr/testify/require"
    34  )
    35  
    36  func createRootTestContext(t *testing.T) (ctx Context) {
    37  	env := newTestWorkflowEnv(t)
    38  	interceptors, envInterceptor := newWorkflowInterceptors(env.impl, env.impl.workflowInterceptors)
    39  	return newWorkflowContext(env.impl, interceptors, envInterceptor)
    40  }
    41  
    42  func TestDispatcher(t *testing.T) {
    43  	value := "foo"
    44  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) { value = "bar" })
    45  	require.Equal(t, "foo", value)
    46  	require.NoError(t, d.ExecuteUntilAllBlocked())
    47  	require.True(t, d.IsDone())
    48  	require.Equal(t, "bar", value)
    49  }
    50  
    51  func TestNonBlockingChildren(t *testing.T) {
    52  	var history []string
    53  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
    54  		for i := 0; i < 10; i++ {
    55  			ii := i
    56  			Go(ctx, func(ctx Context) {
    57  				history = append(history, fmt.Sprintf("child-%v", ii))
    58  			})
    59  		}
    60  		history = append(history, "root")
    61  	})
    62  	require.EqualValues(t, 0, len(history))
    63  
    64  	require.NoError(t, d.ExecuteUntilAllBlocked())
    65  	require.True(t, d.IsDone())
    66  	require.EqualValues(t, 11, len(history))
    67  }
    68  
    69  func TestNonbufferedChannel(t *testing.T) {
    70  	var history []string
    71  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
    72  		c1 := NewChannel(ctx)
    73  		Go(ctx, func(ctx Context) {
    74  			history = append(history, "child-start")
    75  			var v string
    76  			more := c1.Receive(ctx, &v)
    77  			require.True(t, more)
    78  			history = append(history, fmt.Sprintf("child-end-%v", v))
    79  		})
    80  		history = append(history, "root-before-channel-put")
    81  		c1.Send(ctx, "value1")
    82  		history = append(history, "root-after-channel-put")
    83  
    84  	})
    85  	require.EqualValues(t, 0, len(history))
    86  	require.NoError(t, d.ExecuteUntilAllBlocked())
    87  	require.True(t, d.IsDone())
    88  
    89  	expected := []string{
    90  		"root-before-channel-put",
    91  		"child-start",
    92  		"child-end-value1",
    93  		"root-after-channel-put",
    94  	}
    95  	require.EqualValues(t, expected, history)
    96  
    97  }
    98  
    99  func TestNonbufferedChannelBlockedReceive(t *testing.T) {
   100  	var history []string
   101  	var c2 Channel
   102  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   103  		c1 := NewChannel(ctx)
   104  		c2 = NewChannel(ctx)
   105  		Go(ctx, func(ctx Context) {
   106  			var v string
   107  			more := c1.Receive(ctx, &v)
   108  			require.True(t, more)
   109  			history = append(history, fmt.Sprintf("child1-end1-%v", v))
   110  			more = c1.Receive(ctx, &v)
   111  			require.True(t, more)
   112  			history = append(history, fmt.Sprintf("child1-end2-%v", v))
   113  		})
   114  		Go(ctx, func(ctx Context) {
   115  			var v string
   116  			history = append(history, "child2-start")
   117  			more := c2.Receive(ctx, &v)
   118  			require.True(t, more)
   119  			history = append(history, fmt.Sprintf("child2-end1-%v", v))
   120  			more = c2.Receive(ctx, &v)
   121  			require.True(t, more)
   122  			history = append(history, fmt.Sprintf("child2-end2-%v", v))
   123  		})
   124  
   125  		history = append(history, "root-before-channel-put")
   126  		c1.Send(ctx, "value11")
   127  		c1.Send(ctx, "value12")
   128  		history = append(history, "root-after-channel-put")
   129  
   130  	})
   131  	require.EqualValues(t, 0, len(history))
   132  	require.NoError(t, d.ExecuteUntilAllBlocked())
   133  	c2.SendAsync("value21")
   134  	require.NoError(t, d.ExecuteUntilAllBlocked())
   135  	c2.SendAsync("value22")
   136  	require.NoError(t, d.ExecuteUntilAllBlocked())
   137  	require.True(t, d.IsDone(), d.StackTrace())
   138  }
   139  
   140  func TestBufferedChannelPut(t *testing.T) {
   141  	var history []string
   142  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   143  		c1 := NewBufferedChannel(ctx, 1)
   144  		Go(ctx, func(ctx Context) {
   145  			history = append(history, "child-start")
   146  			var v1, v2 string
   147  			more := c1.Receive(ctx, &v1)
   148  			require.True(t, more)
   149  			history = append(history, fmt.Sprintf("child-end-%v", v1))
   150  			c1.Receive(ctx, &v2)
   151  			history = append(history, fmt.Sprintf("child-end-%v", v2))
   152  
   153  		})
   154  		history = append(history, "root-before-channel-put")
   155  		c1.Send(ctx, "value1")
   156  		history = append(history, "root-after-channel-put1")
   157  		c1.Send(ctx, "value2")
   158  		history = append(history, "root-after-channel-put2")
   159  	})
   160  	require.EqualValues(t, 0, len(history))
   161  	require.NoError(t, d.ExecuteUntilAllBlocked())
   162  	require.True(t, d.IsDone())
   163  
   164  	expected := []string{
   165  		"root-before-channel-put",
   166  		"root-after-channel-put1",
   167  		"child-start",
   168  		"child-end-value1",
   169  		"child-end-value2",
   170  		"root-after-channel-put2",
   171  	}
   172  	require.EqualValues(t, expected, history)
   173  }
   174  
   175  func TestBufferedChannelGet(t *testing.T) {
   176  	var history []string
   177  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   178  		c1 := NewChannel(ctx)
   179  		c2 := NewBufferedChannel(ctx, 2)
   180  
   181  		Go(ctx, func(ctx Context) {
   182  			history = append(history, "child1-start")
   183  			c2.Send(ctx, "bar1")
   184  			history = append(history, "child1-get")
   185  			var v1 string
   186  			more := c1.Receive(ctx, &v1)
   187  			require.True(t, more)
   188  			history = append(history, fmt.Sprintf("child1-end-%v", v1))
   189  
   190  		})
   191  		Go(ctx, func(ctx Context) {
   192  			history = append(history, "child2-start")
   193  			c2.Send(ctx, "bar2")
   194  			history = append(history, "child2-get")
   195  			var v1 string
   196  			more := c1.Receive(ctx, &v1)
   197  			require.True(t, more)
   198  			history = append(history, fmt.Sprintf("child2-end-%v", v1))
   199  		})
   200  		history = append(history, "root-before-channel-get1")
   201  		c2.Receive(ctx, nil)
   202  		history = append(history, "root-before-channel-get2")
   203  		c2.Receive(ctx, nil)
   204  		history = append(history, "root-before-channel-put")
   205  		c1.Send(ctx, "value1")
   206  		history = append(history, "root-after-channel-put1")
   207  		c1.Send(ctx, "value2")
   208  		history = append(history, "root-after-channel-put2")
   209  	})
   210  	require.EqualValues(t, 0, len(history))
   211  	require.NoError(t, d.ExecuteUntilAllBlocked())
   212  	require.True(t, d.IsDone(), strings.Join(history, "\n")+"\n\n"+d.StackTrace())
   213  
   214  	expected := []string{
   215  		"root-before-channel-get1",
   216  		"child1-start",
   217  		"child1-get",
   218  		"child2-start",
   219  		"child2-get",
   220  		"root-before-channel-get2",
   221  		"root-before-channel-put",
   222  		"root-after-channel-put1",
   223  		"root-after-channel-put2",
   224  		"child1-end-value1",
   225  		"child2-end-value2",
   226  	}
   227  	require.EqualValues(t, expected, history)
   228  }
   229  
   230  func TestNotBlockingSelect(t *testing.T) {
   231  	var history []string
   232  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   233  		c1 := NewBufferedChannel(ctx, 1)
   234  		c2 := NewBufferedChannel(ctx, 1)
   235  		s := NewSelector(ctx)
   236  		s.
   237  			AddReceive(c1, func(c Channel, more bool) {
   238  				require.True(t, more)
   239  				var v string
   240  				c.Receive(ctx, &v)
   241  				history = append(history, fmt.Sprintf("c1-%v", v))
   242  			}).
   243  			AddReceive(c2, func(c Channel, more bool) {
   244  				require.True(t, more)
   245  				var v string
   246  				c.Receive(ctx, &v)
   247  				history = append(history, fmt.Sprintf("c2-%v", v))
   248  			}).
   249  			AddDefault(func() { history = append(history, "default") })
   250  		c1.Send(ctx, "one")
   251  		s.Select(ctx)
   252  		c2.Send(ctx, "two")
   253  		s.Select(ctx)
   254  		s.Select(ctx)
   255  	})
   256  	require.NoError(t, d.ExecuteUntilAllBlocked())
   257  	require.True(t, d.IsDone())
   258  
   259  	expected := []string{
   260  		"c1-one",
   261  		"c2-two",
   262  		"default",
   263  	}
   264  	require.EqualValues(t, expected, history)
   265  }
   266  
   267  func TestBlockingSelect(t *testing.T) {
   268  	var history []string
   269  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   270  		c1 := NewChannel(ctx)
   271  		c2 := NewChannel(ctx)
   272  		Go(ctx, func(ctx Context) {
   273  			history = append(history, "add-one")
   274  			c1.Send(ctx, "one")
   275  			history = append(history, "add-one-done")
   276  
   277  		})
   278  		Go(ctx, func(ctx Context) {
   279  			history = append(history, "add-two")
   280  			c2.Send(ctx, "two")
   281  			history = append(history, "add-two-done")
   282  		})
   283  
   284  		s := NewSelector(ctx)
   285  		s.
   286  			AddReceive(c1, func(c Channel, more bool) {
   287  				require.True(t, more)
   288  				var v string
   289  				c.Receive(ctx, &v)
   290  				history = append(history, fmt.Sprintf("c1-%v", v))
   291  			}).
   292  			AddReceive(c2, func(c Channel, more bool) {
   293  				var v string
   294  				c.Receive(ctx, &v)
   295  				history = append(history, fmt.Sprintf("c2-%v", v))
   296  			})
   297  		history = append(history, "select1")
   298  		s.Select(ctx)
   299  		history = append(history, "select2")
   300  		s.Select(ctx)
   301  		history = append(history, "done")
   302  	})
   303  	require.NoError(t, d.ExecuteUntilAllBlocked())
   304  	require.True(t, d.IsDone(), strings.Join(history, "\n"))
   305  
   306  	expected := []string{
   307  		"select1",
   308  		"add-one",
   309  		"add-one-done",
   310  		"add-two",
   311  		"c1-one",
   312  		"select2",
   313  		"c2-two",
   314  		"done",
   315  		"add-two-done",
   316  	}
   317  	require.EqualValues(t, expected, history)
   318  }
   319  
   320  func TestBlockingSelectAsyncSend(t *testing.T) {
   321  	var history []string
   322  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   323  
   324  		c1 := NewChannel(ctx)
   325  		s := NewSelector(ctx)
   326  		s.
   327  			AddReceive(c1, func(c Channel, more bool) {
   328  				require.True(t, more)
   329  				var v int
   330  				c.Receive(ctx, &v)
   331  				history = append(history, fmt.Sprintf("c1-%v", v))
   332  			})
   333  		for i := 0; i < 3; i++ {
   334  			ii := i // to reference within closure
   335  			Go(ctx, func(ctx Context) {
   336  				history = append(history, fmt.Sprintf("add-%v", ii))
   337  				c1.SendAsync(ii)
   338  			})
   339  			history = append(history, fmt.Sprintf("select-%v", ii))
   340  			s.Select(ctx)
   341  		}
   342  		history = append(history, "done")
   343  	})
   344  	require.NoError(t, d.ExecuteUntilAllBlocked())
   345  	require.True(t, d.IsDone(), strings.Join(history, "\n"))
   346  
   347  	expected := []string{
   348  		"select-0",
   349  		"add-0",
   350  		"c1-0",
   351  		"select-1",
   352  		"add-1",
   353  		"c1-1",
   354  		"select-2",
   355  		"add-2",
   356  		"c1-2",
   357  		"done",
   358  	}
   359  	require.EqualValues(t, expected, history)
   360  }
   361  
   362  func TestSelectOnClosedChannel(t *testing.T) {
   363  	var history []string
   364  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   365  		c := NewBufferedChannel(ctx, 1)
   366  		c.Send(ctx, 5)
   367  		c.Close()
   368  
   369  		selector := NewNamedSelector(ctx, "waiting for channel")
   370  
   371  		selector.AddReceive(c, func(f Channel, more bool) {
   372  			var n int
   373  
   374  			if !more {
   375  				history = append(history, "more from function is false")
   376  				return
   377  			}
   378  
   379  			more = f.Receive(ctx, &n)
   380  			if !more {
   381  				history = append(history, "more from receive is false")
   382  				return
   383  			}
   384  			history = append(history, fmt.Sprintf("got message on channel: %v", n))
   385  		})
   386  
   387  		selector.Select(ctx)
   388  		selector.Select(ctx)
   389  		selector.Select(ctx)
   390  		selector.Select(ctx)
   391  	})
   392  	require.NoError(t, d.ExecuteUntilAllBlocked())
   393  	require.True(t, d.IsDone(), strings.Join(history, "\n"))
   394  
   395  	expected := []string{
   396  		"got message on channel: 5",
   397  		"more from function is false",
   398  		"more from function is false",
   399  		"more from function is false",
   400  	}
   401  	require.EqualValues(t, expected, history)
   402  }
   403  
   404  func TestBlockingSelectAsyncSend2(t *testing.T) {
   405  	var history []string
   406  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   407  		c1 := NewBufferedChannel(ctx, 100)
   408  		c2 := NewBufferedChannel(ctx, 100)
   409  		s := NewSelector(ctx)
   410  		s.
   411  			AddReceive(c1, func(c Channel, more bool) {
   412  				require.True(t, more)
   413  				var v string
   414  				c.Receive(ctx, &v)
   415  				history = append(history, fmt.Sprintf("c1-%v", v))
   416  			}).
   417  			AddReceive(c2, func(c Channel, more bool) {
   418  				require.True(t, more)
   419  				var v string
   420  				c.Receive(ctx, &v)
   421  				history = append(history, fmt.Sprintf("c2-%v", v))
   422  			})
   423  
   424  		history = append(history, "send-s2")
   425  		c2.SendAsync("s2")
   426  		history = append(history, "select-0")
   427  		s.Select(ctx)
   428  		history = append(history, "send-s1")
   429  		c1.SendAsync("s1")
   430  		history = append(history, "select-1")
   431  		s.Select(ctx)
   432  		history = append(history, "done")
   433  	})
   434  	require.NoError(t, d.ExecuteUntilAllBlocked())
   435  	require.True(t, d.IsDone(), strings.Join(history, "\n"))
   436  
   437  	expected := []string{
   438  		"send-s2",
   439  		"select-0",
   440  		"c2-s2",
   441  		"send-s1",
   442  		"select-1",
   443  		"c1-s1",
   444  		"done",
   445  	}
   446  	require.EqualValues(t, expected, history)
   447  }
   448  
   449  func TestSendSelect(t *testing.T) {
   450  	var history []string
   451  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   452  		c1 := NewChannel(ctx)
   453  		c2 := NewChannel(ctx)
   454  		Go(ctx, func(ctx Context) {
   455  			history = append(history, "receiver")
   456  			var v string
   457  			more := c2.Receive(ctx, &v)
   458  			require.True(t, more)
   459  			history = append(history, fmt.Sprintf("c2-%v", v))
   460  			more = c1.Receive(ctx, &v)
   461  
   462  			require.True(t, more)
   463  			history = append(history, fmt.Sprintf("c1-%v", v))
   464  		})
   465  		s := NewSelector(ctx)
   466  		s.AddSend(c1, "one", func() { history = append(history, "send1") }).
   467  			AddSend(c2, "two", func() { history = append(history, "send2") })
   468  		history = append(history, "select1")
   469  		s.Select(ctx)
   470  		history = append(history, "select2")
   471  		s.Select(ctx)
   472  		history = append(history, "done")
   473  	})
   474  	require.NoError(t, d.ExecuteUntilAllBlocked())
   475  	require.True(t, d.IsDone())
   476  
   477  	expected := []string{
   478  		"select1",
   479  		"receiver",
   480  		"c2-two",
   481  		"send2",
   482  		"select2",
   483  		"send1",
   484  		"done",
   485  		"c1-one",
   486  	}
   487  	require.EqualValues(t, expected, history)
   488  }
   489  
   490  func TestSendSelectWithAsyncReceive(t *testing.T) {
   491  	var history []string
   492  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   493  		c1 := NewChannel(ctx)
   494  		c2 := NewChannel(ctx)
   495  		Go(ctx, func(ctx Context) {
   496  			history = append(history, "receiver")
   497  			var v string
   498  			ok, more := c2.ReceiveAsyncWithMoreFlag(&v)
   499  			require.True(t, ok)
   500  			require.True(t, more)
   501  			history = append(history, fmt.Sprintf("c2-%v", v))
   502  			more = c1.Receive(ctx, &v)
   503  
   504  			require.True(t, more)
   505  			history = append(history, fmt.Sprintf("c1-%v", v))
   506  		})
   507  		s := NewSelector(ctx)
   508  		s.AddSend(c1, "one", func() { history = append(history, "send1") }).
   509  			AddSend(c2, "two", func() { history = append(history, "send2") })
   510  		history = append(history, "select1")
   511  		s.Select(ctx)
   512  		history = append(history, "select2")
   513  		s.Select(ctx)
   514  		history = append(history, "done")
   515  	})
   516  	require.NoError(t, d.ExecuteUntilAllBlocked())
   517  	require.True(t, d.IsDone(), strings.Join(history, "\n"))
   518  
   519  	expected := []string{
   520  		"select1",
   521  		"receiver",
   522  		"c2-two",
   523  		"send2",
   524  		"select2",
   525  		"send1",
   526  		"done",
   527  		"c1-one",
   528  	}
   529  	require.EqualValues(t, expected, history)
   530  }
   531  
   532  func TestChannelClose(t *testing.T) {
   533  	var history []string
   534  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   535  		jobs := NewBufferedChannel(ctx, 5)
   536  		done := NewNamedChannel(ctx, "done")
   537  
   538  		GoNamed(ctx, "receiver", func(ctx Context) {
   539  			for {
   540  				var j int
   541  				more := jobs.Receive(ctx, &j)
   542  				if more {
   543  					history = append(history, fmt.Sprintf("received job %v", j))
   544  				} else {
   545  					history = append(history, "received all jobs")
   546  					done.Send(ctx, true)
   547  					return
   548  				}
   549  			}
   550  		})
   551  		for j := 1; j <= 3; j++ {
   552  			jobs.Send(ctx, j)
   553  			history = append(history, fmt.Sprintf("sent job %v", j))
   554  		}
   555  		jobs.Close()
   556  		history = append(history, "sent all jobs")
   557  		done.Receive(ctx, nil)
   558  		history = append(history, "done")
   559  
   560  	})
   561  	require.EqualValues(t, 0, len(history))
   562  	require.NoError(t, d.ExecuteUntilAllBlocked())
   563  	require.True(t, d.IsDone(), d.StackTrace())
   564  
   565  	expected := []string{
   566  		"sent job 1",
   567  		"sent job 2",
   568  		"sent job 3",
   569  		"sent all jobs",
   570  		"received job 1",
   571  		"received job 2",
   572  		"received job 3",
   573  		"received all jobs",
   574  		"done",
   575  	}
   576  	require.EqualValues(t, expected, history)
   577  }
   578  
   579  func TestSendClosedChannel(t *testing.T) {
   580  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   581  		defer func() {
   582  			require.NotNil(t, recover(), "panic expected")
   583  		}()
   584  		c := NewChannel(ctx)
   585  		Go(ctx, func(ctx Context) {
   586  			c.Close()
   587  		})
   588  		c.Send(ctx, "baz")
   589  	})
   590  	require.NoError(t, d.ExecuteUntilAllBlocked())
   591  	require.True(t, d.IsDone())
   592  }
   593  
   594  func TestBlockedSendClosedChannel(t *testing.T) {
   595  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   596  		defer func() {
   597  			require.NotNil(t, recover(), "panic expected")
   598  		}()
   599  		c := NewBufferedChannel(ctx, 5)
   600  		c.Send(ctx, "bar")
   601  		c.Close()
   602  		c.Send(ctx, "baz")
   603  	})
   604  	require.NoError(t, d.ExecuteUntilAllBlocked())
   605  	require.True(t, d.IsDone())
   606  }
   607  
   608  func TestAsyncSendClosedChannel(t *testing.T) {
   609  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   610  		defer func() {
   611  			require.NotNil(t, recover(), "panic expected")
   612  		}()
   613  		c := NewBufferedChannel(ctx, 5)
   614  		c.Send(ctx, "bar")
   615  		c.Close()
   616  		_ = c.SendAsync("baz")
   617  	})
   618  	require.NoError(t, d.ExecuteUntilAllBlocked())
   619  	require.True(t, d.IsDone())
   620  }
   621  
   622  func TestDispatchClose(t *testing.T) {
   623  	var history []string
   624  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   625  		c := NewNamedChannel(ctx, "forever_blocked")
   626  		for i := 0; i < 10; i++ {
   627  			ii := i
   628  			GoNamed(ctx, fmt.Sprintf("c-%v", i), func(ctx Context) {
   629  				defer func() {
   630  					// Trigger no-longer-valid context access within deferred function.
   631  					// At this point deferred function should not continue and will be exited.
   632  					getState(ctx)
   633  				}()
   634  				c.Receive(ctx, nil) // blocked forever
   635  				history = append(history, fmt.Sprintf("child-%v", ii))
   636  			})
   637  		}
   638  		history = append(history, "root")
   639  		c.Receive(ctx, nil) // blocked forever
   640  	})
   641  	require.EqualValues(t, 0, len(history))
   642  	require.NoError(t, d.ExecuteUntilAllBlocked())
   643  	require.False(t, d.IsDone())
   644  	stack := d.StackTrace()
   645  	// 11 coroutines (3 lines each) + 10 nl
   646  	require.EqualValues(t, 11*3+10, len(strings.Split(stack, "\n")), stack)
   647  	require.Contains(t, stack, "coroutine 1 [blocked on forever_blocked.Receive]:")
   648  	for i := 0; i < 10; i++ {
   649  		require.Contains(t, stack, fmt.Sprintf("coroutine c-%v [blocked on forever_blocked.Receive]:", i))
   650  	}
   651  	beforeClose := runtime.NumGoroutine()
   652  	d.Close()
   653  	time.Sleep(100 * time.Millisecond) // Let all goroutines to die
   654  	closedCount := beforeClose - runtime.NumGoroutine()
   655  	require.True(t, closedCount >= 11)
   656  	expected := []string{
   657  		"root",
   658  	}
   659  	require.EqualValues(t, expected, history)
   660  	for _, c := range d.coroutines {
   661  		// Ensure that coroutines did not panic during dispatcher closing procedure
   662  		require.Nil(t, c.panicError)
   663  	}
   664  }
   665  
   666  func TestPanic(t *testing.T) {
   667  	var history []string
   668  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   669  		c := NewNamedChannel(ctx, "forever_blocked")
   670  		for i := 0; i < 10; i++ {
   671  			ii := i
   672  			GoNamed(ctx, fmt.Sprintf("c-%v", i), func(ctx Context) {
   673  				if ii == 9 {
   674  					panic("simulated failure")
   675  				}
   676  				c.Receive(ctx, nil) // blocked forever
   677  				history = append(history, fmt.Sprintf("child-%v", ii))
   678  			})
   679  		}
   680  		history = append(history, "root")
   681  		c.Receive(ctx, nil) // blocked forever
   682  	})
   683  	require.EqualValues(t, 0, len(history))
   684  	err := d.ExecuteUntilAllBlocked()
   685  	require.Error(t, err)
   686  	value := err.Error()
   687  	require.EqualValues(t, "simulated failure", value)
   688  	require.EqualValues(t, "simulated failure", err.Error())
   689  	panicError, ok := err.(*workflowPanicError)
   690  	require.True(t, ok)
   691  	require.Contains(t, panicError.StackTrace(), "cadence/internal.TestPanic")
   692  }
   693  
   694  func TestAwait(t *testing.T) {
   695  	flag := false
   696  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   697  		Await(ctx, func() bool { return flag })
   698  	})
   699  	err := d.ExecuteUntilAllBlocked()
   700  	require.NoError(t, err)
   701  	require.False(t, d.IsDone())
   702  	err = d.ExecuteUntilAllBlocked()
   703  	require.NoError(t, err)
   704  	require.False(t, d.IsDone())
   705  	flag = true
   706  	err = d.ExecuteUntilAllBlocked()
   707  	require.NoError(t, err)
   708  	require.True(t, d.IsDone())
   709  }
   710  
   711  func TestAwaitCancellation(t *testing.T) {
   712  	var awaitError error
   713  	ctx := createRootTestContext(t)
   714  	ctx, cancelHandler := WithCancel(ctx)
   715  	d, _ := newDispatcher(ctx, func(ctx Context) {
   716  		awaitError = Await(ctx, func() bool { return false })
   717  	})
   718  	err := d.ExecuteUntilAllBlocked()
   719  	require.NoError(t, err)
   720  	require.False(t, d.IsDone())
   721  	cancelHandler()
   722  	err = d.ExecuteUntilAllBlocked()
   723  	require.NoError(t, err)
   724  	require.True(t, d.IsDone())
   725  	require.Error(t, awaitError)
   726  	_, ok := awaitError.(*CanceledError)
   727  	require.True(t, ok)
   728  }
   729  
   730  func TestFutureSetValue(t *testing.T) {
   731  	var history []string
   732  	var f Future
   733  	var s Settable
   734  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   735  		f, s = NewFuture(ctx)
   736  		Go(ctx, func(ctx Context) {
   737  			history = append(history, "child-start")
   738  			require.False(t, f.IsReady())
   739  			var v string
   740  			err := f.Get(ctx, &v)
   741  			require.NoError(t, err)
   742  			require.True(t, f.IsReady())
   743  			history = append(history, fmt.Sprintf("future-get-%v", v))
   744  			// test second get of the ready future
   745  			err = f.Get(ctx, &v)
   746  			require.NoError(t, err)
   747  			require.True(t, f.IsReady())
   748  			history = append(history, fmt.Sprintf("child-end-%v", v))
   749  		})
   750  		history = append(history, "root-end")
   751  
   752  	})
   753  	require.EqualValues(t, 0, len(history))
   754  	require.NoError(t, d.ExecuteUntilAllBlocked())
   755  	require.False(t, d.IsDone(), fmt.Sprintf("%v", d.StackTrace()))
   756  	history = append(history, "future-set")
   757  	require.False(t, f.IsReady())
   758  	s.SetValue("value1")
   759  	require.True(t, f.IsReady())
   760  	require.NoError(t, d.ExecuteUntilAllBlocked())
   761  	require.True(t, d.IsDone())
   762  
   763  	expected := []string{
   764  		"root-end",
   765  		"child-start",
   766  		"future-set",
   767  		"future-get-value1",
   768  		"child-end-value1",
   769  	}
   770  	require.EqualValues(t, expected, history)
   771  
   772  }
   773  
   774  func TestFutureFail(t *testing.T) {
   775  	var history []string
   776  	var f Future
   777  	var s Settable
   778  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   779  		f, s = NewFuture(ctx)
   780  		Go(ctx, func(ctx Context) {
   781  			history = append(history, "child-start")
   782  			require.False(t, f.IsReady())
   783  			var v string
   784  			err := f.Get(ctx, &v)
   785  			require.Error(t, err)
   786  			require.True(t, f.IsReady())
   787  			history = append(history, fmt.Sprintf("future-get-%v", err))
   788  			// test second get of the ready future
   789  			err = f.Get(ctx, &v)
   790  			require.Error(t, err)
   791  			require.True(t, f.IsReady())
   792  			history = append(history, fmt.Sprintf("child-end-%v", err))
   793  		})
   794  		history = append(history, "root-end")
   795  
   796  	})
   797  	require.EqualValues(t, 0, len(history))
   798  	require.NoError(t, d.ExecuteUntilAllBlocked())
   799  	require.False(t, d.IsDone(), fmt.Sprintf("%v", d.StackTrace()))
   800  	history = append(history, "future-set")
   801  	require.False(t, f.IsReady())
   802  	s.SetError(errors.New("value1"))
   803  	assert.True(t, f.IsReady())
   804  	require.NoError(t, d.ExecuteUntilAllBlocked())
   805  	require.True(t, d.IsDone())
   806  
   807  	expected := []string{
   808  		"root-end",
   809  		"child-start",
   810  		"future-set",
   811  		"future-get-value1",
   812  		"child-end-value1",
   813  	}
   814  	require.EqualValues(t, expected, history)
   815  }
   816  
   817  func TestFutureSet(t *testing.T) {
   818  	var history []string
   819  	var f1, f2 Future
   820  	var s1, s2 Settable
   821  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   822  		f1, s1 = NewFuture(ctx)
   823  		f2, s2 = NewFuture(ctx)
   824  		Go(ctx, func(ctx Context) {
   825  			history = append(history, "child-start")
   826  			require.False(t, f1.IsReady())
   827  			var v string
   828  			err := f1.Get(ctx, &v)
   829  			require.Error(t, err)
   830  			require.NotNil(t, v)
   831  			require.True(t, f1.IsReady())
   832  			history = append(history, fmt.Sprintf("f1-get-%v-%v", v, err))
   833  			// test second get of the ready future
   834  			err = f1.Get(ctx, &v)
   835  			require.Error(t, err)
   836  			require.True(t, f1.IsReady())
   837  			history = append(history, fmt.Sprintf("f1-get2-%v-%v", v, err))
   838  
   839  			err = f2.Get(ctx, &v)
   840  			require.NoError(t, err)
   841  			require.True(t, f2.IsReady())
   842  			history = append(history, fmt.Sprintf("f2-get-%v-%v", v, err))
   843  
   844  			// test second get of the ready future
   845  			err = f2.Get(ctx, &v)
   846  			require.NoError(t, err)
   847  			require.True(t, f1.IsReady())
   848  			history = append(history, fmt.Sprintf("f2-get2-%v-%v", v, err))
   849  
   850  			history = append(history, fmt.Sprintf("child-end"))
   851  		})
   852  		history = append(history, "root-end")
   853  	})
   854  
   855  	require.EqualValues(t, 0, len(history))
   856  	require.NoError(t, d.ExecuteUntilAllBlocked())
   857  	require.False(t, d.IsDone(), fmt.Sprintf("%v", d.StackTrace()))
   858  	history = append(history, "f1-set")
   859  	require.False(t, f1.IsReady())
   860  	s1.Set("value-will-be-ignored", errors.New("error1"))
   861  	require.True(t, f1.IsReady())
   862  	require.NoError(t, d.ExecuteUntilAllBlocked())
   863  
   864  	require.False(t, d.IsDone(), fmt.Sprintf("%v", d.StackTrace()))
   865  	history = append(history, "f2-set")
   866  	require.False(t, f2.IsReady())
   867  	s2.Set("value2", nil)
   868  	require.True(t, f2.IsReady())
   869  	require.NoError(t, d.ExecuteUntilAllBlocked())
   870  	require.True(t, d.IsDone())
   871  
   872  	expected := []string{
   873  		"root-end",
   874  		"child-start",
   875  		"f1-set",
   876  		"f1-get--error1",
   877  		"f1-get2--error1",
   878  		"f2-set",
   879  		"f2-get-value2-<nil>",
   880  		"f2-get2-value2-<nil>",
   881  		"child-end",
   882  	}
   883  	require.EqualValues(t, expected, history)
   884  }
   885  
   886  func TestFutureChain(t *testing.T) {
   887  	var history []string
   888  	var f1, cf1, f2, cf2 Future
   889  	var s1, cs1, s2, cs2 Settable
   890  
   891  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   892  		f1, s1 = NewFuture(ctx)
   893  		cf1, cs1 = NewFuture(ctx)
   894  		s1.Chain(cf1)
   895  		f2, s2 = NewFuture(ctx)
   896  		cf2, cs2 = NewFuture(ctx)
   897  		s2.Chain(cf2)
   898  		Go(ctx, func(ctx Context) {
   899  			history = append(history, "child-start")
   900  			require.False(t, f1.IsReady())
   901  			var v string
   902  			err := f1.Get(ctx, &v)
   903  			require.Error(t, err)
   904  			require.True(t, f1.IsReady())
   905  			history = append(history, fmt.Sprintf("f1-get-%v-%v", v, err))
   906  			// test second get of the ready future
   907  			err = f1.Get(ctx, &v)
   908  			require.Error(t, err)
   909  			require.True(t, f1.IsReady())
   910  			history = append(history, fmt.Sprintf("f1-get2-%v-%v", v, err))
   911  
   912  			err = f2.Get(ctx, &v)
   913  			require.NoError(t, err)
   914  			require.Equal(t, "value2", v)
   915  			require.True(t, f2.IsReady())
   916  			history = append(history, fmt.Sprintf("f2-get-%v-%v", v, err))
   917  			// test second get of the ready future
   918  			err = f2.Get(ctx, &v)
   919  			require.NoError(t, err)
   920  			require.Equal(t, "value2", v)
   921  			require.True(t, f2.IsReady())
   922  			history = append(history, fmt.Sprintf("f2-get2-%v-%v", v, err))
   923  		})
   924  		history = append(history, "root-end")
   925  
   926  	})
   927  	require.EqualValues(t, 0, len(history))
   928  	require.NoError(t, d.ExecuteUntilAllBlocked())
   929  	require.False(t, d.IsDone(), fmt.Sprintf("%v", d.StackTrace()))
   930  	history = append(history, "f1-set")
   931  	require.False(t, f1.IsReady())
   932  	cs1.Set("value1-will-be-ignored", errors.New("error1"))
   933  	require.True(t, f1.IsReady())
   934  	require.NoError(t, d.ExecuteUntilAllBlocked())
   935  
   936  	require.False(t, d.IsDone(), fmt.Sprintf("%v", d.StackTrace()))
   937  	history = append(history, "f2-set")
   938  	require.False(t, f2.IsReady())
   939  	cs2.Set("value2", nil)
   940  	require.True(t, f2.IsReady())
   941  	require.NoError(t, d.ExecuteUntilAllBlocked())
   942  
   943  	require.True(t, d.IsDone())
   944  
   945  	expected := []string{
   946  		"root-end",
   947  		"child-start",
   948  		"f1-set",
   949  		"f1-get--error1",
   950  		"f1-get2--error1",
   951  		"f2-set",
   952  		"f2-get-value2-<nil>",
   953  		"f2-get2-value2-<nil>",
   954  	}
   955  	require.EqualValues(t, expected, history)
   956  }
   957  
   958  func TestSelectFuture(t *testing.T) {
   959  	var history []string
   960  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
   961  		future1, settable1 := NewFuture(ctx)
   962  		future2, settable2 := NewFuture(ctx)
   963  		Go(ctx, func(ctx Context) {
   964  			history = append(history, "add-one")
   965  			settable1.SetValue("one")
   966  		})
   967  		Go(ctx, func(ctx Context) {
   968  			history = append(history, "add-two")
   969  			settable2.SetValue("two")
   970  		})
   971  
   972  		s := NewSelector(ctx)
   973  		s.
   974  			AddFuture(future1, func(f Future) {
   975  				var v string
   976  				err := f.Get(ctx, &v)
   977  				require.NoError(t, err)
   978  				history = append(history, fmt.Sprintf("c1-%v", v))
   979  			}).
   980  			AddFuture(future2, func(f Future) {
   981  				var v string
   982  				err := f.Get(ctx, &v)
   983  				require.NoError(t, err)
   984  				history = append(history, fmt.Sprintf("c2-%v", v))
   985  			})
   986  		history = append(history, "select1")
   987  		s.Select(ctx)
   988  		history = append(history, "select2")
   989  		s.Select(ctx)
   990  		history = append(history, "done")
   991  	})
   992  	require.NoError(t, d.ExecuteUntilAllBlocked())
   993  	require.True(t, d.IsDone())
   994  
   995  	expected := []string{
   996  		"select1",
   997  		"add-one",
   998  		"add-two",
   999  		"c1-one",
  1000  		"select2",
  1001  		"c2-two",
  1002  		"done",
  1003  	}
  1004  	require.EqualValues(t, expected, history)
  1005  }
  1006  
  1007  func TestSelectDecodeFuture(t *testing.T) {
  1008  	var history []string
  1009  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
  1010  		future1, settable1 := newDecodeFuture(ctx, "testFn1")
  1011  		future2, settable2 := newDecodeFuture(ctx, "testFn2")
  1012  		Go(ctx, func(ctx Context) {
  1013  			history = append(history, "add-one")
  1014  			settable1.SetValue([]byte("one"))
  1015  		})
  1016  		Go(ctx, func(ctx Context) {
  1017  			history = append(history, "add-two")
  1018  			settable2.SetValue([]byte("two"))
  1019  		})
  1020  
  1021  		s := NewSelector(ctx)
  1022  		s.
  1023  			AddFuture(future1, func(f Future) {
  1024  				var v []byte
  1025  				err := f.Get(ctx, &v)
  1026  				require.NoError(t, err)
  1027  				history = append(history, fmt.Sprintf("c1-%s", v))
  1028  			}).
  1029  			AddFuture(future2, func(f Future) {
  1030  				var v []byte
  1031  				err := f.Get(ctx, &v)
  1032  				require.NoError(t, err)
  1033  				history = append(history, fmt.Sprintf("c2-%s", v))
  1034  			})
  1035  		history = append(history, "select1")
  1036  		s.Select(ctx)
  1037  		history = append(history, "select2")
  1038  		s.Select(ctx)
  1039  		history = append(history, "done")
  1040  	})
  1041  	require.NoError(t, d.ExecuteUntilAllBlocked())
  1042  	require.True(t, d.IsDone())
  1043  
  1044  	expected := []string{
  1045  		"select1",
  1046  		"add-one",
  1047  		"add-two",
  1048  		"c1-one",
  1049  		"select2",
  1050  		"c2-two",
  1051  		"done",
  1052  	}
  1053  	require.EqualValues(t, expected, history)
  1054  }
  1055  
  1056  func TestDecodeFutureChain(t *testing.T) {
  1057  	var history []string
  1058  	var f1, cf1, f2, cf2 Future
  1059  	var s1, cs1, s2, cs2 Settable
  1060  
  1061  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
  1062  		f1, s1 = newDecodeFuture(ctx, "testFn")
  1063  		cf1, cs1 = newDecodeFuture(ctx, "testFun")
  1064  		f2, s2 = newDecodeFuture(ctx, "testFn")
  1065  		cf2, cs2 = newDecodeFuture(ctx, "testFun")
  1066  		s1.Chain(cf1)
  1067  		s2.Chain(cf2)
  1068  		Go(ctx, func(ctx Context) {
  1069  			history = append(history, "child-start")
  1070  			require.False(t, f1.IsReady())
  1071  			var v []byte
  1072  			err := f1.Get(ctx, &v)
  1073  			require.Error(t, err)
  1074  			require.Nil(t, v)
  1075  			require.True(t, f1.IsReady())
  1076  			history = append(history, fmt.Sprintf("f1-get-%s-%v", v, err))
  1077  			// test second get of the ready future
  1078  			err = f1.Get(ctx, &v)
  1079  			require.Error(t, err)
  1080  			require.Nil(t, v)
  1081  			require.True(t, f1.IsReady())
  1082  			history = append(history, fmt.Sprintf("f1-get2-%s-%v", v, err))
  1083  
  1084  			// for f2
  1085  			err = f2.Get(ctx, &v)
  1086  			require.NoError(t, err)
  1087  			require.NotNil(t, v)
  1088  			require.True(t, f1.IsReady())
  1089  			history = append(history, fmt.Sprintf("f2-get-%s-%v", v, err))
  1090  			// test second get of the ready future
  1091  			err = f2.Get(ctx, &v)
  1092  			require.NoError(t, err)
  1093  			require.NotNil(t, v)
  1094  			require.True(t, f2.IsReady())
  1095  			history = append(history, fmt.Sprintf("f2-get2-%s-%v", v, err))
  1096  		})
  1097  		history = append(history, "root-end")
  1098  	})
  1099  	require.EqualValues(t, 0, len(history))
  1100  	require.NoError(t, d.ExecuteUntilAllBlocked())
  1101  	// set f1
  1102  	require.False(t, d.IsDone(), fmt.Sprintf("%v", d.StackTrace()))
  1103  	history = append(history, "f1-set")
  1104  	require.False(t, f1.IsReady())
  1105  	cs1.Set([]byte("value-will-be-ignored"), errors.New("error1"))
  1106  	require.True(t, f1.IsReady())
  1107  	require.NoError(t, d.ExecuteUntilAllBlocked())
  1108  
  1109  	// set f2
  1110  	require.False(t, d.IsDone(), fmt.Sprintf("%v", d.StackTrace()))
  1111  	history = append(history, "f2-set")
  1112  	require.False(t, f2.IsReady())
  1113  	cs2.Set([]byte("value2"), nil)
  1114  	require.True(t, f2.IsReady())
  1115  	require.NoError(t, d.ExecuteUntilAllBlocked())
  1116  
  1117  	require.True(t, d.IsDone())
  1118  
  1119  	expected := []string{
  1120  		"root-end",
  1121  		"child-start",
  1122  		"f1-set",
  1123  		"f1-get--error1",
  1124  		"f1-get2--error1",
  1125  		"f2-set",
  1126  		"f2-get-value2-<nil>",
  1127  		"f2-get2-value2-<nil>",
  1128  	}
  1129  	require.EqualValues(t, expected, history)
  1130  }
  1131  
  1132  func TestSelectFuture_WithBatchSets(t *testing.T) {
  1133  	var history []string
  1134  	d, _ := newDispatcher(createRootTestContext(t), func(ctx Context) {
  1135  		future1, settable1 := NewFuture(ctx)
  1136  		future2, settable2 := NewFuture(ctx)
  1137  		future3, settable3 := NewFuture(ctx)
  1138  
  1139  		s := NewSelector(ctx)
  1140  		s.
  1141  			AddFuture(future1, func(f Future) {
  1142  				var v string
  1143  				err := f.Get(ctx, &v)
  1144  				require.NoError(t, err)
  1145  				history = append(history, fmt.Sprintf("c1-%v", v))
  1146  			}).
  1147  			AddFuture(future2, func(f Future) {
  1148  				var v string
  1149  				err := f.Get(ctx, &v)
  1150  				require.NoError(t, err)
  1151  				history = append(history, fmt.Sprintf("c2-%v", v))
  1152  			}).
  1153  			AddFuture(future3, func(f Future) {
  1154  				var v string
  1155  				err := f.Get(ctx, &v)
  1156  				require.NoError(t, err)
  1157  				history = append(history, fmt.Sprintf("c3-%v", v))
  1158  			})
  1159  
  1160  		settable2.Set("two", nil)
  1161  		s.Select(ctx)
  1162  		settable3.Set("three", nil)
  1163  		settable1.Set("one", nil)
  1164  		s.Select(ctx)
  1165  		s.Select(ctx)
  1166  	})
  1167  	require.NoError(t, d.ExecuteUntilAllBlocked())
  1168  	require.True(t, d.IsDone())
  1169  
  1170  	expected := []string{
  1171  		"c2-two",
  1172  		"c1-one",
  1173  		"c3-three",
  1174  	}
  1175  	require.EqualValues(t, expected, history)
  1176  }
  1177  
  1178  func TestChainedFuture(t *testing.T) {
  1179  	activityFn := func(arg int) (int, error) {
  1180  		return arg, nil
  1181  	}
  1182  	workflowFn := func(ctx Context) (int, error) {
  1183  		ctx = WithActivityOptions(ctx, ActivityOptions{
  1184  			ScheduleToStartTimeout: time.Minute,
  1185  			StartToCloseTimeout:    time.Minute,
  1186  		})
  1187  		f := ExecuteActivity(ctx, activityFn, 5)
  1188  		var out int
  1189  		fut, set := NewFuture(ctx)
  1190  		set.Chain(f)
  1191  		require.NoError(t, fut.Get(ctx, &out))
  1192  		return out, nil
  1193  	}
  1194  
  1195  	env := newTestWorkflowEnv(t)
  1196  	env.RegisterWorkflow(workflowFn)
  1197  	env.RegisterActivity(activityFn)
  1198  
  1199  	env.ExecuteWorkflow(workflowFn)
  1200  	err := env.GetWorkflowError()
  1201  	require.NoError(t, err)
  1202  	var out int
  1203  	require.NoError(t, env.GetWorkflowResult(&out))
  1204  	require.Equal(t, 5, out)
  1205  }