Skip to content

Commit

Permalink
Create e2e suite and replay test (#171)
Browse files Browse the repository at this point in the history
* Create e2e suite and replay test

* .
  • Loading branch information
feedmeapples committed Apr 4, 2023
1 parent d7f2c05 commit 00532ad
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 0 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ require (
github.com/urfave/cli/v2 v2.23.6
go.temporal.io/api v1.18.2-0.20230324225508-f2c7ab685b44
go.temporal.io/sdk v1.21.1
go.temporal.io/sdk/contrib/tools/workflowcheck v0.0.0-20230328164709-88a40de39c33
go.temporal.io/server v1.20.1
go.uber.org/zap v1.24.0
golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,8 @@ go.temporal.io/api v1.18.2-0.20230324225508-f2c7ab685b44 h1:ilEY3HPpO6UwiwopVMuX
go.temporal.io/api v1.18.2-0.20230324225508-f2c7ab685b44/go.mod h1:VAc6LF2ckIwAbMEMv+eo+3yw4SjIzwosukjiwXajCJc=
go.temporal.io/sdk v1.21.1 h1:SJCzSsZLBsFiHniJ+E7Yy74pcAs1lg7NbFnsUJ4ggIM=
go.temporal.io/sdk v1.21.1/go.mod h1:Pq3Mp7p0lWNFM+YS2guBy8V/lJySh329AcyS+Wj/Wmo=
go.temporal.io/sdk/contrib/tools/workflowcheck v0.0.0-20230328164709-88a40de39c33 h1:tpDvC3HKzoPGmYZT7LBkYtBWrbZa8GNiLR2LG5iG5sw=
go.temporal.io/sdk/contrib/tools/workflowcheck v0.0.0-20230328164709-88a40de39c33/go.mod h1:CW0zVy7oLeWxBo3wG5bMU2dy4xaprM2net3/DkBzruw=
go.temporal.io/server v1.20.1 h1:vhI7XLQJP0TbYWIJTHzliCaYrekxY3XUhtg0MUSxaXs=
go.temporal.io/server v1.20.1/go.mod h1:0XqeAbOIa+6J1qvne7yEbXKfchw3sIkCaQ16Qo6ZeiU=
go.temporal.io/version v0.3.0 h1:dMrei9l9NyHt8nG6EB8vAwDLLTwx2SvRyucCSumAiig=
Expand Down
116 changes: 116 additions & 0 deletions tests/e2e_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package tests

import (
"bytes"
"context"
"fmt"
"strings"
"testing"

"github.com/stretchr/testify/suite"
"github.com/temporalio/cli/app"
"github.com/urfave/cli/v2"
"go.temporal.io/api/operatorservice/v1"
"go.temporal.io/api/workflowservice/v1"
"go.temporal.io/sdk/client"
"go.temporal.io/sdk/testsuite"
"go.temporal.io/sdk/worker"
healthpb "google.golang.org/grpc/health/grpc_health_v1"
)

type (
e2eSuite struct {
suite.Suite
app *cli.App
ts *testsuite.DevServer
workers []worker.Worker
defaultWorkerOptions worker.Options
writer *MemWriter
}
)

func TestClientIntegrationSuite(t *testing.T) {
suite.Run(t, new(e2eSuite))
}

func (s *e2eSuite) SetupSuite() {
s.app = app.BuildApp()
server, err := testsuite.StartDevServer(context.Background(), testsuite.DevServerOptions{})
s.NoError(err)
s.ts = server
}

func (s *e2eSuite) TearDownSuite() {
}

func (s *e2eSuite) SetupTest() {
app.SetFactory(&clientFactory{
frontendClient: nil,
operatorClient: nil,
sdkClient: s.ts.Client(),
})
s.writer = &MemWriter{}
s.app.Writer = s.writer
}

func (s *e2eSuite) TearDownTest() {
s.ts.Stop()
}

func (s *e2eSuite) NewWorker(taskQueue string, registerFunc func(registry worker.Registry)) worker.Worker {
w := worker.New(s.ts.Client(), taskQueue, s.defaultWorkerOptions)
registerFunc(w)
s.workers = append(s.workers, w)

err := w.Start()
s.NoError(err)

return w
}

type clientFactory struct {
frontendClient workflowservice.WorkflowServiceClient
operatorClient operatorservice.OperatorServiceClient
sdkClient client.Client
}

func (m *clientFactory) FrontendClient(c *cli.Context) workflowservice.WorkflowServiceClient {
return m.frontendClient
}

func (m *clientFactory) OperatorClient(c *cli.Context) operatorservice.OperatorServiceClient {
return m.operatorClient
}

func (m *clientFactory) SDKClient(c *cli.Context, namespace string) client.Client {
return m.sdkClient
}

func (m *clientFactory) HealthClient(_ *cli.Context) healthpb.HealthClient {
panic("HealthClient mock is not supported")
}

// MemWriter is an io.Writer implementation that stores the written content.
type MemWriter struct {
content bytes.Buffer
}

func (tlw *MemWriter) Write(p []byte) (n int, err error) {
return tlw.content.Write(p)
}

func (tlw *MemWriter) GetContent() string {
return tlw.content.String()
}

func TestMemWriter(t *testing.T) {
tlw := &MemWriter{}
fmt.Fprintln(tlw, "This message is written to the TestLogWriter.")

content := tlw.GetContent()
expected := "This message is written to the TestLogWriter."

if !strings.Contains(content, expected) {
t.Errorf("Expected log content to contain '%s', but it doesn't. Content: '%s'", expected, content)
}
}
53 changes: 53 additions & 0 deletions tests/workflow_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package tests

import (
"context"
"io/ioutil"
"os"

"github.com/pborman/uuid"
"github.com/temporalio/cli/tests/workflows/helloworld"
"go.temporal.io/sdk/client"
"go.temporal.io/sdk/worker"
)

const (
testTq = "test-queue"
)

func (s *e2eSuite) TestWorkflowShow_ReplayableHistory() {
c := s.ts.Client()

s.NewWorker(testTq, func(r worker.Registry) {
r.RegisterWorkflow(helloworld.Workflow)
r.RegisterActivity(helloworld.Activity)
})

wfr, err := c.ExecuteWorkflow(
context.Background(),
client.StartWorkflowOptions{TaskQueue: testTq},
helloworld.Workflow,
"world",
)
s.NoError(err)

var result string
err = wfr.Get(context.Background(), &result)
s.NoError(err)

// show history
err = s.app.Run([]string{"", "workflow", "show", "--workflow-id", wfr.GetID(), "--run-id", wfr.GetRunID(), "--output", "json"})
s.NoError(err)

// save history to file
historyFile := uuid.New() + ".json"
logs := s.writer.GetContent()
err = ioutil.WriteFile(historyFile, []byte(logs), 0644)
s.NoError(err)
defer os.Remove(historyFile)

replayer := worker.NewWorkflowReplayer()
replayer.RegisterWorkflow(helloworld.Workflow)
err = replayer.ReplayWorkflowHistoryFromJSONFile(nil, historyFile)
s.NoError(err)
}
40 changes: 40 additions & 0 deletions tests/workflows/helloworld/helloworld.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package helloworld

import (
"context"
"time"

"go.temporal.io/sdk/activity"
"go.temporal.io/sdk/workflow"

// TODO(cretz): Remove when tagged
_ "go.temporal.io/sdk/contrib/tools/workflowcheck/determinism"
)

// Workflow is a Hello World workflow definition.
func Workflow(ctx workflow.Context, name string) (string, error) {
ao := workflow.ActivityOptions{
StartToCloseTimeout: 10 * time.Second,
}
ctx = workflow.WithActivityOptions(ctx, ao)

logger := workflow.GetLogger(ctx)
logger.Info("HelloWorld workflow started", "name", name)

var result string
err := workflow.ExecuteActivity(ctx, Activity, name).Get(ctx, &result)
if err != nil {
logger.Error("Activity failed.", "Error", err)
return "", err
}

logger.Info("HelloWorld workflow completed.", "result", result)

return result, nil
}

func Activity(ctx context.Context, name string) (string, error) {
logger := activity.GetLogger(ctx)
logger.Info("Activity", "name", name)
return "Hello " + name + "!", nil
}

0 comments on commit 00532ad

Please sign in to comment.