diff --git a/bin/test.sh b/bin/test.sh index 3a21aa0..aa75cb0 100755 --- a/bin/test.sh +++ b/bin/test.sh @@ -1,14 +1,16 @@ #!/bin/bash -set -e - export GOEXPERIMENT=nocoverageredesign go install github.com/jstemmer/go-junit-report/v2@latest list=`go list ./... | grep -v mocks | grep -v docs | grep -v errors | grep -v examples` -go test -v -coverpkg=./... -race -covermode=atomic -coverprofile=coverage.out 2>&1 $list | go-junit-report -set-exit-code > junit.xml +go test -v -coverpkg=./... -race -covermode=atomic -coverprofile=coverage.out 2>&1 $list > test.log + +cat test.log + +cat test.log | go-junit-report -set-exit-code > junit.xml coverage=$(go tool cover -func coverage.out | grep total | awk '{print $3}') diff --git a/messaging/natsjs/argo-event.go b/messaging/natsjs/argo-event.go deleted file mode 100644 index 922f32c..0000000 --- a/messaging/natsjs/argo-event.go +++ /dev/null @@ -1,73 +0,0 @@ -package natsjs - -import ( - "encoding/base64" - "encoding/json" - - "github.com/simiancreative/simiango/errors" -) - -func ArgoEventFromString(str string) (ArgoEvent, error) { - var e ArgoEvent - err := json.Unmarshal([]byte(str), &e) - return e, err -} - -func ArgoUnmarshalEvent(dest interface{}, str string) (err error) { - newEvent, err := ArgoEventFromString(str) - if err != nil { - return errors.Wrap(err, "failed to unmarshal event") - } - - str, err = newEvent.JSONBody() - if err != nil { - return errors.Wrap(err, "failed to extract JSON body") - } - - err = json.Unmarshal([]byte(str), &dest) - if err != nil { - return errors.Wrap(err, "failed to unmarshal event") - } - - return nil -} - -// EventContext represents the context of an event -type ArgoEventContext struct { - ID string `json:"id"` - Source string `json:"source"` - SpecVersion string `json:"specversion"` - Type string `json:"type"` - DataContentType string `json:"datacontenttype"` - Subject string `json:"subject"` - Time string `json:"time"` -} - -// Event represents an event received from an argo event source -type ArgoEvent struct { - Context ArgoEventContext `json:"context"` - Data string `json:"data"` -} - -type ArgoEventData struct { - Subject string `json:"subject"` - Body interface{} `json:"body"` -} - -func (e ArgoEvent) JSONBody() (string, error) { - var data ArgoEventData - - bytes, err := base64.StdEncoding.DecodeString(e.Data) - if err != nil { - return "", err - } - - err = json.Unmarshal(bytes, &data) - if err != nil { - return "", err - } - - bytes, err = json.Marshal(data.Body) - - return string(bytes), err -} diff --git a/messaging/natsjs/argo-event_test.go b/messaging/natsjs/argo-event_test.go deleted file mode 100644 index 7611258..0000000 --- a/messaging/natsjs/argo-event_test.go +++ /dev/null @@ -1,182 +0,0 @@ -package natsjs_test - -import ( - "encoding/base64" - "encoding/json" - "testing" - - "github.com/simiancreative/simiango/messaging/natsjs" - "github.com/stretchr/testify/assert" -) - -func TestArgoEventFromString(t *testing.T) { - testEvent := natsjs.ArgoEvent{ - Context: natsjs.ArgoEventContext{ - ID: "testID", - Source: "testSource", - SpecVersion: "testSpecVersion", - Type: "testType", - DataContentType: "testDataContentType", - Subject: "testSubject", - Time: "testTime", - }, - Data: "testData", - } - - bytes, _ := json.Marshal(testEvent) - str := string(bytes) - - event, err := natsjs.ArgoEventFromString(str) - - assert.NoError(t, err) - assert.Equal(t, testEvent.Context.ID, event.Context.ID) - - // Test with invalid JSON - _, err = natsjs.ArgoEventFromString("{invalid json}") - assert.Error(t, err) -} - -func TestJSONBody(t *testing.T) { - testData := natsjs.ArgoEventData{ - Subject: "testSubject", - Body: "testBody", - } - - bytes, _ := json.Marshal(testData) - str := base64.StdEncoding.EncodeToString(bytes) - - testEvent := natsjs.ArgoEvent{ - Context: natsjs.ArgoEventContext{ - ID: "testID", - Source: "testSource", - SpecVersion: "testSpecVersion", - Type: "testType", - DataContentType: "testDataContentType", - Subject: "testSubject", - Time: "testTime", - }, - Data: str, - } - - body, err := testEvent.JSONBody() - - assert.NoError(t, err) - assert.Equal(t, `"testBody"`, body) - - // Test with invalid base64 data - testEvent.Data = "invalid base64" - - _, err = testEvent.JSONBody() - assert.Error(t, err) -} - -func TestBadJSONBody(t *testing.T) { - str := base64.StdEncoding.EncodeToString([]byte("invalidJSON")) - - testEvent := natsjs.ArgoEvent{ - Context: natsjs.ArgoEventContext{ - ID: "testID", - Source: "testSource", - SpecVersion: "testSpecVersion", - Type: "testType", - DataContentType: "testDataContentType", - Subject: "testSubject", - Time: "testTime", - }, - Data: str, - } - - body, err := testEvent.JSONBody() - assert.Error(t, err) - assert.Equal(t, "", body) -} - -func TestArgoUnmarshalEvent(t *testing.T) { - // Sample JSON string representing an ArgoEvent - sampleJSON := `{ - "context": { - "id": "1234", - "source": "source", - "specversion": "1.0", - "type": "type", - "datacontenttype": "application/json", - "subject": "subject", - "time": "2023-10-01T00:00:00Z" - }, - "data": "eyJzdWJqZWN0IjoiZXhhbXBsZSIsImJvZHkiOnsia2V5IjoidmFsdWUifX0=" - }` - - // Destination variable - var dest map[string]interface{} - - // Call the function - err := natsjs.ArgoUnmarshalEvent(&dest, sampleJSON) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - - // Verify the results - expectedBody := map[string]interface{}{"key": "value"} - if dest["key"] != expectedBody["key"] { - t.Errorf("Expected body %v, got %v", expectedBody, dest) - } -} - -func TestArgoUnmarshalEvent_Errors(t *testing.T) { - // Test case 1: Invalid JSON string - invalidJSON := `{"context": { "id": "1234" "source": "source" }}` // Missing comma - var dest1 map[string]interface{} - err := natsjs.ArgoUnmarshalEvent(&dest1, invalidJSON) - assert.Error(t, err) - - // Test case 2: Invalid base64 data - invalidBase64 := `{ - "context": { - "id": "1234", - "source": "source", - "specversion": "1.0", - "type": "type", - "datacontenttype": "application/json", - "subject": "subject", - "time": "2023-10-01T00:00:00Z" - }, - "data": "invalid_base64_data" - }` - var dest2 map[string]interface{} - err = natsjs.ArgoUnmarshalEvent(&dest2, invalidBase64) - assert.Error(t, err) - - // test case 3: invalid json body - invalidjsonbody := `{ - "context": { - "id": "1234", - "source": "source", - "specversion": "1.0", - "type": "type", - "datacontenttype": "application/json", - "subject": "subject", - "time": "2023-10-01t00:00:00z" - }, - "data": "W30K" // {"subject":"example","body":{"foo":"bar"}} - }` - var dest3 map[string]interface{} - err = natsjs.ArgoUnmarshalEvent(&dest3, invalidjsonbody) - assert.Error(t, err) - - // test case 3: invalid json body - invalidjsonMessage := `{ - "context": { - "id": "1234", - "source": "source", - "specversion": "1.0", - "type": "type", - "datacontenttype": "application/json", - "subject": "subject", - "time": "2023-10-01t00:00:00z" - }, - "data": "eyJzdWJqZWN0IjoiZXhhbXBsZSIsImJvZHkiOiJ7XSJ9Cg==" - }` - var dest4 map[string]interface{} - err = natsjs.ArgoUnmarshalEvent(&dest4, invalidjsonMessage) - assert.Error(t, err) -} diff --git a/messaging/natsjs/client.go b/messaging/natsjs/client.go deleted file mode 100644 index d0f83b7..0000000 --- a/messaging/natsjs/client.go +++ /dev/null @@ -1,33 +0,0 @@ -package natsjs - -import ( - "context" - "time" - - "github.com/nats-io/nats.go/jetstream" -) - -type Client struct{} - -func (c *Client) InitStream(streamName string) *Client { - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - - if connection == nil { - panic("Connection is not established") - } - - _, err := connection.js.CreateOrUpdateStream(ctx, jetstream.StreamConfig{ - Name: streamName, - Subjects: []string{streamName + ".>"}, - }) - if err != nil { - panic(err) - } - - return c -} - -func (c *Client) NewMessage() *Message { - return &Message{} -} diff --git a/messaging/natsjs/consumer.go b/messaging/natsjs/consumer.go deleted file mode 100644 index 57f7178..0000000 --- a/messaging/natsjs/consumer.go +++ /dev/null @@ -1,127 +0,0 @@ -package natsjs - -import ( - "context" - - "github.com/nats-io/nats.go/jetstream" - "github.com/simiancreative/simiango/errors" - "github.com/simiancreative/simiango/logger" -) - -func NewConsumer(name, stream, subject string) *Consumer { - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - - if connection == nil { - panic("Connection is not established") - } - - // retrieve consumer handle from a stream - cons, err := connection.js.CreateOrUpdateConsumer( - ctx, stream, jetstream.ConsumerConfig{ - FilterSubject: subject, - Durable: name, - Name: name, - }, - ) - if err != nil { - panic(err) - } - - return &Consumer{cons: cons} -} - -type Consumer struct { - cons jetstream.Consumer - // batchSize int -} - -// func (c *Consumer) BatchConfiguration(size int) *Consumer { -// c.batchSize = size -// -// return c -// } - -func (c Consumer) Consume(callback func(jetstream.Msg) error) (stop func(), err error) { - cc, err := c.cons.Consume(func(msg jetstream.Msg) { - err := callback(msg) - - if err != nil { - logger.Errorf("Error consuming message: %#v", errors.Unwrap(err)) - } - - logger.Warnf("Acking message: %s", msg.Data()) - msg.Ack() - }) - - stop = func() { - logger.Debugf("Stopping consumer") - cc.Stop() - } - - return stop, err -} - -// Some thinking to do before we implement a batch consumer. - -// The nats side is relatively easy. We need to decide how we want to handle the -// application logic and how we ack messages. - -// Do we want to ack messages in the callback or after the callback has been executed? -// -// 1. If we ack messages after the callback we need to make sure that the callback is -// idempotent on a per message basis. -// -// 2. If we ack messages inside the callback we need to make sure that the messages -// can be acked out of order in the case where some messages are acked but not -// others. - -// func (c Consumer) BatchConsume(callback func([]string) error) (stop func(), err error) { -// var shouldStop bool -// -// go func() { -// for { -// if shouldStop { -// break -// } -// -// batch, err := c.cons.Fetch(c.batchSize) -// if err != nil { -// log.Printf("Error fetching messages: %v", err) -// continue -// } -// -// msgs, data := collectMessages(batch) -// -// if len(msgs) == 0 { -// continue -// } -// -// err = callback(data) -// if err != nil { -// logger.Errorf("Error consuming message: %v", err) -// continue -// } -// -// for _, msg := range msgs { -// msg.Ack() -// } -// } -// }() -// -// stop = func() { -// logger.Debugf("Stopping consumer") -// shouldStop = true -// } -// -// return stop, err -// } -// -// func collectMessages(batch jetstream.MessageBatch) (msgs []jetstream.Msg, data []string) { -// for msg := range batch.Messages() { -// data = append(data, string(msg.Data())) -// msgs = append(msgs, msg) -// } -// -// return -// } diff --git a/messaging/natsjs/consumer_test.go b/messaging/natsjs/consumer_test.go deleted file mode 100644 index 9fffc59..0000000 --- a/messaging/natsjs/consumer_test.go +++ /dev/null @@ -1,131 +0,0 @@ -package natsjs_test - -import ( - "testing" - "time" - - "github.com/nats-io/nats.go/jetstream" - "github.com/simiancreative/simiango/errors" - "github.com/simiancreative/simiango/logger" - "github.com/simiancreative/simiango/messaging/natsjs" - "github.com/simiancreative/simiango/mocks/nats" - "github.com/stretchr/testify/assert" -) - -func testNewConsumer(t *testing.T) { - defer nats.MockServer()() - - assert.NotPanics(t, func() { - natsjs.SetTimeout(30) - natsjs.Connect() - - consumer := natsjs.NewConsumer("test", "test", "test") - assert.NotNil(t, consumer) - }) -} - -func testNewConsumerFailure(t *testing.T) { - assert.Panics(t, func() { - natsjs.SetTimeout(1) - natsjs.NewConsumer("test", "test", "test") - }) -} - -func testNewConsumerStop(t *testing.T) { - logger.Enable() - defer nats.MockServer()() - - natsjs.SetTimeout(30) - natsjs.Connect() - - stop, err := natsjs. - NewConsumer("test", "test", "test.>"). - Consume(func(_ jetstream.Msg) error { - return nil - }) - - assert.NoError(t, err) - assert.NotNil(t, stop) - assert.NotPanics(t, stop) -} - -func testNewConsumerConsume(t *testing.T) { - logger.Enable() - defer nats.MockServer()() - - result := make(chan string) - - natsjs.SetTimeout(30) - natsjs.Connect() - - stop, err := natsjs. - NewConsumer("test", "test", "test.>"). - Consume(func(msg jetstream.Msg) error { - logger.Debugf("Received message: %v", msg) - result <- string(msg.Data()) - return nil - }) - - assert.NoError(t, err) - assert.NotNil(t, stop) - - natsjs.New(). - NewMessage(). - SetSubject("test", "test.test"). - SetData("test data"). - Publish() - - select { - case value := <-result: - assert.Equal(t, value, `"test data"`) - case <-time.After(500 * time.Millisecond): - t.Errorf("Timeout waiting for async result") - } -} - -func testNewConsumerConsumeFailure(t *testing.T) { - hook := logger.Mock() - defer nats.MockServer()() - - natsjs.SetTimeout(30) - natsjs.Connect() - - result := make(chan string) - - callback := func(msg jetstream.Msg) error { - result <- string(msg.Data()) - return errors.New("test error") - } - - natsjs. - NewConsumer("test", "test", "test.>"). - Consume(callback) - - natsjs.New(). - NewMessage(). - SetSubject("test", "test.test"). - SetData("test data"). - Publish() - - select { - case <-result: - time.Sleep(100 * time.Millisecond) - case <-time.After(500 * time.Millisecond): - t.Errorf("Timeout waiting for async result") - } - - assert.Equal(t, `Acking message: "test data"`, hook.LastEntry().Message) -} - -func testNewConsumerNoConnection(t *testing.T) { - natsjs.Close() - - assert.Panics(t, func() { - natsjs. - NewConsumer("test", "test", "test.>"). - Consume(func(msg jetstream.Msg) error { - logger.Debugf("Received message: %v", msg) - return errors.New("test error") - }) - }) -} diff --git a/messaging/natsjs/event.go b/messaging/natsjs/event.go deleted file mode 100644 index 932a935..0000000 --- a/messaging/natsjs/event.go +++ /dev/null @@ -1,16 +0,0 @@ -package natsjs - -import ( - "encoding/json" - - "github.com/simiancreative/simiango/errors" -) - -func UnmarshalEvent(dest interface{}, str string) (err error) { - err = json.Unmarshal([]byte(str), &dest) - if err != nil { - return errors.Wrap(err, "failed to unmarshal event") - } - - return nil -} diff --git a/messaging/natsjs/event_test.go b/messaging/natsjs/event_test.go deleted file mode 100644 index 2c76fa1..0000000 --- a/messaging/natsjs/event_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package natsjs_test - -import ( - "testing" - - "github.com/simiancreative/simiango/messaging/natsjs" -) - -type TestEvent struct { - Name string `json:"name"` -} - -func TestUnmarshalEvent(t *testing.T) { - tests := []struct { - name string - input string - wantErr bool - wantEvent TestEvent - }{ - { - name: "valid JSON", - input: `{"name": "test event"}`, - wantErr: false, - wantEvent: TestEvent{Name: "test event"}, - }, - { - name: "invalid JSON", - input: `{"name": "test event"`, - wantErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - var event TestEvent - err := natsjs.UnmarshalEvent(&event, tt.input) - if (err != nil) != tt.wantErr { - t.Errorf("UnmarshalEvent() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !tt.wantErr && event != tt.wantEvent { - t.Errorf("UnmarshalEvent() = %v, want %v", event, tt.wantEvent) - } - }) - } -} diff --git a/messaging/natsjs/message.go b/messaging/natsjs/message.go deleted file mode 100644 index 8151e4f..0000000 --- a/messaging/natsjs/message.go +++ /dev/null @@ -1,52 +0,0 @@ -package natsjs - -import ( - "context" - "encoding/json" - "strings" -) - -type Message struct { - Subject string - Data []byte -} - -// SetSubject sets the subject of the message. The subject is used to route the -// message to the correct stream. -// -// even though stream name is not required to relate a message to a stream, it -// forces our naming convention and makes it easier to find the stream that the -// message belongs to -func (m *Message) SetSubject(streamName, prefix string, suffix ...string) *Message { - suffix = append([]string{streamName, prefix}, suffix...) - m.Subject = strings.ToLower(strings.Join(suffix, ".")) - - return m -} - -func (m *Message) SetData(raw interface{}) *Message { - data, err := json.Marshal(raw) - if err != nil { - panic(err) - } - - m.Data = data - - return m -} - -func (m *Message) Publish() error { - if connection == nil { - panic("Connection is not established") - } - - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - - _, err := connection.js.Publish(ctx, m.Subject, m.Data) - if err != nil { - return err - } - - return nil -} diff --git a/messaging/natsjs/message_test.go b/messaging/natsjs/message_test.go deleted file mode 100644 index cbb1cba..0000000 --- a/messaging/natsjs/message_test.go +++ /dev/null @@ -1,95 +0,0 @@ -package natsjs_test - -import ( - "encoding/json" - "testing" - - "github.com/simiancreative/simiango/messaging/natsjs" - "github.com/simiancreative/simiango/mocks/nats" - "github.com/stretchr/testify/assert" -) - -func testMessageSetSubject(t *testing.T) { - msg := &natsjs.Message{} - msg.SetSubject("prefix", "suffix") - assert.Equal(t, "prefix.suffix", msg.Subject) -} - -func testMessageSetData(t *testing.T) { - msg := &natsjs.Message{} - data := map[string]string{"key": "value"} - msg.SetData(data) - - expectedData, _ := json.Marshal(data) - assert.Equal(t, expectedData, msg.Data) -} - -func testMessageSetDataError(t *testing.T) { - assert.Panics( - t, - func() { - msg := &natsjs.Message{} - data := make(chan int) - msg.SetData(data) - }, - "SetData should panic if data is not serializable", - ) -} - -func testMessagePublish(t *testing.T) { - defer nats.MockServer()() - natsjs.Connect() - natsjs.SetTimeout(2) - - err := natsjs.New(). - InitStream("test"). - NewMessage(). - SetSubject("test", "subject"). - SetData("test data"). - Publish() - - assert.Nil(t, err) -} - -func testMessagePublishError(t *testing.T) { - defer nats.MockServer()() - natsjs.Connect() - natsjs.SetTimeout(0) - - err := natsjs.New(). - NewMessage(). - SetSubject("test", "subject"). - SetData("test data"). - Publish() - - assert.Error(t, err) -} - -func testPublishNoConnection(t *testing.T) { - natsjs.Close() - - assert.PanicsWithValue( - t, - "Connection is not established", - func() { - natsjs.New(). - NewMessage(). - SetSubject("test", "subject"). - SetData("test data"). - Publish() - }, - "Publish should panic if connection is not set", - ) -} - -func testPublishNoData(t *testing.T) { - defer nats.MockServer()() - natsjs.Connect() - - err := natsjs.New(). - NewMessage(). - SetSubject("test", "subject"). - Publish() - - assert.Error(t, err) -} diff --git a/messaging/natsjs/stream.go b/messaging/natsjs/stream.go deleted file mode 100644 index efeb517..0000000 --- a/messaging/natsjs/stream.go +++ /dev/null @@ -1,91 +0,0 @@ -package natsjs - -import ( - "crypto/tls" - "os" - "time" - - "github.com/nats-io/nats.go" - "github.com/nats-io/nats.go/jetstream" -) - -type conn struct { - nc *nats.Conn - js jetstream.JetStream -} - -var reconnect = true -var connection *conn -var timeout = 30 * time.Second - -func SetTimeout(t time.Duration) { - timeout = t * time.Second -} - -func SetReconnect(r bool) { - reconnect = r -} - -// Connect establishes a connection to the NATS server. -// -// USAGE: -// -// import "api/lib/stream" -// -// stream.New(). -// -// InitStream("default"). -// NewMessage(). -// SetSubject("notifications.email", params.Kind, params.Category). -// SetData(map[string]int{"pending_notifications_id": row.ID}). -// Publish() -func Connect() { - if connection != nil && connection.nc != nil && !connection.nc.IsClosed() { - return - } - - host := os.Getenv("NATS_HOST") - if host == "" { - panic("NATS_HOST is not set") - } - - opts := nats.Options{ - Url: host, - - AllowReconnect: reconnect, - RetryOnFailedConnect: true, - MaxReconnect: 10, - ReconnectWait: 10 * time.Second, - - // this is acceptable because the nats server is not exposed outside the cluster - // it is currently using a self signed certificate so we need to skip the verification - TLSConfig: &tls.Config{ - InsecureSkipVerify: true, - }, - } - - nc, err := opts.Connect() - if err != nil { - panic(err) - } - - js, err := jetstream.New(nc) - if err != nil { - panic(err) - } - - connection = &conn{nc, js} -} - -func Close() { - if connection == nil || connection.nc == nil { - return - } - - connection.nc.Close() - connection = nil -} - -func New() *Client { - return &Client{} -} diff --git a/messaging/natsjs/stream_test.go b/messaging/natsjs/stream_test.go deleted file mode 100644 index 00bfe37..0000000 --- a/messaging/natsjs/stream_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package natsjs_test - -import ( - "os" - "reflect" - "runtime" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/simiancreative/simiango/messaging/natsjs" - "github.com/simiancreative/simiango/mocks/nats" -) - -func TestStream(t *testing.T) { - natsjs.SetReconnect(false) - - for _, test := range tests { - // gets the function name to apply to the test run - funcValue := reflect.ValueOf(test) - name := runtime.FuncForPC(funcValue.Pointer()).Name() - - // runs test sequentially so the mock server doesnt trip over itself - t.Run(name, test) - } -} - -var tests = []func(*testing.T){ - testConnect, - testConnectFailure, - testInitStreamNoConnection, - testMessageSetSubject, - testMessageSetData, - testMessageSetDataError, - testMessagePublish, - testMessagePublishError, - testPublishNoConnection, - testPublishNoData, - testNewConsumer, - testNewConsumerFailure, - testNewConsumerConsume, - testNewConsumerStop, - testNewConsumerNoConnection, - testNewConsumerConsumeFailure, -} - -func testConnectFailure(t *testing.T) { - natsjs.Close() - - assert.PanicsWithValue( - t, - "NATS_HOST is not set", - func() { - os.Unsetenv("NATS_HOST") - natsjs.Connect() - }, - "Connect should panic if NATS_HOST is not set", - ) -} - -func testConnect(t *testing.T) { - defer nats.MockServer()() - - assert.NotPanics( - t, - func() { - natsjs.Connect() - }, - "Connect should not panic if NATS_HOST is set", - ) -} - -func testInitStreamNoConnection(t *testing.T) { - assert.PanicsWithValue( - t, - "Connection is not established", - func() { - natsjs.Close() - natsjs.New().InitStream("test") - }, - "Connect should panic if connection is not set", - ) -} diff --git a/messaging/natsjscm/natsjscm.go b/messaging/natsjscm/natsjscm.go new file mode 100644 index 0000000..9571bf2 --- /dev/null +++ b/messaging/natsjscm/natsjscm.go @@ -0,0 +1,250 @@ +package natsjscm + +import ( + "context" + "fmt" + "sync" + "time" + + "github.com/nats-io/nats.go" + "github.com/nats-io/nats.go/jetstream" + "github.com/sanity-io/litter" + "github.com/simiancreative/simiango/logger" +) + +type Logger interface { + Debugf(format string, args ...interface{}) + Errorf(format string, args ...interface{}) +} + +type Connector interface { + Connect() error + Disconnect() error + IsConnected() bool + GetConnection() *nats.Conn + GetJetStream() jetstream.JetStream + EnsureStream(ctx context.Context, config jetstream.StreamConfig) (jetstream.JetStream, error) +} + +// ConnectionConfig holds the configuration for NATS connection +type ConnectionConfig struct { + URL string + Options []nats.Option + Logger Logger // Optional logger + ReconnectWait time.Duration + JetStreamDomain string // Optional JetStream domain +} + +// ConnectionManager manages NATS connections +type ConnectionManager struct { + config ConnectionConfig + nc *nats.Conn + js jetstream.JetStream + mu sync.RWMutex + refs int + log Logger +} + +// NewConnectionManager creates a new connection manager +func NewConnectionManager(config ConnectionConfig) (*ConnectionManager, error) { + if config.URL == "" { + return nil, fmt.Errorf("NATS URL is required") + } + + if config.Logger == nil { + config.Logger = logger.New() + } + + if config.ReconnectWait <= 0 { + config.ReconnectWait = 5 * time.Second + } + + // Add connection status callbacks + options := append([]nats.Option{}, config.Options...) + cm := &ConnectionManager{ + config: config, + log: config.Logger, + } + + // Add connection event handlers + options = append(options, + nats.ReconnectHandler(func(_ *nats.Conn) { + cm.handleReconnect() + }), + ) + + cm.config.Options = options + return cm, nil +} + +func (cm *ConnectionManager) handleReconnect() { + cm.mu.Lock() + defer cm.mu.Unlock() + + cm.log.Debugf("NATS connection reconnected") + + // Recreate JetStream context after reconnect + if cm.nc == nil { + return + } + + js, err := cm.createJetStreamContext(cm.nc) + if err != nil { + cm.log.Errorf("Failed to recreate JetStream context %s", err) + go cm.retryConnection() + return + } + + cm.js = js + cm.log.Debugf("JetStream context recreated") +} + +// createJetStreamContext creates a new JetStream context with the current configuration +func (cm *ConnectionManager) createJetStreamContext(nc *nats.Conn) (jetstream.JetStream, error) { + // Create JetStream context + return jetstream.New(nc) +} + +// retryConnection attempts to reconnect to NATS periodically +func (cm *ConnectionManager) retryConnection() { + for { + time.Sleep(cm.config.ReconnectWait) + + cm.mu.Lock() + if cm.nc != nil && cm.nc.IsConnected() { + cm.mu.Unlock() + return + } + + cm.log.Debugf("Attempting to reconnect to NATS") + nc, err := nats.Connect(cm.config.URL, cm.config.Options...) + if err != nil { + cm.log.Errorf("Failed to reconnect to NATS: %s", err) + cm.mu.Unlock() + continue + } + + js, err := cm.createJetStreamContext(nc) + if err != nil { + cm.log.Errorf("Failed to recreate JetStream context: %s", err) + nc.Close() + cm.mu.Unlock() + continue + } + + cm.nc = nc + cm.js = js + cm.refs = 1 + cm.log.Debugf("Successfully reconnected to NATS") + cm.mu.Unlock() + return + } +} + +// Connect establishes a connection to NATS if not already connected +func (cm *ConnectionManager) Connect() error { + cm.mu.Lock() + defer cm.mu.Unlock() + + // If already connected, increment reference count + if cm.nc != nil && cm.nc.IsConnected() { + cm.refs++ + return nil + } + + litter.Dump(cm.config) + + // Connect to NATS + nc, err := nats.Connect(cm.config.URL, cm.config.Options...) + if err != nil { + return fmt.Errorf("failed to connect to NATS: %w", err) + } + + // Create JetStream context + js, err := cm.createJetStreamContext(nc) + if err != nil { + nc.Close() + return fmt.Errorf("failed to create JetStream context: %w", err) + } + + cm.nc = nc + cm.js = js + cm.refs = 1 + + return nil +} + +// GetConnection returns the NATS connection +func (cm *ConnectionManager) GetConnection() *nats.Conn { + cm.mu.RLock() + defer cm.mu.RUnlock() + return cm.nc +} + +// GetJetStream returns the JetStream context +func (cm *ConnectionManager) GetJetStream() jetstream.JetStream { + cm.mu.RLock() + defer cm.mu.RUnlock() + return cm.js +} + +// EnsureStream creates a stream if it doesn't exist +func (cm *ConnectionManager) EnsureStream( + ctx context.Context, + config jetstream.StreamConfig, +) (jetstream.JetStream, error) { + cm.mu.RLock() + js := cm.js + cm.mu.RUnlock() + + if js == nil { + return nil, fmt.Errorf("not connected to JetStream") + } + + // Try to get the stream first + _, err := js.Stream(ctx, config.Name) + + // If stream exists, return it + if err == nil { + return js, nil + } + + // If stream doesn't exist, create it + if err == jetstream.ErrStreamNotFound { + _, err := js.CreateStream(ctx, config) + if err != nil { + return nil, err + } + return js, nil + } + + return nil, err +} + +// Disconnect decrements the reference count and closes connection if no more references +func (cm *ConnectionManager) Disconnect() error { + cm.mu.Lock() + defer cm.mu.Unlock() + + if cm.nc == nil { + return nil + } + + cm.refs-- + if cm.refs > 0 { + return nil + } + + cm.nc.Close() + cm.nc = nil + cm.js = nil + + return nil +} + +// IsConnected checks if there is an active connection +func (cm *ConnectionManager) IsConnected() bool { + cm.mu.RLock() + defer cm.mu.RUnlock() + return cm.nc != nil && cm.nc.IsConnected() && !cm.nc.IsClosed() +} diff --git a/messaging/natsjscm/natsjscm_test.go b/messaging/natsjscm/natsjscm_test.go new file mode 100644 index 0000000..a4aa137 --- /dev/null +++ b/messaging/natsjscm/natsjscm_test.go @@ -0,0 +1,345 @@ +package natsjscm_test + +import ( + "context" + "fmt" + "net" + "os" + "strconv" + "testing" + "time" + + natsserver "github.com/nats-io/nats-server/v2/test" + "github.com/nats-io/nats.go/jetstream" + + "github.com/nats-io/nats.go" + "github.com/simiancreative/simiango/messaging/natsjscm" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// Mock Logger for testing +type mockLogger struct { + debugMessages []string + errorMessages []string +} + +func newMockLogger() *mockLogger { + return &mockLogger{ + debugMessages: []string{}, + errorMessages: []string{}, + } +} + +func (m *mockLogger) Debugf(format string, args ...interface{}) { + m.debugMessages = append(m.debugMessages, fmt.Sprintf(format, args...)) +} + +func (m *mockLogger) Errorf(format string, args ...interface{}) { + m.errorMessages = append(m.errorMessages, fmt.Sprintf(format, args...)) +} + +func MockServer(args ...int) func() { + port := 0 + if len(args) > 0 { + port = args[0] + } + + err := getPort(&port) + if err != nil { + panic(err) + } + + os.Setenv("NATS_HOST", fmt.Sprintf("localhost:%v", port)) + os.Setenv("NATS_PORT", fmt.Sprintf("%v", port)) + + opts := natsserver.DefaultTestOptions + opts.Port = port + opts.JetStream = true + + return natsserver.RunServer(&opts).Shutdown +} + +func getPort(port *int) error { + if *port != 0 { + return nil + } + + addr, _ := net.ResolveTCPAddr("tcp", "localhost:0") + + listener, _ := net.ListenTCP("tcp", addr) + defer listener.Close() + + *port = listener.Addr().(*net.TCPAddr).Port + + return nil +} + +// TestNewConnectionManager tests the creation of the ConnectionManager +func TestNewConnectionManager(t *testing.T) { + tests := []struct { + name string + config natsjscm.ConnectionConfig + expectError bool + errorMsg string + }{ + { + name: "Valid configuration", + config: natsjscm.ConnectionConfig{ + URL: "nats://localhost:4222", + ReconnectWait: 5 * time.Second, + }, + expectError: false, + }, + { + name: "Missing URL", + config: natsjscm.ConnectionConfig{ + URL: "", + ReconnectWait: 5 * time.Second, + }, + expectError: true, + errorMsg: "NATS URL is required", + }, + { + name: "With custom logger", + config: natsjscm.ConnectionConfig{ + URL: "nats://localhost:4222", + ReconnectWait: 5 * time.Second, + Logger: newMockLogger(), + }, + expectError: false, + }, + { + name: "With custom JetStream domain", + config: natsjscm.ConnectionConfig{ + URL: "nats://localhost:4222", + ReconnectWait: 5 * time.Second, + JetStreamDomain: "test-domain", + }, + expectError: false, + }, + { + name: "Zero reconnect wait should use default", + config: natsjscm.ConnectionConfig{ + URL: "nats://localhost:4222", + ReconnectWait: 0, + }, + expectError: false, + }, + { + name: "With NATS options", + config: natsjscm.ConnectionConfig{ + URL: "nats://localhost:4222", + ReconnectWait: 5 * time.Second, + Options: []nats.Option{nats.Name("test-connection")}, + }, + expectError: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + cm, err := natsjscm.NewConnectionManager(tc.config) + + if tc.expectError { + require.Error(t, err) + assert.Contains(t, err.Error(), tc.errorMsg) + } else { + require.NoError(t, err) + require.NotNil(t, cm) + } + }) + } +} + +// TestConnectionLifecycle tests connect, disconnect and status methods +func TestConnectionLifecycle(t *testing.T) { + defer MockServer()() + + tests := []struct { + name string + fn func(t *testing.T) + }{ + { + name: "Connect and check status", + fn: func(t *testing.T) { + cm, err := natsjscm.NewConnectionManager(natsjscm.ConnectionConfig{ + URL: os.Getenv("NATS_HOST"), + ReconnectWait: 100 * time.Millisecond, + }) + require.NoError(t, err) + + // Initially not connected + assert.False(t, cm.IsConnected()) + + // Connect + err = cm.Connect() + require.NoError(t, err) + assert.True(t, cm.IsConnected()) + + // Get connection and JetStream + nc := cm.GetConnection() + require.NotNil(t, nc) + + js := cm.GetJetStream() + require.NotNil(t, js) + + // Disconnect + err = cm.Disconnect() + require.NoError(t, err) + assert.False(t, cm.IsConnected()) + }, + }, + { + name: "Reference counting in connect/disconnect", + fn: func(t *testing.T) { + cm, err := natsjscm.NewConnectionManager(natsjscm.ConnectionConfig{ + URL: os.Getenv("NATS_HOST"), + ReconnectWait: 100 * time.Millisecond, + }) + require.NoError(t, err) + + // First connection + err = cm.Connect() + require.NoError(t, err) + assert.True(t, cm.IsConnected()) + + // Second connection (should increment ref count) + err = cm.Connect() + require.NoError(t, err) + + // First disconnect (should decrement ref count but stay connected) + err = cm.Disconnect() + require.NoError(t, err) + assert.True(t, cm.IsConnected()) + + // Second disconnect (should close connection) + err = cm.Disconnect() + require.NoError(t, err) + assert.False(t, cm.IsConnected()) + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, tc.fn) + } +} + +// TestEnsureStream tests stream management functionality +func TestEnsureStream(t *testing.T) { + defer MockServer()() + + cm, err := natsjscm.NewConnectionManager(natsjscm.ConnectionConfig{ + URL: os.Getenv("NATS_HOST"), + ReconnectWait: 100 * time.Millisecond, + }) + require.NoError(t, err) + + err = cm.Connect() + require.NoError(t, err) + defer func() { + err := cm.Disconnect() + require.NoError(t, err) + }() + + ctx := context.Background() + + tests := []struct { + name string + config jetstream.StreamConfig + expectError bool + }{ + { + name: "Create new stream", + config: jetstream.StreamConfig{ + Name: "test-stream-1", + Subjects: []string{"test.subject.1"}, + Storage: jetstream.MemoryStorage, + }, + expectError: false, + }, + { + name: "Get existing stream", + config: jetstream.StreamConfig{ + Name: "test-stream-1", // Same as previous test + Subjects: []string{"test.subject.1"}, + Storage: jetstream.MemoryStorage, + }, + expectError: false, + }, + { + name: "Create stream with invalid config", + config: jetstream.StreamConfig{ + Name: "", // Invalid - empty name + Subjects: []string{"test.subject.2"}, + }, + expectError: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + js, err := cm.EnsureStream(ctx, tc.config) + + if tc.expectError { + require.Error(t, err) + } else { + require.NoError(t, err) + require.NotNil(t, js) + + // Verify the stream exists + streamInfo, err := js.Stream(ctx, tc.config.Name) + require.NoError(t, err) + require.NotNil(t, streamInfo) + assert.Equal(t, tc.config.Name, streamInfo.CachedInfo().Config.Name) + } + }) + } +} + +// TestConnectionEvents tests the connection event handlers +func TestConnectionEvents(t *testing.T) { + shutdown := MockServer() + + // Create a mock logger to capture log messages + logger := newMockLogger() + + // Create a connection manager with event handlers + cm, err := natsjscm.NewConnectionManager(natsjscm.ConnectionConfig{ + URL: os.Getenv("NATS_HOST"), + ReconnectWait: 100 * time.Millisecond, + Logger: logger, + }) + require.NoError(t, err) + + // Connect to the server + err = cm.Connect() + require.NoError(t, err) + assert.True(t, cm.IsConnected()) + + // Simulate server shutdown to trigger disconnect + shutdown() + + assert.Eventually(t, func() bool { + return !cm.IsConnected() + }, 5000*time.Millisecond, 100*time.Millisecond, "Connection should be closed") + + // Restart the server to trigger reconnect + port, _ := strconv.Atoi(os.Getenv("NATS_PORT")) + defer MockServer(port)() + + // Verify reconnect handler was called + assert.Eventually(t, func() bool { + return cm.IsConnected() + }, 5000*time.Millisecond, 100*time.Millisecond, "Connection should be reconnected") + + // Verify JetStream context is properly recreated + js := cm.GetJetStream() + require.NotNil(t, js) + + // Clean up + err = cm.Disconnect() + require.NoError(t, err) + assert.False(t, cm.IsConnected()) +} diff --git a/mocks/nats/argo-event.go b/mocks/nats/argo-event.go deleted file mode 100644 index 01b08ee..0000000 --- a/mocks/nats/argo-event.go +++ /dev/null @@ -1,39 +0,0 @@ -package nats - -import ( - "crypto/md5" - "encoding/base64" - "encoding/json" - "fmt" - "time" - - "github.com/simiancreative/simiango/messaging/natsjs" -) - -func BuildArgoEvent(workflowName, action, msg string) string { - subject := fmt.Sprintf("%s-%s", workflowName, action) - - data := natsjs.ArgoEventData{ - Subject: subject, - } - - json.Unmarshal([]byte(msg), &data.Body) - dataStr, _ := json.Marshal(data) - - event := natsjs.ArgoEvent{ - Context: natsjs.ArgoEventContext{ - ID: fmt.Sprintf("%x", md5.Sum([]byte(subject))), - Source: "nats-event-source", - SpecVersion: "1.0", - Type: "nats", - DataContentType: "application/json", - Subject: subject, - Time: time.Now().Format(time.RFC3339), - }, - Data: base64.StdEncoding.EncodeToString(dataStr), - } - - jsonData, _ := json.Marshal(event) - - return string(jsonData) -} diff --git a/mocks/nats/argo-event_test.go b/mocks/nats/argo-event_test.go deleted file mode 100644 index 794d584..0000000 --- a/mocks/nats/argo-event_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package nats_test - -import ( - "encoding/base64" - "encoding/json" - "testing" - - "github.com/simiancreative/simiango/messaging/natsjs" - "github.com/simiancreative/simiango/mocks/nats" - "github.com/stretchr/testify/assert" -) - -func TestBuildArgoEvent(t *testing.T) { - // Test the happy path - workflowName := "test-workflow" - action := "test-action" - msg := `{"key":"value"}` - - result := nats.BuildArgoEvent(workflowName, action, msg) - - var event natsjs.ArgoEvent - err := json.Unmarshal([]byte(result), &event) - assert.NoError(t, err) - - expectedSubject := workflowName + "-" + action - assert.Equal(t, expectedSubject, event.Context.Subject) - - var data natsjs.ArgoEventData - dataBytes, _ := base64.StdEncoding.DecodeString(event.Data) - json.Unmarshal(dataBytes, &data) - assert.Equal(t, data.Subject, expectedSubject) -} diff --git a/mocks/nats/msg.go b/mocks/nats/msg.go deleted file mode 100644 index 68bb510..0000000 --- a/mocks/nats/msg.go +++ /dev/null @@ -1,96 +0,0 @@ -package nats - -import ( - "context" - "sync" - "time" - - "github.com/nats-io/nats.go" - "github.com/nats-io/nats.go/jetstream" -) - -var NewJetStreamMsg = func(subject string, data []byte) *jetStreamMsg { - return &jetStreamMsg{ - msg: &nats.Msg{ - Subject: subject, - Data: data, - }, - } -} - -type jetStreamMsg struct { - msg *nats.Msg - ackd bool - js *jetstream.JetStream - sync.Mutex -} - -func (m *jetStreamMsg) Metadata() (*jetstream.MsgMetadata, error) { - return nil, nil -} - -// Data returns the message body. -func (m *jetStreamMsg) Data() []byte { - return m.msg.Data -} - -// Headers returns a map of headers for a message. -func (m *jetStreamMsg) Headers() nats.Header { - return m.msg.Header -} - -// Subject returns a subject on which a message is published. -func (m *jetStreamMsg) Subject() string { - return m.msg.Subject -} - -// Reply returns a reply subject for a JetStream message. -func (m *jetStreamMsg) Reply() string { - return m.msg.Reply -} - -func (m *jetStreamMsg) Ack() error { - return nil -} - -func (m *jetStreamMsg) DoubleAck(_ context.Context) error { - return nil -} - -func (m *jetStreamMsg) Nak() error { - return nil -} - -func (m *jetStreamMsg) NakWithDelay(_ time.Duration) error { - return nil -} - -func (m *jetStreamMsg) InProgress() error { - return nil -} - -func (m *jetStreamMsg) Term() error { - return nil -} - -func (m *jetStreamMsg) TermWithReason(_ string) error { - return nil -} - -type ackOpts struct { - nakDelay time.Duration - termReason string -} - -func (m *jetStreamMsg) ackReply( - _ context.Context, - _ []byte, - _ bool, - _ ackOpts, -) error { - return nil -} - -func (m *jetStreamMsg) checkReply() error { - return nil -} diff --git a/mocks/nats/msg_test.go b/mocks/nats/msg_test.go deleted file mode 100644 index 663711f..0000000 --- a/mocks/nats/msg_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package nats - -import ( - "testing" - - "github.com/nats-io/nats.go" - "github.com/stretchr/testify/assert" -) - -func TestJetStreamMsg(t *testing.T) { - subject := "test.subject" - data := []byte("test data") - msg := NewJetStreamMsg(subject, data) - - t.Run("Metadata", func(t *testing.T) { - metadata, err := msg.Metadata() - assert.Nil(t, metadata) - assert.Nil(t, err) - }) - - t.Run("Data", func(t *testing.T) { - assert.Equal(t, data, msg.Data()) - }) - - t.Run("Headers", func(t *testing.T) { - assert.IsType(t, nats.Header{}, msg.Headers()) - }) - - t.Run("Subject", func(t *testing.T) { - assert.Equal(t, subject, msg.Subject()) - }) - - t.Run("Reply", func(t *testing.T) { - assert.Equal(t, "", msg.Reply()) - }) - - t.Run("Ack", func(t *testing.T) { - assert.Nil(t, msg.Ack()) - }) - - t.Run("DoubleAck", func(t *testing.T) { - assert.Nil(t, msg.DoubleAck(nil)) - }) - - t.Run("Nak", func(t *testing.T) { - assert.Nil(t, msg.Nak()) - }) - - t.Run("NakWithDelay", func(t *testing.T) { - assert.Nil(t, msg.NakWithDelay(0)) - }) - - t.Run("InProgress", func(t *testing.T) { - assert.Nil(t, msg.InProgress()) - }) - - t.Run("Term", func(t *testing.T) { - assert.Nil(t, msg.Term()) - }) - - t.Run("TermWithReason", func(t *testing.T) { - assert.Nil(t, msg.TermWithReason("")) - }) - - t.Run("ackReply", func(t *testing.T) { - assert.Nil(t, msg.ackReply(nil, nil, false, ackOpts{})) - }) - - t.Run("checkReply", func(t *testing.T) { - assert.Nil(t, msg.checkReply()) - }) -} diff --git a/mocks/nats/server.go b/mocks/nats/server.go deleted file mode 100644 index ff08b26..0000000 --- a/mocks/nats/server.go +++ /dev/null @@ -1,33 +0,0 @@ -package nats - -import ( - "fmt" - "net" - "os" - - natsserver "github.com/nats-io/nats-server/v2/test" -) - -func MockServer() func() { - port, err := getPort() - if err != nil { - panic(err) - } - - os.Setenv("NATS_HOST", fmt.Sprintf("localhost:%v", port)) - - opts := natsserver.DefaultTestOptions - opts.Port = port - opts.JetStream = true - - return natsserver.RunServer(&opts).Shutdown -} - -func getPort() (int, error) { - addr, _ := net.ResolveTCPAddr("tcp", "localhost:0") - - listener, _ := net.ListenTCP("tcp", addr) - defer listener.Close() - - return listener.Addr().(*net.TCPAddr).Port, nil -} diff --git a/test.log b/test.log new file mode 100644 index 0000000..e82cdbc --- /dev/null +++ b/test.log @@ -0,0 +1,1015 @@ +? github.com/simiancreative/simiango/data/sql [no test files] +? github.com/simiancreative/simiango/data/sql/combinators [no test files] +=== RUN TestRetry +=== RUN TestRetry/successful_retry +{"level":"debug","msg":"RETRYING: attempt 1","time":"2025-03-03T09:34:40-05:00"} +{"level":"debug","msg":"RETRYING: attempt 2","time":"2025-03-03T09:34:41-05:00"} +=== RUN TestRetry/max_retries_exceeded +{"level":"debug","msg":"RETRYING: attempt 1","time":"2025-03-03T09:34:42-05:00"} +{"level":"debug","msg":"RETRYING: attempt 2","time":"2025-03-03T09:34:43-05:00"} +--- PASS: TestRetry (4.01s) + --- PASS: TestRetry/successful_retry (2.00s) + --- PASS: TestRetry/max_retries_exceeded (2.00s) +PASS +coverage: 3.8% of statements in ./... +ok github.com/simiancreative/simiango/backoff 5.630s coverage: 3.8% of statements in ./... +=== RUN TestCircuitBreaker +=== RUN TestCircuitBreaker/remains_closed_when_under_threshold +time="2025-03-03T09:34:40-05:00" level=debug msg="creating new circuit breaker" failure_threshold=3 half_open_max_calls=2 open_timeout=1s +time="2025-03-03T09:34:40-05:00" level=debug msg="attempt started" attempts=1 state=CLOSED +time="2025-03-03T09:34:40-05:00" level=debug msg="recording attempt result" attempts=1 failures=0 state=CLOSED success=false successes=0 +time="2025-03-03T09:34:40-05:00" level=debug msg="recorded failure" failures=1 state=CLOSED threshold=3 +time="2025-03-03T09:34:40-05:00" level=debug msg="attempt started" attempts=2 state=CLOSED +time="2025-03-03T09:34:40-05:00" level=debug msg="recording attempt result" attempts=2 failures=1 state=CLOSED success=false successes=0 +time="2025-03-03T09:34:40-05:00" level=debug msg="recorded failure" failures=2 state=CLOSED threshold=3 +time="2025-03-03T09:34:40-05:00" level=debug msg="circuit breaker allow check" allowed=true attempts=2 max_calls=2 state=CLOSED +=== RUN TestCircuitBreaker/opens_after_threshold_failures +time="2025-03-03T09:34:40-05:00" level=debug msg="creating new circuit breaker" failure_threshold=2 half_open_max_calls=2 open_timeout=1s +time="2025-03-03T09:34:40-05:00" level=debug msg="attempt started" attempts=1 state=CLOSED +time="2025-03-03T09:34:40-05:00" level=debug msg="recording attempt result" attempts=1 failures=0 state=CLOSED success=false successes=0 +time="2025-03-03T09:34:40-05:00" level=debug msg="recorded failure" failures=1 state=CLOSED threshold=2 +time="2025-03-03T09:34:40-05:00" level=debug msg="attempt started" attempts=2 state=CLOSED +time="2025-03-03T09:34:40-05:00" level=debug msg="recording attempt result" attempts=2 failures=1 state=CLOSED success=false successes=0 +time="2025-03-03T09:34:40-05:00" level=debug msg="recorded failure" failures=2 state=CLOSED threshold=2 +time="2025-03-03T09:34:40-05:00" level=debug msg="opening circuit" from_state=CLOSED open_timeout=1s +time="2025-03-03T09:34:40-05:00" level=debug msg="state transition" attempts=0 from_state=CLOSED successes=0 to_state=OPEN +time="2025-03-03T09:34:40-05:00" level=debug msg="attempt rejected - circuit open" state=OPEN +=== RUN TestCircuitBreaker/transitions_to_half-open_after_timeout +time="2025-03-03T09:34:40-05:00" level=debug msg="creating new circuit breaker" failure_threshold=2 half_open_max_calls=2 open_timeout=50ms +time="2025-03-03T09:34:40-05:00" level=debug msg="attempt started" attempts=1 state=CLOSED +time="2025-03-03T09:34:40-05:00" level=debug msg="recording attempt result" attempts=1 failures=0 state=CLOSED success=false successes=0 +time="2025-03-03T09:34:40-05:00" level=debug msg="recorded failure" failures=1 state=CLOSED threshold=2 +time="2025-03-03T09:34:40-05:00" level=debug msg="attempt started" attempts=2 state=CLOSED +time="2025-03-03T09:34:40-05:00" level=debug msg="recording attempt result" attempts=2 failures=1 state=CLOSED success=false successes=0 +time="2025-03-03T09:34:40-05:00" level=debug msg="recorded failure" failures=2 state=CLOSED threshold=2 +time="2025-03-03T09:34:40-05:00" level=debug msg="opening circuit" from_state=CLOSED open_timeout=50ms +time="2025-03-03T09:34:40-05:00" level=debug msg="state transition" attempts=0 from_state=CLOSED successes=0 to_state=OPEN +time="2025-03-03T09:34:40-05:00" level=debug msg="open timeout elapsed" current_state=OPEN +time="2025-03-03T09:34:40-05:00" level=debug msg="state transition" attempts=0 from_state=OPEN successes=0 to_state=HALF_OPEN +time="2025-03-03T09:34:40-05:00" level=debug msg="attempt started" attempts=1 state=HALF_OPEN +=== RUN TestCircuitBreaker/closes_after_successful_half-open_calls +time="2025-03-03T09:34:40-05:00" level=debug msg="creating new circuit breaker" failure_threshold=2 half_open_max_calls=2 open_timeout=50ms +time="2025-03-03T09:34:40-05:00" level=debug msg="attempt started" attempts=1 state=CLOSED +time="2025-03-03T09:34:40-05:00" level=debug msg="recording attempt result" attempts=1 failures=0 state=CLOSED success=false successes=0 +time="2025-03-03T09:34:40-05:00" level=debug msg="recorded failure" failures=1 state=CLOSED threshold=2 +time="2025-03-03T09:34:40-05:00" level=debug msg="attempt started" attempts=2 state=CLOSED +time="2025-03-03T09:34:40-05:00" level=debug msg="recording attempt result" attempts=2 failures=1 state=CLOSED success=false successes=0 +time="2025-03-03T09:34:40-05:00" level=debug msg="recorded failure" failures=2 state=CLOSED threshold=2 +time="2025-03-03T09:34:40-05:00" level=debug msg="opening circuit" from_state=CLOSED open_timeout=50ms +time="2025-03-03T09:34:40-05:00" level=debug msg="state transition" attempts=0 from_state=CLOSED successes=0 to_state=OPEN +time="2025-03-03T09:34:40-05:00" level=debug msg="open timeout elapsed" current_state=OPEN +time="2025-03-03T09:34:40-05:00" level=debug msg="state transition" attempts=0 from_state=OPEN successes=0 to_state=HALF_OPEN +time="2025-03-03T09:34:40-05:00" level=debug msg="attempt started" attempts=1 state=HALF_OPEN +time="2025-03-03T09:34:40-05:00" level=debug msg="recording attempt result" attempts=1 failures=2 state=HALF_OPEN success=true successes=0 +time="2025-03-03T09:34:40-05:00" level=debug msg="recorded success in half-open state" attempts=1 max_calls=2 successes=1 +time="2025-03-03T09:34:40-05:00" level=debug msg="attempt started" attempts=2 state=HALF_OPEN +time="2025-03-03T09:34:40-05:00" level=debug msg="recording attempt result" attempts=2 failures=2 state=HALF_OPEN success=true successes=1 +time="2025-03-03T09:34:40-05:00" level=debug msg="recorded success in half-open state" attempts=2 max_calls=2 successes=2 +time="2025-03-03T09:34:40-05:00" level=debug msg="state transition" attempts=0 from_state=HALF_OPEN successes=0 to_state=CLOSED +=== RUN TestCircuitBreaker/limits_calls_in_half-open_state +time="2025-03-03T09:34:40-05:00" level=debug msg="creating new circuit breaker" failure_threshold=2 half_open_max_calls=2 open_timeout=50ms +time="2025-03-03T09:34:40-05:00" level=debug msg="attempt started" attempts=1 state=CLOSED +time="2025-03-03T09:34:40-05:00" level=debug msg="recording attempt result" attempts=1 failures=0 state=CLOSED success=false successes=0 +time="2025-03-03T09:34:40-05:00" level=debug msg="recorded failure" failures=1 state=CLOSED threshold=2 +time="2025-03-03T09:34:40-05:00" level=debug msg="attempt started" attempts=2 state=CLOSED +time="2025-03-03T09:34:40-05:00" level=debug msg="recording attempt result" attempts=2 failures=1 state=CLOSED success=false successes=0 +time="2025-03-03T09:34:40-05:00" level=debug msg="recorded failure" failures=2 state=CLOSED threshold=2 +time="2025-03-03T09:34:40-05:00" level=debug msg="opening circuit" from_state=CLOSED open_timeout=50ms +time="2025-03-03T09:34:40-05:00" level=debug msg="state transition" attempts=0 from_state=CLOSED successes=0 to_state=OPEN +time="2025-03-03T09:34:41-05:00" level=debug msg="open timeout elapsed" current_state=OPEN +time="2025-03-03T09:34:41-05:00" level=debug msg="state transition" attempts=0 from_state=OPEN successes=0 to_state=HALF_OPEN +time="2025-03-03T09:34:41-05:00" level=debug msg="attempt started" attempts=1 state=HALF_OPEN +time="2025-03-03T09:34:41-05:00" level=debug msg="attempt started" attempts=2 state=HALF_OPEN +time="2025-03-03T09:34:41-05:00" level=debug msg="attempt rejected - max half-open calls reached" attempts=2 max_calls=2 +time="2025-03-03T09:34:41-05:00" level=debug msg="recording attempt result" attempts=2 failures=2 state=HALF_OPEN success=true successes=0 +time="2025-03-03T09:34:41-05:00" level=debug msg="recorded success in half-open state" attempts=2 max_calls=2 successes=1 +time="2025-03-03T09:34:41-05:00" level=debug msg="recording attempt result" attempts=2 failures=2 state=HALF_OPEN success=true successes=1 +time="2025-03-03T09:34:41-05:00" level=debug msg="recorded success in half-open state" attempts=2 max_calls=2 successes=2 +time="2025-03-03T09:34:41-05:00" level=debug msg="state transition" attempts=0 from_state=HALF_OPEN successes=0 to_state=CLOSED +--- PASS: TestCircuitBreaker (0.19s) + --- PASS: TestCircuitBreaker/remains_closed_when_under_threshold (0.00s) + --- PASS: TestCircuitBreaker/opens_after_threshold_failures (0.00s) + --- PASS: TestCircuitBreaker/transitions_to_half-open_after_timeout (0.06s) + --- PASS: TestCircuitBreaker/closes_after_successful_half-open_calls (0.06s) + --- PASS: TestCircuitBreaker/limits_calls_in_half-open_state (0.06s) +PASS +coverage: 5.0% of statements in ./... +time="2025-03-03T09:34:41-05:00" level=debug msg="open timeout elapsed" current_state=OPEN +time="2025-03-03T09:34:41-05:00" level=debug msg="state transition" attempts=0 from_state=OPEN successes=0 to_state=HALF_OPEN +ok github.com/simiancreative/simiango/circuitbreaker 2.240s coverage: 5.0% of statements in ./... +=== RUN TestRecoverAndThrow +=== RUN TestRecoverAndThrow/as_string +{"level":"error","msg":"\n\n=============== LOGGING STACK TRACE =====================\n\nError: 4edca9f6-0ff0-444c-aae1-201ebe7c73bc\nrecovered\ngithub.com/simiancreative/simiango/cli.Recover\n\t/Users/ross/code/simian/simiango/cli/cli.go:58\nruntime.gopanic\n\t/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.10.darwin-arm64/src/runtime/panic.go:770\ngithub.com/simiancreative/simiango/cli_test.TestRecoverAndThrow.func1.1\n\t/Users/ross/code/simian/simiango/cli/cli_test.go:54\nruntime.goexit\n\t/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.10.darwin-arm64/src/runtime/asm_arm64.s:1222\n\n=============== END LOGGING STACK TRACE =================\n\n\t\t","time":"2025-03-03T09:34:41-05:00"} +{"event_id":"e156f9b65dc4417db51e15728e6715e9","sent_at":"2025-03-03T09:34:41.347583-05:00","dsn":"http://publicKey@127.0.0.1:57868/1","sdk":{"name":"sentry.go","version":"0.31.1"},"trace":{"public_key":"publicKey","release":"b5bff38-dirty","sample_rate":"0.1","trace_id":"f58f2215154a01f69f5556f9054727cf"}} +{"type":"event","length":2195} +{"contexts":{"device":{"arch":"arm64","num_cpu":12},"os":{"name":"darwin"},"runtime":{"go_maxprocs":12,"go_numcgocalls":1,"go_numroutines":9,"name":"go","version":"go1.22.10 X:nocoverageredesign"},"trace":{"span_id":"4e08c010e5dc699b","trace_id":"f58f2215154a01f69f5556f9054727cf"}},"event_id":"e156f9b65dc4417db51e15728e6715e9","level":"fatal","platform":"go","release":"b5bff38-dirty","sdk":{"name":"sentry.go","version":"0.31.1","integrations":["ContextifyFrames","Environment","GlobalTags","IgnoreErrors","IgnoreTransactions","Modules"],"packages":[{"name":"sentry-go","version":"0.31.1"}]},"server_name":"Rosss-MacBook-Pro.local","user":{},"modules":{"":""},"exception":[{"type":"*errors.errorString","value":"4edca9f6-0ff0-444c-aae1-201ebe7c73bc","mechanism":{"type":"generic","exception_id":0,"is_exception_group":true}},{"type":"*errors.withMessage","value":"recovered: 4edca9f6-0ff0-444c-aae1-201ebe7c73bc","mechanism":{"type":"generic","parent_id":0,"exception_id":1,"is_exception_group":true}},{"type":"*errors.withStack","value":"recovered: 4edca9f6-0ff0-444c-aae1-201ebe7c73bc","stacktrace":{"frames":[{"function":"TestRecoverAndThrow.func1.1","module":"github.com/simiancreative/simiango/cli_test","abs_path":"/Users/ross/code/simian/simiango/cli/cli_test.go","lineno":54,"pre_context":["\t\t\t// Set up the Sentry client","\t\t\tsentry.Enable()","","\t\t\tgo func() {","\t\t\t\tdefer cli.Recover()"],"context_line":"\t\t\t\tpanic(tt.param)","post_context":["\t\t\t}()","","\t\t\tselect {","\t\t\tcase request := \u003c-handledRequests:","\t\t\t\tassert.Equal(t, \"/api/1/envelope/\", request.R.URL.Path)"],"in_app":true},{"function":"Recover","module":"github.com/simiancreative/simiango/cli","abs_path":"/Users/ross/code/simian/simiango/cli/cli.go","lineno":58,"pre_context":["\tif ok {","\t\terr = errors.Wrap(err, \"recovered\")","\t}","","\tif !ok {"],"context_line":"\t\terr = errors.Wrap(fmt.Errorf(\"%v\", val), \"recovered\")","post_context":["\t}","","\tprintStackTrace(err)","","\tsentry.CurrentHub().Recover(err)"],"in_app":true}]},"mechanism":{"type":"generic","parent_id":1,"exception_id":2,"is_exception_group":true}}],"timestamp":"2025-03-03T09:34:41.346154-05:00"} + +=== RUN TestRecoverAndThrow/as_error +{"level":"error","msg":"\n\n=============== LOGGING STACK TRACE =====================\n\nError: error: 4edca9f6-0ff0-444c-aae1-201ebe7c73bc\nrecovered\ngithub.com/simiancreative/simiango/cli.Recover\n\t/Users/ross/code/simian/simiango/cli/cli.go:54\nruntime.gopanic\n\t/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.10.darwin-arm64/src/runtime/panic.go:770\ngithub.com/simiancreative/simiango/cli_test.TestRecoverAndThrow.func1.1\n\t/Users/ross/code/simian/simiango/cli/cli_test.go:54\nruntime.goexit\n\t/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.10.darwin-arm64/src/runtime/asm_arm64.s:1222\n\n=============== END LOGGING STACK TRACE =================\n\n\t\t","time":"2025-03-03T09:34:41-05:00"} +{"event_id":"c88ac3f181f145348a3498a4b8bf29c5","sent_at":"2025-03-03T09:34:41.37523-05:00","dsn":"http://publicKey@127.0.0.1:57870/1","sdk":{"name":"sentry.go","version":"0.31.1"},"trace":{"public_key":"publicKey","release":"b5bff38-dirty","sample_rate":"0.1","trace_id":"f58f2215154a01f69f5556f9054727cf"}} +{"type":"event","length":2198} +{"contexts":{"device":{"arch":"arm64","num_cpu":12},"os":{"name":"darwin"},"runtime":{"go_maxprocs":12,"go_numcgocalls":1,"go_numroutines":14,"name":"go","version":"go1.22.10 X:nocoverageredesign"},"trace":{"span_id":"4e08c010e5dc699b","trace_id":"f58f2215154a01f69f5556f9054727cf"}},"event_id":"c88ac3f181f145348a3498a4b8bf29c5","level":"fatal","platform":"go","release":"b5bff38-dirty","sdk":{"name":"sentry.go","version":"0.31.1","integrations":["ContextifyFrames","Environment","GlobalTags","IgnoreErrors","IgnoreTransactions","Modules"],"packages":[{"name":"sentry-go","version":"0.31.1"}]},"server_name":"Rosss-MacBook-Pro.local","user":{},"modules":{"":""},"exception":[{"type":"*errors.errorString","value":"error: 4edca9f6-0ff0-444c-aae1-201ebe7c73bc","mechanism":{"type":"generic","exception_id":0,"is_exception_group":true}},{"type":"*errors.withMessage","value":"recovered: error: 4edca9f6-0ff0-444c-aae1-201ebe7c73bc","mechanism":{"type":"generic","parent_id":0,"exception_id":1,"is_exception_group":true}},{"type":"*errors.withStack","value":"recovered: error: 4edca9f6-0ff0-444c-aae1-201ebe7c73bc","stacktrace":{"frames":[{"function":"TestRecoverAndThrow.func1.1","module":"github.com/simiancreative/simiango/cli_test","abs_path":"/Users/ross/code/simian/simiango/cli/cli_test.go","lineno":54,"pre_context":["\t\t\t// Set up the Sentry client","\t\t\tsentry.Enable()","","\t\t\tgo func() {","\t\t\t\tdefer cli.Recover()"],"context_line":"\t\t\t\tpanic(tt.param)","post_context":["\t\t\t}()","","\t\t\tselect {","\t\t\tcase request := \u003c-handledRequests:","\t\t\t\tassert.Equal(t, \"/api/1/envelope/\", request.R.URL.Path)"],"in_app":true},{"function":"Recover","module":"github.com/simiancreative/simiango/cli","abs_path":"/Users/ross/code/simian/simiango/cli/cli.go","lineno":54,"pre_context":["\t\treturn","\t}","","\terr, ok := val.(error)","\tif ok {"],"context_line":"\t\terr = errors.Wrap(err, \"recovered\")","post_context":["\t}","","\tif !ok {","\t\terr = errors.Wrap(fmt.Errorf(\"%v\", val), \"recovered\")","\t}"],"in_app":true}]},"mechanism":{"type":"generic","parent_id":1,"exception_id":2,"is_exception_group":true}}],"timestamp":"2025-03-03T09:34:41.374748-05:00"} + +--- PASS: TestRecoverAndThrow (0.08s) + --- PASS: TestRecoverAndThrow/as_string (0.05s) + --- PASS: TestRecoverAndThrow/as_error (0.03s) +PASS +coverage: 4.8% of statements in ./... +ok github.com/simiancreative/simiango/cli 2.561s coverage: 4.8% of statements in ./... +=== RUN TestWithFlag +--- PASS: TestWithFlag (0.00s) +=== RUN TestWithFlagNoEnv +{"level":"error","msg":"No environment specified","time":"2025-03-03T09:34:41-05:00"} +--- PASS: TestWithFlagNoEnv (0.00s) +=== RUN TestEnable +--- PASS: TestEnable (0.00s) +=== RUN TestEnableNoEnv +--- PASS: TestEnableNoEnv (0.00s) +PASS +coverage: 3.5% of statements in ./... +ok github.com/simiancreative/simiango/config 2.887s coverage: 3.5% of statements in ./... +=== RUN TestNew +--- PASS: TestNew (0.00s) +PASS +coverage: 2.3% of statements in ./... +ok github.com/simiancreative/simiango/cryptkeeper 3.723s coverage: 2.3% of statements in ./... +=== RUN TestKeeper_SetConfigurator +--- PASS: TestKeeper_SetConfigurator (0.00s) +=== RUN TestKeeper_SetEncrypter +--- PASS: TestKeeper_SetEncrypter (0.00s) +=== RUN TestKeeper_SetHasher +--- PASS: TestKeeper_SetHasher (0.00s) +=== RUN TestKeeper_Encrypt +--- PASS: TestKeeper_Encrypt (0.00s) +=== RUN TestKeeper_Decrypt +--- PASS: TestKeeper_Decrypt (0.00s) +=== RUN TestKeeper_Hash +--- PASS: TestKeeper_Hash (0.00s) +=== RUN TestKeeper_Verify +--- PASS: TestKeeper_Verify (0.00s) +PASS +coverage: 2.4% of statements in ./... +ok github.com/simiancreative/simiango/cryptkeeper/keepers 3.301s coverage: 2.4% of statements in ./... +=== RUN TestSetup +--- PASS: TestSetup (0.00s) +=== RUN TestEncrypt +--- PASS: TestEncrypt (0.00s) +=== RUN TestDecrypt +--- PASS: TestDecrypt (0.00s) +PASS +coverage: 4.5% of statements in ./... +ok github.com/simiancreative/simiango/cryptkeeper/keepers/aes 4.113s coverage: 4.5% of statements in ./... +? github.com/simiancreative/simiango/messaging/amqp [no test files] +? github.com/simiancreative/simiango/messaging/kafka [no test files] +=== RUN TestHash +--- PASS: TestHash (0.64s) +=== RUN TestVerify +--- PASS: TestVerify (1.90s) +PASS +coverage: 2.0% of statements in ./... +ok github.com/simiancreative/simiango/cryptkeeper/keepers/bcrypt 7.041s coverage: 2.0% of statements in ./... +=== RUN TestPGP +--- PASS: TestPGP (1.54s) +=== RUN TestPGPErr +--- PASS: TestPGPErr (0.00s) +PASS +coverage: 3.3% of statements in ./... +ok github.com/simiancreative/simiango/cryptkeeper/keepers/pgp 7.350s coverage: 3.3% of statements in ./... +=== RUN TestQueryX +--- PASS: TestQueryX (0.00s) +PASS +coverage: 2.3% of statements in ./... +ok github.com/simiancreative/simiango/data/mssql 5.374s coverage: 2.3% of statements in ./... +=== RUN TestQueryX +--- PASS: TestQueryX (0.00s) +PASS +coverage: 2.3% of statements in ./... +ok github.com/simiancreative/simiango/data/mysql 6.248s coverage: 2.3% of statements in ./... +=== RUN TestQueryX +--- PASS: TestQueryX (0.00s) +PASS +coverage: 2.3% of statements in ./... +ok github.com/simiancreative/simiango/data/pg 4.972s coverage: 2.3% of statements in ./... +=== RUN TestClientGet +--- PASS: TestClientGet (0.00s) +=== RUN TestClientSet +--- PASS: TestClientSet (0.00s) +=== RUN TestClientExists +--- PASS: TestClientExists (0.00s) +=== RUN TestClientDel +--- PASS: TestClientDel (0.00s) +PASS +coverage: 2.3% of statements in ./... +ok github.com/simiancreative/simiango/data/redis 3.670s coverage: 2.3% of statements in ./... +=== RUN TestRegister +--- PASS: TestRegister (0.00s) +PASS +coverage: 1.9% of statements in ./... +ok github.com/simiancreative/simiango/data/redis/mock 3.788s coverage: 1.9% of statements in ./... +=== RUN TestCreate +"SELECT `products`.* FROM `products` WHERE (`id` = 456)" +--- PASS: TestCreate (0.00s) +=== RUN TestDelete +--- PASS: TestDelete (0.00s) +=== RUN TestOne +--- PASS: TestOne (0.00s) +=== RUN TestAugmentOne +--- PASS: TestAugmentOne (0.00s) +=== RUN TestPage +--- PASS: TestPage (0.00s) +=== RUN TestColumns +--- PASS: TestColumns (0.00s) +=== RUN TestOrder +--- PASS: TestOrder (0.00s) +=== RUN TestFilters +--- PASS: TestFilters (0.00s) +=== RUN TestAugmentListQuery +--- PASS: TestAugmentListQuery (0.00s) +=== RUN TestPageFromReq +--- PASS: TestPageFromReq (0.00s) +=== RUN TestPageFromReqNoOrder +--- PASS: TestPageFromReqNoOrder (0.00s) +=== RUN TestUpdate +"SELECT `products`.* FROM `products` WHERE (`id` = 456)" +--- PASS: TestUpdate (0.00s) +PASS +coverage: 9.6% of statements in ./... +ok github.com/simiancreative/simiango/data/sql/crud 3.315s coverage: 9.6% of statements in ./... +=== RUN TestScan +--- PASS: TestScan (0.00s) +=== RUN TestScanFail +--- PASS: TestScanFail (0.00s) +=== RUN TestMarshall +--- PASS: TestMarshall (0.00s) +=== RUN TestUnMarshall +--- PASS: TestUnMarshall (0.00s) +PASS +coverage: 6.1% of statements in ./... +ok github.com/simiancreative/simiango/data/sql/nulls 3.608s coverage: 6.1% of statements in ./... +=== RUN TestPage +--- PASS: TestPage (0.00s) +PASS +coverage: 4.3% of statements in ./... +ok github.com/simiancreative/simiango/data/sql/pagination 3.826s coverage: 4.3% of statements in ./... +? github.com/simiancreative/simiango/simian-go [no test files] +? github.com/simiancreative/simiango/simian-go/app/cryptkeeper [no test files] +? github.com/simiancreative/simiango/simian-go/app [no test files] +? github.com/simiancreative/simiango/simian-go/app/cryptkeeper/encrypt [no test files] +? github.com/simiancreative/simiango/simian-go/app/gen [no test files] +? github.com/simiancreative/simiango/simian-go/app/cryptkeeper/decrypt [no test files] +? github.com/simiancreative/simiango/simian-go/app/gen/service [no test files] +? github.com/simiancreative/simiango/simian-go/app/meta [no test files] +? github.com/simiancreative/simiango/simian-go/app/token [no test files] +? github.com/simiancreative/simiango/simian-go/app/token/decode [no test files] +? github.com/simiancreative/simiango/simian-go/app/token/generate [no test files] +? github.com/simiancreative/simiango/simian-go/app/meta/uuid [no test files] +? github.com/simiancreative/simiango/stats/prometheus [no test files] +? github.com/simiancreative/simiango/simian-go/app/token/test [no test files] +=== RUN TestUnsafeSelect +--- PASS: TestUnsafeSelect (0.00s) +=== RUN TestUnsafeGet +--- PASS: TestUnsafeGet (0.00s) +=== RUN TestUnsafeResultaddItem +--- PASS: TestUnsafeResultaddItem (0.00s) +=== RUN TestUnsafeCoerceBIGINT +--- PASS: TestUnsafeCoerceBIGINT (0.00s) +=== RUN TestUnsafeCoerceDECIMAL +--- PASS: TestUnsafeCoerceDECIMAL (0.00s) +=== RUN TestUnsafeCoerceVARCHAR +--- PASS: TestUnsafeCoerceVARCHAR (0.00s) +=== RUN TestUnsafeCoerceUNKNOWN +--- PASS: TestUnsafeCoerceUNKNOWN (0.00s) +PASS +coverage: 3.9% of statements in ./... +ok github.com/simiancreative/simiango/data/sql/unsafe 3.811s coverage: 3.9% of statements in ./... +=== RUN TestMock +--- PASS: TestMock (0.00s) +PASS +coverage: 2.1% of statements in ./... +ok github.com/simiancreative/simiango/logger 3.446s coverage: 2.1% of statements in ./... +? github.com/simiancreative/simiango/timeutils [no test files] +=== RUN TestNewConnectionManager +=== RUN TestNewConnectionManager/Valid_configuration +=== RUN TestNewConnectionManager/Missing_URL +=== RUN TestNewConnectionManager/With_custom_logger +=== RUN TestNewConnectionManager/With_custom_JetStream_domain +=== RUN TestNewConnectionManager/Zero_reconnect_wait_should_use_default +=== RUN TestNewConnectionManager/With_NATS_options +--- PASS: TestNewConnectionManager (0.00s) + --- PASS: TestNewConnectionManager/Valid_configuration (0.00s) + --- PASS: TestNewConnectionManager/Missing_URL (0.00s) + --- PASS: TestNewConnectionManager/With_custom_logger (0.00s) + --- PASS: TestNewConnectionManager/With_custom_JetStream_domain (0.00s) + --- PASS: TestNewConnectionManager/Zero_reconnect_wait_should_use_default (0.00s) + --- PASS: TestNewConnectionManager/With_NATS_options (0.00s) +=== RUN TestConnectionLifecycle +=== RUN TestConnectionLifecycle/Connect_and_check_status +natsjscm.ConnectionConfig{ + URL: "localhost:57895", + Options: []nats.Option{ + nats.Option, + }, + Logger: &logrus.Logger{ + Out: &os.File{}, + Hooks: logrus.LevelHooks{}, + Formatter: &logrus.JSONFormatter{ + TimestampFormat: "", + DisableTimestamp: false, + DisableHTMLEscape: false, + DataKey: "", + FieldMap: logrus.FieldMap(nil), + CallerPrettyfier: , + PrettyPrint: false, + }, + ReportCaller: false, + Level: 5, + ExitFunc: os.Exit, + BufferPool: nil, + }, + ReconnectWait: 100000000, + JetStreamDomain: "", +} +=== RUN TestConnectionLifecycle/Reference_counting_in_connect/disconnect +natsjscm.ConnectionConfig{ + URL: "localhost:57895", + Options: []nats.Option{ + nats.Option, + }, + Logger: &logrus.Logger{ + Out: &os.File{}, + Hooks: logrus.LevelHooks{}, + Formatter: &logrus.JSONFormatter{ + TimestampFormat: "", + DisableTimestamp: false, + DisableHTMLEscape: false, + DataKey: "", + FieldMap: logrus.FieldMap(nil), + CallerPrettyfier: , + PrettyPrint: false, + }, + ReportCaller: false, + Level: 5, + ExitFunc: os.Exit, + BufferPool: nil, + }, + ReconnectWait: 100000000, + JetStreamDomain: "", +} +--- PASS: TestConnectionLifecycle (0.04s) + --- PASS: TestConnectionLifecycle/Connect_and_check_status (0.01s) + --- PASS: TestConnectionLifecycle/Reference_counting_in_connect/disconnect (0.00s) +=== RUN TestEnsureStream +natsjscm.ConnectionConfig{ + URL: "localhost:57901", + Options: []nats.Option{ + nats.Option, + }, + Logger: &logrus.Logger{ + Out: &os.File{}, + Hooks: logrus.LevelHooks{}, + Formatter: &logrus.JSONFormatter{ + TimestampFormat: "", + DisableTimestamp: false, + DisableHTMLEscape: false, + DataKey: "", + FieldMap: logrus.FieldMap(nil), + CallerPrettyfier: , + PrettyPrint: false, + }, + ReportCaller: false, + Level: 5, + ExitFunc: os.Exit, + BufferPool: nil, + }, + ReconnectWait: 100000000, + JetStreamDomain: "", +} +=== RUN TestEnsureStream/Create_new_stream +=== RUN TestEnsureStream/Get_existing_stream +=== RUN TestEnsureStream/Create_stream_with_invalid_config +--- PASS: TestEnsureStream (0.04s) + --- PASS: TestEnsureStream/Create_new_stream (0.00s) + --- PASS: TestEnsureStream/Get_existing_stream (0.00s) + --- PASS: TestEnsureStream/Create_stream_with_invalid_config (0.00s) +=== RUN TestConnectionEvents +natsjscm.ConnectionConfig{ + URL: "localhost:57904", + Options: []nats.Option{ + nats.Option, + }, + Logger: &natsjscm_test.mockLogger{}, + ReconnectWait: 100000000, + JetStreamDomain: "", +} +--- PASS: TestConnectionEvents (2.16s) +PASS +coverage: 4.8% of statements in ./... +ok github.com/simiancreative/simiango/messaging/natsjscm 5.468s coverage: 4.8% of statements in ./... +=== RUN TestNewHandler +=== RUN TestNewHandler/valid_configuration +=== RUN TestNewHandler/missing_jetstream +=== RUN TestNewHandler/missing_required_config +--- PASS: TestNewHandler (0.00s) + --- PASS: TestNewHandler/valid_configuration (0.00s) + --- PASS: TestNewHandler/missing_jetstream (0.00s) + --- PASS: TestNewHandler/missing_required_config (0.00s) +=== RUN TestHandlerPublishMessage +=== RUN TestHandlerPublishMessage/successful_publish +=== RUN TestHandlerPublishMessage/publish_with_no_headers +=== RUN TestHandlerPublishMessage/publish_error +--- PASS: TestHandlerPublishMessage (0.00s) + --- PASS: TestHandlerPublishMessage/successful_publish (0.00s) + --- PASS: TestHandlerPublishMessage/publish_with_no_headers (0.00s) + --- PASS: TestHandlerPublishMessage/publish_error (0.00s) +=== RUN TestHandlerShouldDLQ +=== RUN TestHandlerShouldDLQ/should_dlq_when_deliveries_exceeded +=== RUN TestHandlerShouldDLQ/should_not_dlq_when_under_max_deliveries +=== RUN TestHandlerShouldDLQ/should_not_dlq_on_metadata_error +--- PASS: TestHandlerShouldDLQ (0.00s) + --- PASS: TestHandlerShouldDLQ/should_dlq_when_deliveries_exceeded (0.00s) + --- PASS: TestHandlerShouldDLQ/should_not_dlq_when_under_max_deliveries (0.00s) + --- PASS: TestHandlerShouldDLQ/should_not_dlq_on_metadata_error (0.00s) +PASS +coverage: 3.4% of statements in ./... +ok github.com/simiancreative/simiango/messaging/natsjsdlq 2.691s coverage: 3.4% of statements in ./... +=== RUN TestID +--- PASS: TestID (0.00s) +=== RUN TestGetDurationMilliseconds +--- PASS: TestGetDurationMilliseconds (0.00s) +=== RUN TestRescuePanic +{"context":"test_context","level":"error","msg":"(Test panic) caused panic and was recovered","request_id":"test_id","stack":"/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.10.darwin-arm64/src/runtime/panic.go:770 (0x1023e1853)gopanic: fn()/Users/ross/code/simian/simiango/meta/rescue_test.go:20 (0x102c015ab)TestRescuePanic: panic(\"Test panic\")/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.10.darwin-arm64/src/testing/testing.go:1689 (0x102531ff3)tRunner: fn(t)/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.10.darwin-arm64/src/runtime/asm_arm64.s:1222 (0x102421113)goexit: MOVD\tR0, R0\t// NOP","time":"2025-03-03T09:34:49-05:00"} +--- PASS: TestRescuePanic (0.00s) +=== RUN TestGinRecovery +[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached. + +[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. + - using env: export GIN_MODE=release + - using code: gin.SetMode(gin.ReleaseMode) + +[GIN-debug] GET /test --> github.com/simiancreative/simiango/meta.TestGinRecovery.func2 (4 handlers) +[GIN] 2025/03/03 - 09:34:49 | 200 | 110.792µs | | GET "/test" +--- PASS: TestGinRecovery (0.00s) +=== RUN TestRecoverGinPanic +[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached. + +[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. + - using env: export GIN_MODE=release + - using code: gin.SetMode(gin.ReleaseMode) + +[GIN-debug] GET /test --> github.com/simiancreative/simiango/meta.TestRecoverGinPanic.func2 (4 handlers) +{"level":"error","msg":"Test error","request":["GET /test HTTP/1.1","",""],"request_id":null,"stack":["/Users/ross/code/simian/simiango/meta/rescue_test.go:49 (0x102c02717)","TestRecoverGinPanic.func1: panic(errors.New(\"Test error\"))","/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/github.com/gin-gonic/gin@v1.10.0/context.go:185 (0x102bcb30b)","(*Context).Next: c.handlers[c.index](c)","/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/github.com/gin-gonic/gin@v1.10.0/recovery.go:102 (0x102bcb29c)","CustomRecoveryWithWriter.func1: c.Next()","/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/github.com/gin-gonic/gin@v1.10.0/context.go:185 (0x102bca1fb)","(*Context).Next: c.handlers[c.index](c)","/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/github.com/gin-gonic/gin@v1.10.0/logger.go:249 (0x102bca19c)","LoggerWithConfig.func1: c.Next()","/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/github.com/gin-gonic/gin@v1.10.0/context.go:185 (0x102bc8eef)","(*Context).Next: c.handlers[c.index](c)","/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/github.com/gin-gonic/gin@v1.10.0/gin.go:633 (0x102bc89f4)","(*Engine).handleHTTPRequest: c.Next()","/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/github.com/gin-gonic/gin@v1.10.0/gin.go:589 (0x102bc8153)","(*Engine).ServeHTTP: engine.handleHTTPRequest(c)","/Users/ross/code/simian/simiango/meta/rescue_test.go:57 (0x102c01b3b)","TestRecoverGinPanic: r.ServeHTTP(w, req)","/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.10.darwin-arm64/src/testing/testing.go:1689 (0x102531ff3)","tRunner: fn(t)","/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.10.darwin-arm64/src/runtime/asm_arm64.s:1222 (0x102421113)","goexit: MOVD\tR0, R0\t// NOP"],"time":"2025-03-03T09:34:49-05:00"} +[GIN] 2025/03/03 - 09:34:49 | 200 | 1.346334ms | | GET "/test" +--- PASS: TestRecoverGinPanic (0.00s) +=== RUN TestRecoverGinPanic_BrokenPipe +[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached. + +[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. + - using env: export GIN_MODE=release + - using code: gin.SetMode(gin.ReleaseMode) + +[GIN-debug] GET /test --> github.com/simiancreative/simiango/meta.TestRecoverGinPanic_BrokenPipe.func2 (4 handlers) +{"level":"error","msg":": : broken pipe","request":["GET /test HTTP/1.1","",""],"request_id":null,"stack":["/Users/ross/code/simian/simiango/meta/rescue_test.go:72 (0x102c023eb)","TestRecoverGinPanic_BrokenPipe.func1: panic(\u0026net.OpError{Err: \u0026os.SyscallError{Err: errors.New(\"broken pipe\")}})","/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/github.com/gin-gonic/gin@v1.10.0/context.go:185 (0x102bcb30b)","(*Context).Next: c.handlers[c.index](c)","/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/github.com/gin-gonic/gin@v1.10.0/recovery.go:102 (0x102bcb29c)","CustomRecoveryWithWriter.func1: c.Next()","/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/github.com/gin-gonic/gin@v1.10.0/context.go:185 (0x102bca1fb)","(*Context).Next: c.handlers[c.index](c)","/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/github.com/gin-gonic/gin@v1.10.0/logger.go:249 (0x102bca19c)","LoggerWithConfig.func1: c.Next()","/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/github.com/gin-gonic/gin@v1.10.0/context.go:185 (0x102bc8eef)","(*Context).Next: c.handlers[c.index](c)","/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/github.com/gin-gonic/gin@v1.10.0/gin.go:633 (0x102bc89f4)","(*Engine).handleHTTPRequest: c.Next()","/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/github.com/gin-gonic/gin@v1.10.0/gin.go:589 (0x102bc8153)","(*Engine).ServeHTTP: engine.handleHTTPRequest(c)","/Users/ross/code/simian/simiango/meta/rescue_test.go:80 (0x102c01deb)","TestRecoverGinPanic_BrokenPipe: r.ServeHTTP(w, req)","/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.10.darwin-arm64/src/testing/testing.go:1689 (0x102531ff3)","tRunner: fn(t)","/Users/ross/.asdf/installs/golang/1.21.7/packages/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.10.darwin-arm64/src/runtime/asm_arm64.s:1222 (0x102421113)","goexit: MOVD\tR0, R0\t// NOP"],"time":"2025-03-03T09:34:49-05:00"} +[GIN] 2025/03/03 - 09:34:49 | 500 | 999.292µs | | GET "/test" +Error #01: : : broken pipe +--- PASS: TestRecoverGinPanic_BrokenPipe (0.00s) +=== RUN TestStack +--- PASS: TestStack (0.00s) +=== RUN TestStackAsBuf +--- PASS: TestStackAsBuf (0.00s) +=== RUN TestSource +--- PASS: TestSource (0.00s) +=== RUN TestFunction +--- PASS: TestFunction (0.00s) +PASS +coverage: 5.2% of statements in ./... +ok github.com/simiancreative/simiango/meta 3.400s coverage: 5.2% of statements in ./... +=== RUN TestAssignable +--- PASS: TestAssignable (0.00s) +PASS +coverage: 2.5% of statements in ./... +ok github.com/simiancreative/simiango/meta/assign 3.522s coverage: 2.5% of statements in ./... +=== RUN TestHandleError +=== RUN TestHandleError/With_nil_hub +=== RUN TestHandleError/With_scopeFunc +--- PASS: TestHandleError (0.00s) + --- PASS: TestHandleError/With_nil_hub (0.00s) + --- PASS: TestHandleError/With_scopeFunc (0.00s) +=== RUN TestGinCaptureError +=== RUN TestGinCaptureError/sentryScopeFunc_is_not_ok +--- PASS: TestGinCaptureError (0.00s) + --- PASS: TestGinCaptureError/sentryScopeFunc_is_not_ok (0.00s) +=== RUN TestScopeFunctionError +=== RUN TestScopeFunctionError/scopeFunction_is_not_ok +--- PASS: TestScopeFunctionError (0.00s) + --- PASS: TestScopeFunctionError/scopeFunction_is_not_ok (0.00s) +=== RUN TestEnable +=== RUN TestEnable/Missing_DSN +{"level":"warning","msg":"SENTRY_DSN is not set","time":"2025-03-03T09:34:50-05:00"} +=== RUN TestEnable/Init_error +{"level":"warning","msg":"Sentry initialization failed: [Sentry] DsnParseError: invalid scheme","time":"2025-03-03T09:34:50-05:00"} +=== RUN TestEnable/Valid_case +--- PASS: TestEnable (0.03s) + --- PASS: TestEnable/Missing_DSN (0.00s) + --- PASS: TestEnable/Init_error (0.03s) + --- PASS: TestEnable/Valid_case (0.00s) +=== RUN TestRecoverAndThrow +--- PASS: TestRecoverAndThrow (0.16s) +PASS +coverage: 3.7% of statements in ./... +ok github.com/simiancreative/simiango/monitoring/sentry 3.694s coverage: 3.7% of statements in ./... +=== RUN TestErrorMiddleware +=== RUN TestErrorMiddleware/no_errors +=== RUN TestErrorMiddleware/with_errors +--- PASS: TestErrorMiddleware (0.00s) + --- PASS: TestErrorMiddleware/no_errors (0.00s) + --- PASS: TestErrorMiddleware/with_errors (0.00s) +=== RUN TestParseRequest +--- PASS: TestParseRequest (0.00s) +=== RUN TestServiceResult +--- PASS: TestServiceResult (0.00s) +=== RUN TestServiceResultNilPointer +--- PASS: TestServiceResultNilPointer (0.00s) +=== RUN TestDirectService +--- PASS: TestDirectService (0.00s) +=== RUN TestParseBody +=== RUN TestParseBody/when_config.Input_is_nil +=== RUN TestParseBody/when_config.Input_is_not_nil_and_body_parsing_is_successful +=== RUN TestParseBody/when_config.Input_is_not_nil_and_body_parsing_fails +--- PASS: TestParseBody (0.00s) + --- PASS: TestParseBody/when_config.Input_is_nil (0.00s) + --- PASS: TestParseBody/when_config.Input_is_not_nil_and_body_parsing_is_successful (0.00s) + --- PASS: TestParseBody/when_config.Input_is_not_nil_and_body_parsing_fails (0.00s) +=== RUN TestUtilsHeaders +--- PASS: TestUtilsHeaders (0.00s) +=== RUN TestUtilsParams +--- PASS: TestUtilsParams (0.00s) +=== RUN TestHandleError +--- PASS: TestHandleError (0.00s) +=== RUN TestHandleErrorOK +--- PASS: TestHandleErrorOK (0.00s) +=== RUN TestHandleAfterPass +--- PASS: TestHandleAfterPass (0.00s) +=== RUN TestHandleAfterCall +--- PASS: TestHandleAfterCall (0.00s) +=== RUN TestHandleRecovery +--- PASS: TestHandleRecovery (0.00s) +=== RUN TestHandleErrorResp +--- PASS: TestHandleErrorResp (0.00s) +=== RUN TestHandleErrorRespNil +--- PASS: TestHandleErrorRespNil (0.00s) +=== RUN TestHandleErrorRespStatusLessThan500 +--- PASS: TestHandleErrorRespStatusLessThan500 (0.00s) +PASS +coverage: 5.1% of statements in ./... +ok github.com/simiancreative/simiango/server 3.888s coverage: 5.1% of statements in ./... +=== RUN TestToContentResponse +--- PASS: TestToContentResponse (0.00s) +=== RUN TestToContentResponseNotSlice +--- PASS: TestToContentResponseNotSlice (0.00s) +=== RUN TestToContentResponseTotalPages +--- PASS: TestToContentResponseTotalPages (0.00s) +=== RUN TestHeaders +--- PASS: TestHeaders (0.00s) +=== RUN TestRawParams +--- PASS: TestRawParams (0.00s) +=== RUN TestToResultError +--- PASS: TestToResultError (0.00s) +PASS +coverage: 4.1% of statements in ./... +ok github.com/simiancreative/simiango/service 4.074s coverage: 4.1% of statements in ./... +=== RUN TestCatchSig +{"level":"info","msg":"Sig: begin shutdown (interrupt)","time":"2025-03-03T09:34:52-05:00"} +{"level":"info","msg":"Sig: shutdown complete","time":"2025-03-03T09:34:52-05:00"} +--- PASS: TestCatchSig (1.00s) +PASS +coverage: 3.4% of statements in ./... +ok github.com/simiancreative/simiango/sig 5.338s coverage: 3.4% of statements in ./... +=== RUN TestStart +2025/03/03 09:34:52 INFO Starting DevServer ExePath /var/folders/50/3__098sx6p15jz_0m0yp3m_r0000gn/T/temporal-cli-go-sdk-1.31.0 Args [server start-dev --ip 127.0.0.1 --port 57916 --namespace default --dynamic-config-value frontend.enableServerVersionCheck=false --headless] +2025/03/03 09:34:52 INFO DevServer ready +{"level":"info","msg":"Started Worker[Namespace default TaskQueue startTest WorkerID 94877@Rosss-MacBook-Pro.local@]","time":"2025-03-03T09:34:52-05:00"} +{"level":"warning","msg":"Failed to poll for task.[Namespace default TaskQueue startTest WorkerID 94877@Rosss-MacBook-Pro.local@ WorkerType ActivityWorker Error grpc: the client connection is closing]","time":"2025-03-03T09:34:52-05:00"} +{"level":"warning","msg":"Failed to poll for task.[Namespace default TaskQueue startTest WorkerID 94877@Rosss-MacBook-Pro.local@ WorkerType WorkflowWorker Error grpc: the client connection is closing]","time":"2025-03-03T09:34:52-05:00"} +CLI 1.2.0 (Server 1.26.2, UI 2.34.0) + +Server: localhost:57916 +Metrics: http://localhost:57919/metrics +Stopping server... +time=2025-03-03T09:34:52.626 level=ERROR msg="service failures" operation=PollActivityTaskQueue wf-namespace=default grpc_code=Unavailable error="Frontend is not healthy yet" +time=2025-03-03T09:34:52.626 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=ActivityWorker Error="Frontend is not healthy yet" +time=2025-03-03T09:34:52.627 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=WorkflowWorker Error="last connection error: connection error: desc = \"transport: Error while dialing: dial tcp 127.0.0.1:57916: connect: connection refused\"" +time=2025-03-03T09:34:52.627 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=ActivityWorker Error="last connection error: connection error: desc = \"transport: Error while dialing: dial tcp 127.0.0.1:57916: connect: connection refused\"" +time=2025-03-03T09:34:53.627 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:57923 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:53.627 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:57923 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:53.627 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:57923 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:53.627 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:57923 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:53.627 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:57923 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:53.627 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:53.627 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:57923 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +--- PASS: TestStart (1.35s) +=== RUN TestSubmit +2025/03/03 09:34:53 INFO Starting DevServer ExePath /var/folders/50/3__098sx6p15jz_0m0yp3m_r0000gn/T/temporal-cli-go-sdk-1.31.0 Args [server start-dev --ip 127.0.0.1 --port 57945 --namespace default --dynamic-config-value frontend.enableServerVersionCheck=false --headless] +2025/03/03 09:34:53 INFO DevServer ready +{"level":"info","msg":"Started Worker[Namespace default TaskQueue unitTestModel WorkerID 94877@Rosss-MacBook-Pro.local@]","time":"2025-03-03T09:34:53-05:00"} +{"level":"debug","msg":"ExecuteActivity[Namespace default TaskQueue unitTestModel WorkerID 94877@Rosss-MacBook-Pro.local@ WorkflowType runner WorkflowID unitTestModel-1741012493 RunID 23895d7c-8070-4378-b7c7-c011457bb675 Attempt 1 ActivityID 5 ActivityType unitTestActivity]","time":"2025-03-03T09:34:53-05:00"} +{"level":"info","msg":"Stopped Worker[Namespace default TaskQueue unitTestModel WorkerID 94877@Rosss-MacBook-Pro.local@]","time":"2025-03-03T09:34:53-05:00"} +CLI 1.2.0 (Server 1.26.2, UI 2.34.0) + +Server: localhost:57945 +Metrics: http://localhost:57947/metrics +Stopping server... +time=2025-03-03T09:34:53.848 level=ERROR msg="service failures" operation=DescribeNamespace wf-namespace=default grpc_code=Unavailable error="Frontend is not healthy yet" +time=2025-03-03T09:34:53.848 level=ERROR msg="service failures" operation=PollWorkflowTaskQueue wf-namespace=default grpc_code=Unavailable error="Frontend is not healthy yet" +time=2025-03-03T09:34:53.849 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=WorkflowWorker Error="Frontend is not healthy yet" +time=2025-03-03T09:34:53.849 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=WorkflowWorker Error="last connection error: connection error: desc = \"transport: Error while dialing: dial tcp 127.0.0.1:57945: connect: connection refused\"" +time=2025-03-03T09:34:54.850 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:57951 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:54.850 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:57951 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:54.850 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:57951 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:54.850 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:57951 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:54.851 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:57951 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:54.851 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:57951 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +--- PASS: TestSubmit (1.23s) +=== RUN TestSubmit_NoModel +--- PASS: TestSubmit_NoModel (0.00s) +=== RUN TestClose +2025/03/03 09:34:54 INFO Starting DevServer ExePath /var/folders/50/3__098sx6p15jz_0m0yp3m_r0000gn/T/temporal-cli-go-sdk-1.31.0 Args [server start-dev --ip 127.0.0.1 --port 57974 --namespace default --dynamic-config-value frontend.enableServerVersionCheck=false --headless] +2025/03/03 09:34:54 INFO DevServer ready +CLI 1.2.0 (Server 1.26.2, UI 2.34.0) + +Server: localhost:57974 +Metrics: http://localhost:57976/metrics +Stopping server... +time=2025-03-03T09:34:55.098 level=ERROR msg="service failures" operation=PollActivityTaskQueue wf-namespace=default grpc_code=Unavailable error="Frontend is not healthy yet" +time=2025-03-03T09:34:55.099 level=ERROR msg="service failures" operation=PollWorkflowTaskQueue wf-namespace=default grpc_code=Unavailable error="Frontend is not healthy yet" +time=2025-03-03T09:34:55.099 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=WorkflowWorker Error="Frontend is not healthy yet" +time=2025-03-03T09:34:55.099 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=ActivityWorker Error="Frontend is not healthy yet" +time=2025-03-03T09:34:55.099 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=ActivityWorker Error="last connection error: connection error: desc = \"transport: Error while dialing: dial tcp 127.0.0.1:57974: connect: connection refused\"" +time=2025-03-03T09:34:55.280 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=WorkflowWorker Error="last connection error: connection error: desc = \"transport: Error while dialing: dial tcp 127.0.0.1:57974: connect: connection refused\"" +time=2025-03-03T09:34:56.102 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:57980 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:56.102 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:57980 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:56.102 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:56.102 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:57980 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:56.102 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:57980 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:56.102 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:57980 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:56.102 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:57980 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +--- PASS: TestClose (1.25s) +=== RUN TestSchedule +2025/03/03 09:34:56 INFO Starting DevServer ExePath /var/folders/50/3__098sx6p15jz_0m0yp3m_r0000gn/T/temporal-cli-go-sdk-1.31.0 Args [server start-dev --ip 127.0.0.1 --port 58001 --namespace default --dynamic-config-value frontend.enableServerVersionCheck=false --headless] +2025/03/03 09:34:56 INFO DevServer ready +CLI 1.2.0 (Server 1.26.2, UI 2.34.0) + +Server: localhost:58001 +Metrics: http://localhost:58003/metrics +Stopping server... +time=2025-03-03T09:34:56.347 level=ERROR msg="service failures" operation=PollActivityTaskQueue wf-namespace=default grpc_code=Unavailable error="Frontend is not healthy yet" +time=2025-03-03T09:34:56.347 level=ERROR msg="service failures" operation=PollWorkflowTaskQueue wf-namespace=default grpc_code=Unavailable error="Frontend is not healthy yet" +time=2025-03-03T09:34:56.348 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=WorkflowWorker Error="Frontend is not healthy yet" +time=2025-03-03T09:34:56.348 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=ActivityWorker Error="Frontend is not healthy yet" +time=2025-03-03T09:34:56.348 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=ActivityWorker Error="last connection error: connection error: desc = \"transport: Error while dialing: dial tcp 127.0.0.1:58001: connect: connection refused\"" +time=2025-03-03T09:34:56.549 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=WorkflowWorker Error="last connection error: connection error: desc = \"transport: Error while dialing: dial tcp 127.0.0.1:58001: connect: connection refused\"" +time=2025-03-03T09:34:57.349 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58007 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:57.349 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58007 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:57.349 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58007 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:57.350 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58007 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:57.350 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58007 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:57.350 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58007 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:57.351 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +--- PASS: TestSchedule (1.25s) +=== RUN TestScheduledConfigs +2025/03/03 09:34:57 INFO Starting DevServer ExePath /var/folders/50/3__098sx6p15jz_0m0yp3m_r0000gn/T/temporal-cli-go-sdk-1.31.0 Args [server start-dev --ip 127.0.0.1 --port 58027 --namespace default --dynamic-config-value frontend.enableServerVersionCheck=false --headless] +2025/03/03 09:34:57 INFO DevServer ready +CLI 1.2.0 (Server 1.26.2, UI 2.34.0) + +Server: localhost:58027 +Metrics: http://localhost:58030/metrics +Stopping server... +time=2025-03-03T09:34:57.598 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-dlq-activity-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local WorkerType=ActivityWorker Error="worker stopping" +time=2025-03-03T09:34:57.599 level=ERROR msg="service failures" operation=PollActivityTaskQueue wf-namespace=default grpc_code=Unavailable error="Frontend is not healthy yet" +time=2025-03-03T09:34:57.599 level=ERROR msg="service failures" operation=PollWorkflowTaskQueue wf-namespace=default grpc_code=Unavailable error="Frontend is not healthy yet" +time=2025-03-03T09:34:57.600 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=WorkflowWorker Error="Frontend is not healthy yet" +time=2025-03-03T09:34:57.600 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=ActivityWorker Error="Frontend is not healthy yet" +time=2025-03-03T09:34:57.600 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=ActivityWorker Error="last connection error: connection error: desc = \"transport: Error while dialing: dial tcp 127.0.0.1:58027: connect: connection refused\"" +time=2025-03-03T09:34:57.785 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=WorkflowWorker Error="last connection error: connection error: desc = \"transport: Error while dialing: dial tcp 127.0.0.1:58027: connect: connection refused\"" +time=2025-03-03T09:34:58.607 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:58.607 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58034 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:58.607 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58034 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:58.607 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58034 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:58.608 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58034 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:58.608 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58034 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:58.608 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58034 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +--- PASS: TestScheduledConfigs (1.26s) +=== RUN TestClient_HasModel +2025/03/03 09:34:58 INFO Starting DevServer ExePath /var/folders/50/3__098sx6p15jz_0m0yp3m_r0000gn/T/temporal-cli-go-sdk-1.31.0 Args [server start-dev --ip 127.0.0.1 --port 58057 --namespace default --dynamic-config-value frontend.enableServerVersionCheck=false --headless] +2025/03/03 09:34:58 INFO DevServer ready +CLI 1.2.0 (Server 1.26.2, UI 2.34.0) + +Server: localhost:58057 +Metrics: http://localhost:58059/metrics +Stopping server... +time=2025-03-03T09:34:59.862 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58063 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:59.862 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58063 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:59.862 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58063 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:59.863 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58063 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:59.863 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58063 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:59.863 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:59.864 level=WARN msg="Failed to poll for task." service=worker Namespace=default TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@default WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:34:59.862 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58063 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +--- PASS: TestClient_HasModel (1.26s) +=== RUN TestConnect +2025/03/03 09:34:59 INFO Starting DevServer ExePath /var/folders/50/3__098sx6p15jz_0m0yp3m_r0000gn/T/temporal-cli-go-sdk-1.31.0 Args [server start-dev --ip 127.0.0.1 --port 58085 --namespace default --dynamic-config-value frontend.enableServerVersionCheck=false --headless] +2025/03/03 09:34:59 INFO DevServer ready +CLI 1.2.0 (Server 1.26.2, UI 2.34.0) + +Server: localhost:58085 +Metrics: http://localhost:58087/metrics +Stopping server... +time=2025-03-03T09:35:01.119 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58091 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:01.121 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58091 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:01.121 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58091 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:01.121 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58091 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:01.121 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58091 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:01.121 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58091 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +--- PASS: TestConnect (1.25s) +=== RUN TestConnect_NoHost +--- PASS: TestConnect_NoHost (0.00s) +=== RUN TestConnect_DialError +--- PASS: TestConnect_DialError (0.06s) +=== RUN TestListen_FailedStart +2025/03/03 09:35:01 INFO Starting DevServer ExePath /var/folders/50/3__098sx6p15jz_0m0yp3m_r0000gn/T/temporal-cli-go-sdk-1.31.0 Args [server start-dev --ip 127.0.0.1 --port 58123 --namespace default --dynamic-config-value frontend.enableServerVersionCheck=false --headless] +2025/03/03 09:35:01 INFO DevServer ready +CLI 1.2.0 (Server 1.26.2, UI 2.34.0) + +Server: localhost:58123 +Metrics: http://localhost:58125/metrics +Stopping server... +time=2025-03-03T09:35:02.427 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58129 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:02.427 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58129 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:02.431 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58129 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:02.431 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58129 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:02.432 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58129 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:02.432 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58129 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +--- PASS: TestListen_FailedStart (11.25s) +=== RUN TestSubmit_FailedMarshal +--- PASS: TestSubmit_FailedMarshal (0.00s) +=== RUN TestSubmit_FailedExecute +2025/03/03 09:35:12 INFO Starting DevServer ExePath /var/folders/50/3__098sx6p15jz_0m0yp3m_r0000gn/T/temporal-cli-go-sdk-1.31.0 Args [server start-dev --ip 127.0.0.1 --port 58186 --namespace default --dynamic-config-value frontend.enableServerVersionCheck=false --headless] +2025/03/03 09:35:12 INFO DevServer ready +CLI 1.2.0 (Server 1.26.2, UI 2.34.0) + +Server: localhost:58186 +Metrics: http://localhost:58188/metrics +Stopping server... +time=2025-03-03T09:35:12.686 level=ERROR msg="service failures" operation=PollActivityTaskQueue wf-namespace=temporal-system grpc_code=Unavailable error="Frontend is not healthy yet" +time=2025-03-03T09:35:12.686 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@temporal-system WorkerType=WorkflowWorker Error="last connection error: connection error: desc = \"transport: Error while dialing: dial tcp 127.0.0.1:58186: connect: connection refused\"" +time=2025-03-03T09:35:12.686 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@temporal-system WorkerType=ActivityWorker Error="Frontend is not healthy yet" +time=2025-03-03T09:35:12.687 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@temporal-system WorkerType=ActivityWorker Error="last connection error: connection error: desc = \"transport: Error while dialing: dial tcp 127.0.0.1:58186: connect: connection refused\"" +time=2025-03-03T09:35:13.688 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58192 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:13.689 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58192 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:13.689 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58192 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:13.689 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58192 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:13.690 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58192 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:13.690 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58192 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:13.690 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-per-ns-tq WorkerID=temporal-system@Rosss-MacBook-Pro.local@temporal-system WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +--- PASS: TestSubmit_FailedExecute (11.26s) +=== RUN TestSubmit_WorkflowFailure +2025/03/03 09:35:23 INFO Starting DevServer ExePath /var/folders/50/3__098sx6p15jz_0m0yp3m_r0000gn/T/temporal-cli-go-sdk-1.31.0 Args [server start-dev --ip 127.0.0.1 --port 58236 --namespace default --dynamic-config-value frontend.enableServerVersionCheck=false --headless] +2025/03/03 09:35:23 INFO DevServer ready +{"level":"info","msg":"Started Worker[Namespace default TaskQueue 72ea94ac-de05-4595-8e20-78497f06e2ac WorkerID 94877@Rosss-MacBook-Pro.local@]","time":"2025-03-03T09:35:23-05:00"} +{"level":"warning","msg":"Failed to poll for task.[Namespace default TaskQueue 72ea94ac-de05-4595-8e20-78497f06e2ac WorkerID 94877@Rosss-MacBook-Pro.local@ WorkerType WorkflowWorker Error worker stopping]","time":"2025-03-03T09:35:23-05:00"} +{"level":"info","msg":"Stopped Worker[Namespace default TaskQueue 72ea94ac-de05-4595-8e20-78497f06e2ac WorkerID 94877@Rosss-MacBook-Pro.local@]","time":"2025-03-03T09:35:23-05:00"} +CLI 1.2.0 (Server 1.26.2, UI 2.34.0) + +Server: localhost:58236 +Metrics: http://localhost:58238/metrics +Stopping server... +time=2025-03-03T09:35:23.936 level=ERROR msg="service failures" operation=PollActivityTaskQueue wf-namespace=temporal-system grpc_code=Unavailable error="Frontend is not healthy yet" +time=2025-03-03T09:35:24.937 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58242 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:24.938 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58242 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:24.938 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58242 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:24.938 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58242 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:24.938 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58242 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:24.938 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58242 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +--- PASS: TestSubmit_WorkflowFailure (1.25s) +=== RUN TestSubmit_ActivityFailure +2025/03/03 09:35:24 INFO Starting DevServer ExePath /var/folders/50/3__098sx6p15jz_0m0yp3m_r0000gn/T/temporal-cli-go-sdk-1.31.0 Args [server start-dev --ip 127.0.0.1 --port 58262 --namespace default --dynamic-config-value frontend.enableServerVersionCheck=false --headless] +2025/03/03 09:35:25 INFO DevServer ready +{"level":"info","msg":"Started Worker[Namespace default TaskQueue 3cb6b718-9f13-4143-8008-29dc4806efd5 WorkerID 94877@Rosss-MacBook-Pro.local@]","time":"2025-03-03T09:35:25-05:00"} +{"level":"debug","msg":"ExecuteActivity[Namespace default TaskQueue 3cb6b718-9f13-4143-8008-29dc4806efd5 WorkerID 94877@Rosss-MacBook-Pro.local@ WorkflowType runner WorkflowID 3cb6b718-9f13-4143-8008-29dc4806efd5-1741012525 RunID b477963d-e1bb-4f3e-a8f8-6036caaad39d Attempt 1 ActivityID 5 ActivityType activity]","time":"2025-03-03T09:35:25-05:00"} +{"level":"error","msg":"Activity error.[Namespace default TaskQueue 3cb6b718-9f13-4143-8008-29dc4806efd5 WorkerID 94877@Rosss-MacBook-Pro.local@ WorkflowID 3cb6b718-9f13-4143-8008-29dc4806efd5-1741012525 RunID b477963d-e1bb-4f3e-a8f8-6036caaad39d ActivityType activity Attempt 1 Error activity failure]","time":"2025-03-03T09:35:25-05:00"} +{"level":"warning","msg":"Failed to poll for task.[Namespace default TaskQueue 3cb6b718-9f13-4143-8008-29dc4806efd5 WorkerID 94877@Rosss-MacBook-Pro.local@ WorkerType WorkflowWorker Error worker stopping]","time":"2025-03-03T09:35:25-05:00"} +{"level":"info","msg":"Stopped Worker[Namespace default TaskQueue 3cb6b718-9f13-4143-8008-29dc4806efd5 WorkerID 94877@Rosss-MacBook-Pro.local@]","time":"2025-03-03T09:35:25-05:00"} +CLI 1.2.0 (Server 1.26.2, UI 2.34.0) + +Server: localhost:58262 +Metrics: http://localhost:58265/metrics +Stopping server... +time=2025-03-03T09:35:26.189 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58269 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:26.189 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58269 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:26.189 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58269 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:26.190 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58269 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:26.190 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58269 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:26.190 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58269 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +--- PASS: TestSubmit_ActivityFailure (1.25s) +=== RUN TestSubmit_CustomWorkflow +2025/03/03 09:35:26 INFO Starting DevServer ExePath /var/folders/50/3__098sx6p15jz_0m0yp3m_r0000gn/T/temporal-cli-go-sdk-1.31.0 Args [server start-dev --ip 127.0.0.1 --port 58291 --namespace default --dynamic-config-value frontend.enableServerVersionCheck=false --headless] +2025/03/03 09:35:26 INFO DevServer ready +{"level":"info","msg":"Started Worker[Namespace default TaskQueue 3c2f4af1-54ed-4a63-b1e6-882323be994b WorkerID 94877@Rosss-MacBook-Pro.local@]","time":"2025-03-03T09:35:26-05:00"} +{"level":"debug","msg":"ExecuteActivity[Namespace default TaskQueue 3c2f4af1-54ed-4a63-b1e6-882323be994b WorkerID 94877@Rosss-MacBook-Pro.local@ WorkflowType runner WorkflowID 3c2f4af1-54ed-4a63-b1e6-882323be994b-1741012526 RunID f88f6297-f7ce-4f7d-8ed3-3244f74e4ada Attempt 1 ActivityID 5 ActivityType activity]","time":"2025-03-03T09:35:26-05:00"} +{"level":"warning","msg":"Failed to poll for task.[Namespace default TaskQueue 3c2f4af1-54ed-4a63-b1e6-882323be994b WorkerID 94877@Rosss-MacBook-Pro.local@ WorkerType WorkflowWorker Error worker stopping]","time":"2025-03-03T09:35:26-05:00"} +{"level":"info","msg":"Stopped Worker[Namespace default TaskQueue 3c2f4af1-54ed-4a63-b1e6-882323be994b WorkerID 94877@Rosss-MacBook-Pro.local@]","time":"2025-03-03T09:35:26-05:00"} +CLI 1.2.0 (Server 1.26.2, UI 2.34.0) + +Server: localhost:58291 +Metrics: http://localhost:58294/metrics +Stopping server... +time=2025-03-03T09:35:26.431 level=ERROR msg="service failures" operation=PollActivityTaskQueue wf-namespace=temporal-system grpc_code=Unavailable error="Frontend is not healthy yet" +time=2025-03-03T09:35:27.433 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58298 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:27.436 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58298 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:27.436 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58298 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:27.437 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58298 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:27.437 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58298 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:27.437 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58298 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +--- PASS: TestSubmit_CustomWorkflow (1.25s) +=== RUN TestSubmit_CustomWorkflowActivityFailure +2025/03/03 09:35:27 INFO Starting DevServer ExePath /var/folders/50/3__098sx6p15jz_0m0yp3m_r0000gn/T/temporal-cli-go-sdk-1.31.0 Args [server start-dev --ip 127.0.0.1 --port 58323 --namespace default --dynamic-config-value frontend.enableServerVersionCheck=false --headless] +2025/03/03 09:35:27 INFO DevServer ready +{"level":"info","msg":"Started Worker[Namespace default TaskQueue 440de023-1671-4091-805f-587846575319 WorkerID 94877@Rosss-MacBook-Pro.local@]","time":"2025-03-03T09:35:27-05:00"} +{"level":"debug","msg":"ExecuteActivity[Namespace default TaskQueue 440de023-1671-4091-805f-587846575319 WorkerID 94877@Rosss-MacBook-Pro.local@ WorkflowType runner WorkflowID 440de023-1671-4091-805f-587846575319-1741012527 RunID 4664f954-de4d-48db-aa3e-a99b9ff499f1 Attempt 1 ActivityID 5 ActivityType activity]","time":"2025-03-03T09:35:27-05:00"} +{"level":"error","msg":"Activity error.[Namespace default TaskQueue 440de023-1671-4091-805f-587846575319 WorkerID 94877@Rosss-MacBook-Pro.local@ WorkflowID 440de023-1671-4091-805f-587846575319-1741012527 RunID 4664f954-de4d-48db-aa3e-a99b9ff499f1 ActivityType activity Attempt 1 Error activity failure]","time":"2025-03-03T09:35:27-05:00"} +{"level":"warning","msg":"Failed to poll for task.[Namespace default TaskQueue 440de023-1671-4091-805f-587846575319 WorkerID 94877@Rosss-MacBook-Pro.local@ WorkerType WorkflowWorker Error worker stopping]","time":"2025-03-03T09:35:27-05:00"} +{"level":"info","msg":"Stopped Worker[Namespace default TaskQueue 440de023-1671-4091-805f-587846575319 WorkerID 94877@Rosss-MacBook-Pro.local@]","time":"2025-03-03T09:35:27-05:00"} +CLI 1.2.0 (Server 1.26.2, UI 2.34.0) + +Server: localhost:58323 +Metrics: http://localhost:58326/metrics +Stopping server... +time=2025-03-03T09:35:28.686 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58330 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:28.686 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58330 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:28.686 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58330 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:28.686 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58330 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:28.686 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58330 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:28.687 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58330 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +--- PASS: TestSubmit_CustomWorkflowActivityFailure (1.25s) +=== RUN TestRegister +--- PASS: TestRegister (0.00s) +=== RUN TestRegister_ErrorHandling +--- PASS: TestRegister_ErrorHandling (0.00s) +=== RUN TestScheduleConfig_Event +--- PASS: TestScheduleConfig_Event (0.00s) +=== RUN TestScheduleConfig_Name +--- PASS: TestScheduleConfig_Name (0.00s) +=== RUN TestScheduleConfigs_Add +--- PASS: TestScheduleConfigs_Add (0.00s) +=== RUN TestScheduleConfigs_Diff +--- PASS: TestScheduleConfigs_Diff (0.00s) +=== RUN TestScheduleConfigs_Contains +--- PASS: TestScheduleConfigs_Contains (0.00s) +=== RUN TestScheduleConfig_ParseMemo +--- PASS: TestScheduleConfig_ParseMemo (0.00s) +=== RUN TestScheduleConfig_ParseMemo_Error +--- PASS: TestScheduleConfig_ParseMemo_Error (0.00s) +=== RUN TestScheduleMigrate +2025/03/03 09:35:28 INFO Starting DevServer ExePath /var/folders/50/3__098sx6p15jz_0m0yp3m_r0000gn/T/temporal-cli-go-sdk-1.31.0 Args [server start-dev --ip 127.0.0.1 --port 58355 --namespace default --dynamic-config-value frontend.enableServerVersionCheck=false --headless] +2025/03/03 09:35:28 INFO DevServer ready +CLI 1.2.0 (Server 1.26.2, UI 2.34.0) + +Server: localhost:58355 +Metrics: http://localhost:58357/metrics +Stopping server... +time=2025-03-03T09:35:29.938 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58361 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:29.938 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58361 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:29.938 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58361 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:29.938 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58361 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:29.938 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58361 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:29.938 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58361 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +--- PASS: TestScheduleMigrate (1.25s) +=== RUN TestWorker +2025/03/03 09:35:29 INFO Starting DevServer ExePath /var/folders/50/3__098sx6p15jz_0m0yp3m_r0000gn/T/temporal-cli-go-sdk-1.31.0 Args [server start-dev --ip 127.0.0.1 --port 58391 --namespace default --dynamic-config-value frontend.enableServerVersionCheck=false --headless] +2025/03/03 09:35:30 INFO DevServer ready +=== RUN TestWorker/valid_process +{"level":"info","msg":"Started Worker[Namespace default TaskQueue 1d00b3cb-ad66-4645-b78a-7a724e76f673 WorkerID 94877@Rosss-MacBook-Pro.local@]","time":"2025-03-03T09:35:30-05:00"} +CLI 1.2.0 (Server 1.26.2, UI 2.34.0) + +Server: localhost:58391 +Metrics: http://localhost:58395/metrics +{"level":"warning","msg":"Failed to poll for task.[Namespace default TaskQueue 1d00b3cb-ad66-4645-b78a-7a724e76f673 WorkerID 94877@Rosss-MacBook-Pro.local@ WorkerType WorkflowWorker Error worker stopping]","time":"2025-03-03T09:35:31-05:00"} +{"level":"info","msg":"Stopped Worker[Namespace default TaskQueue 1d00b3cb-ad66-4645-b78a-7a724e76f673 WorkerID 94877@Rosss-MacBook-Pro.local@]","time":"2025-03-03T09:35:31-05:00"} +=== RUN TestWorker/invalid_workflow +=== RUN TestWorker/invalid_stream +Stopping server... +time=2025-03-03T09:35:32.085 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58399 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:32.085 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58399 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:32.085 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58399 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:32.085 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58399 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:32.085 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58399 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:32.085 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58399 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +--- PASS: TestWorker (2.15s) + --- PASS: TestWorker/valid_process (1.01s) + --- PASS: TestWorker/invalid_workflow (0.00s) + --- PASS: TestWorker/invalid_stream (0.00s) +=== RUN TestSchedules +2025/03/03 09:35:32 INFO Starting DevServer ExePath /var/folders/50/3__098sx6p15jz_0m0yp3m_r0000gn/T/temporal-cli-go-sdk-1.31.0 Args [server start-dev --ip 127.0.0.1 --port 58442 --namespace default --dynamic-config-value frontend.enableServerVersionCheck=false --headless] +2025/03/03 09:35:32 INFO DevServer ready +=== RUN TestSchedules/TestSchedule_ID +=== RUN TestSchedules/TestSchedule_Validate +=== RUN TestSchedules/TestSchedule_Remove +=== RUN TestSchedules/TestSchedule_Upsert +CLI 1.2.0 (Server 1.26.2, UI 2.34.0) + +Server: localhost:58442 +Metrics: http://localhost:58445/metrics +Stopping server... +time=2025-03-03T09:35:33.352 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58449 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:33.353 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58449 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:33.353 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58449 WorkerType=ActivityWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:33.353 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-history-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58449 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:33.353 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-tq-scanner-taskqueue-0 WorkerID=temporal-system@127.0.0.1:58449 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +time=2025-03-03T09:35:33.354 level=WARN msg="Failed to poll for task." service=worker Namespace=temporal-system TaskQueue=temporal-sys-processor-parent-close-policy WorkerID=temporal-system@127.0.0.1:58449 WorkerType=WorkflowWorker Error="closing transport due to: connection error: desc = \"error reading from server: EOF\", received prior goaway: code: NO_ERROR, debug data: \"graceful_stop\"" +--- PASS: TestSchedules (1.27s) + --- PASS: TestSchedules/TestSchedule_ID (0.00s) + --- PASS: TestSchedules/TestSchedule_Validate (0.00s) + --- PASS: TestSchedules/TestSchedule_Remove (0.01s) + --- PASS: TestSchedules/TestSchedule_Upsert (0.13s) +=== RUN TestRegisterActionsAsWorkfows +--- PASS: TestRegisterActionsAsWorkfows (0.00s) +=== RUN TestRegisterWorkflowAsWorkflow +--- PASS: TestRegisterWorkflowAsWorkflow (0.00s) +PASS +coverage: 14.8% of statements in ./... +ok github.com/simiancreative/simiango/temporal 44.965s coverage: 14.8% of statements in ./... +=== RUN TestTokenGenAndTest +--- PASS: TestTokenGenAndTest (0.00s) +=== RUN TestTokenDecode +--- PASS: TestTokenDecode (0.00s) +=== RUN TestTokenParse +--- PASS: TestTokenParse (0.00s) +=== RUN TestTokenTest +--- PASS: TestTokenTest (0.00s) +=== RUN TestExpiredToken +--- PASS: TestExpiredToken (0.00s) +PASS +coverage: 3.5% of statements in ./... +ok github.com/simiancreative/simiango/token 4.053s coverage: 3.5% of statements in ./... +=== RUN TestValidateSuccess +--- PASS: TestValidateSuccess (0.00s) +=== RUN TestValidateFailed +--- PASS: TestValidateFailed (0.00s) +=== RUN TestValidateResultError +--- PASS: TestValidateResultError (0.00s) +=== RUN TestValidateError +--- PASS: TestValidateError (0.00s) +=== RUN TestValid +--- PASS: TestValid (0.00s) +=== RUN TestAddValidation +--- PASS: TestAddValidation (0.00s) +PASS +coverage: 2.5% of statements in ./... +ok github.com/simiancreative/simiango/validate 4.020s coverage: 2.5% of statements in ./... +=== RUN TestExec +--- PASS: TestExec (0.00s) +=== RUN TestValidFlags +--- PASS: TestValidFlags (0.00s) +=== RUN TestFailedArgs +Error: failed to check args: Args/Flags not found for (invalid-args-tester:invalid-args) required args are: + +❌ test : test Description + +Usage: + workflows invalid-args-tester invalid-args [flags] + +Flags: + -h, --help help for invalid-args + --test string test Description + +--- PASS: TestFailedArgs (0.00s) +=== RUN TestSomeValidArgs +Error: failed to check args: Args/Flags not found for (some-valid-args:runner) required args are: + +✅ test : test Description +❌ test-two : test Description + +Usage: + workflows some-valid-args runner [flags] + +Flags: + -h, --help help for runner + --test string test Description + --test-two string test Description + +--- PASS: TestSomeValidArgs (0.00s) +=== RUN TestHandleError +Error: failed to run action: test error +--- PASS: TestHandleError (0.00s) +=== RUN TestMixOfFlagsAndPositional +--- PASS: TestMixOfFlagsAndPositional (0.00s) +=== RUN TestItemFromJSON +--- PASS: TestItemFromJSON (0.00s) +=== RUN TestItemFromJSONWithInvalidKey +--- PASS: TestItemFromJSONWithInvalidKey (0.00s) +=== RUN TestUnmarshalKey +--- PASS: TestUnmarshalKey (0.00s) +=== RUN TestUnmarshalKeyWithInvalidKey +--- PASS: TestUnmarshalKeyWithInvalidKey (0.00s) +PASS +coverage: 4.2% of statements in ./... +ok github.com/simiancreative/simiango/workflow 4.319s coverage: 4.2% of statements in ./...