Files
tasks/tools/tdbg/dlq_service_test.go
Alex ShtinandGitHub 8e8f1b0f7c Remove license header from every file (#7689)
## What changed?
<!-- Describe what has changed in this PR -->
Remove license header from every file. Because it is really hard to
follow in this PR here is the summary:
1. License header is removed from all `.go` and `.proto` files
:fireworks::fireworks:🎆.
2. `LICENSE` file in the root directory has only Temporal and Uber
copyrights.
3. 5 other `LICENSE` files added to the packages which have copyrights
different from Temporal and Uber: Datadog, Xargin, "Mat Ryer, Tyler
Bunnell and contributors".
4. `license_file` flag is removed from all code generation tools.
5. `copyright_file` flag is removed from `go:generate mockgen`
directive.
6. All copyright related targets are removed from `Makefile`.
7. Updated Temporal copyright year to 2025 everywhere.

## Why?
<!-- Tell your future self why have you made these changes -->
I double checked with legal department that it is not needed to have
license header in every file. One file per repo is enough. I put all
copyrights to the root `LICENSE` file and removed header from all other
files. Also updated tools and `Makefile`.
2025-05-01 18:50:21 -07:00

360 lines
10 KiB
Go

package tdbg_test
import (
"bytes"
"context"
"errors"
"fmt"
"strconv"
"testing"
"github.com/stretchr/testify/assert"
"github.com/urfave/cli/v2"
"go.temporal.io/api/workflowservice/v1"
"go.temporal.io/server/api/adminservice/v1"
"go.temporal.io/server/service/history/tasks"
"go.temporal.io/server/tools/tdbg"
"go.temporal.io/server/tools/tdbg/tdbgtest"
"google.golang.org/grpc"
)
type (
dlqTestParams struct {
dlqVersion string
command string
dlqType string
sourceCluster string
targetCluster string
maxMessageCount string
lastMessageID string
outputFileName string
adminClient *fakeAdminClient
clientFactory tdbg.ClientFactory
// expectedErrSubstrings is a list of substrings that are expected to be found in the error message. We don't use an
// exact error message to prevent this from becoming a change-detector test.
expectedErrSubstrings []string
}
dlqTestCase struct {
name string
version string
override func(p *dlqTestParams)
validateStdout func(t *testing.T, b *bytes.Buffer)
validateStderr func(t *testing.T, b *bytes.Buffer)
}
fakeClientFactory struct {
adminClient adminservice.AdminServiceClient
}
fakeAdminClient struct {
adminservice.AdminServiceClient
err error
// ListQueues
nextListQueueResponse int
previousPageToken []byte
listQueueResponses []*adminservice.ListQueuesResponse
}
)
func (tc *dlqTestCase) Run(t *testing.T) {
faultyAdminClient := &fakeAdminClient{err: errors.New("did not expect client to be used")}
p := dlqTestParams{
dlqVersion: tc.version,
dlqType: strconv.Itoa(tasks.CategoryTransfer.ID()),
sourceCluster: "test-source-cluster",
targetCluster: "test-target-cluster",
maxMessageCount: "",
lastMessageID: "",
outputFileName: "",
expectedErrSubstrings: nil,
adminClient: faultyAdminClient,
clientFactory: fakeClientFactory{adminClient: faultyAdminClient},
}
tc.override(&p)
var stdout, stderr bytes.Buffer
app := tdbgtest.NewCliApp(func(params *tdbg.Params) {
params.ClientFactory = p.clientFactory
params.Writer = &stdout
params.ErrWriter = &stderr
})
runArgs := []string{
"tdbg",
"--" + tdbg.FlagYes,
"dlq",
}
runArgs = appendArg(runArgs, tdbg.FlagDLQVersion, p.dlqVersion)
runArgs = append(runArgs, p.command)
if p.command != "list" {
runArgs = appendArg(runArgs, tdbg.FlagDLQType, p.dlqType)
runArgs = appendArg(runArgs, tdbg.FlagCluster, p.sourceCluster)
runArgs = appendArg(runArgs, tdbg.FlagTargetCluster, p.targetCluster)
runArgs = appendArg(runArgs, tdbg.FlagMaxMessageCount, p.maxMessageCount)
runArgs = appendArg(runArgs, tdbg.FlagLastMessageID, p.lastMessageID)
}
runArgs = appendArg(runArgs, tdbg.FlagOutputFilename, p.outputFileName)
t.Logf("Running %v", runArgs)
err := app.Run(runArgs)
if len(p.expectedErrSubstrings) > 0 {
assert.Error(t, err, "Expected error to contain %v", p.expectedErrSubstrings)
for _, s := range p.expectedErrSubstrings {
assert.ErrorContains(t, err, s)
}
} else {
assert.NoError(t, err)
}
if tc.validateStdout != nil {
tc.validateStdout(t, &stdout)
}
if tc.validateStderr != nil {
tc.validateStderr(t, &stderr)
}
}
func TestDLQCommand_V2(t *testing.T) {
for _, tc := range []dlqTestCase{
{
name: "read no target cluster with faulty admin client",
override: func(p *dlqTestParams) {
p.command = "read"
p.targetCluster = ""
p.adminClient.err = errors.New("some error")
p.expectedErrSubstrings = []string{tdbg.FlagTargetCluster, "DescribeCluster", "some error"}
},
},
{
name: "read no source cluster for replication task",
override: func(p *dlqTestParams) {
p.command = "read"
p.sourceCluster = ""
p.dlqType = strconv.Itoa(tasks.CategoryReplication.ID())
p.expectedErrSubstrings = []string{tdbg.FlagCluster, "replication", "source cluster"}
},
},
{
name: "read category is not an integer",
override: func(p *dlqTestParams) {
p.command = "read"
p.dlqType = "my-string"
p.expectedErrSubstrings = []string{"category", "integer", "my-string"}
},
},
{
name: "read invalid category",
override: func(p *dlqTestParams) {
p.command = "read"
p.dlqType = "-1"
p.expectedErrSubstrings = []string{"category", "-1"}
},
},
{
name: "zero max message count",
override: func(p *dlqTestParams) {
p.command = "read"
p.maxMessageCount = "0"
p.expectedErrSubstrings = []string{tdbg.FlagMaxMessageCount, "positive", "0"}
},
},
{
name: "last message ID is less than first possible message ID",
override: func(p *dlqTestParams) {
p.command = "read"
p.lastMessageID = "-1"
p.expectedErrSubstrings = []string{tdbg.FlagLastMessageID, "at least", "0"}
},
},
{
name: "last message ID is less than first possible message ID",
override: func(p *dlqTestParams) {
p.command = "read"
p.lastMessageID = "-1"
p.expectedErrSubstrings = []string{tdbg.FlagLastMessageID, "at least", "0"}
},
},
{
name: "invalid output file name",
override: func(p *dlqTestParams) {
p.command = "read"
p.outputFileName = "\\0/"
p.expectedErrSubstrings = []string{"output file", "\\0/"}
},
},
{
name: "GetDLQTasks error",
override: func(p *dlqTestParams) {
p.command = "read"
p.adminClient.err = errors.New("some error")
p.expectedErrSubstrings = []string{"some error", "GetDLQTasks"}
},
},
{
name: "GetDLQTasks on empty queue",
override: func(p *dlqTestParams) {
p.command = "read"
p.dlqType = "1"
p.adminClient.err = errors.New(" GetDLQTasks failed. Error: queue not found:")
},
},
{
name: "purge invalid last message ID",
override: func(p *dlqTestParams) {
p.command = "purge"
p.lastMessageID = "-1"
p.expectedErrSubstrings = []string{tdbg.FlagLastMessageID, "at least", "0"}
},
},
{
name: "purge client err",
override: func(p *dlqTestParams) {
p.command = "purge"
p.adminClient.err = errors.New("some error")
p.expectedErrSubstrings = []string{"some error", "PurgeDLQTasks"}
},
},
{
name: "merge invalid last message ID",
override: func(p *dlqTestParams) {
p.command = "merge"
p.lastMessageID = "-1"
p.expectedErrSubstrings = []string{tdbg.FlagLastMessageID, "at least", "0"}
},
},
{
name: "merge client err",
override: func(p *dlqTestParams) {
p.command = "merge"
p.adminClient.err = errors.New("some error")
p.expectedErrSubstrings = []string{"some error", "MergeDLQTasks"}
},
},
{
name: "list no queues",
override: func(p *dlqTestParams) {
p.adminClient.err = nil
p.command = "list"
},
},
{
name: "list queues, paginated",
override: func(p *dlqTestParams) {
p.adminClient.err = nil
p.command = "list"
p.adminClient.listQueueResponses = []*adminservice.ListQueuesResponse{
{
Queues: []*adminservice.ListQueuesResponse_QueueInfo{
{
QueueName: "queueOne",
MessageCount: 13,
}, {
QueueName: "queueTwo",
MessageCount: 42,
},
},
NextPageToken: []byte{0x41, 0x41, 0x41},
}, {
Queues: []*adminservice.ListQueuesResponse_QueueInfo{
{
QueueName: "queueThree",
MessageCount: 0,
},
},
NextPageToken: nil,
},
}
},
validateStdout: func(t *testing.T, b *bytes.Buffer) {
// One line per queue. For my own sanity we just expect them all to exist; I'm not validating formatting or order here
patterns := []string{`queueOne\s.*?|\s*13\b`, `queueTwo\s.*?|\s*42\b`, `queueThree\s.*?|\s*0\b`}
for _, p := range patterns {
assert.Regexp(t, p, b.String())
}
},
},
} {
t.Run(tc.name, func(t *testing.T) {
tc.version = "v2"
tc.Run(t)
})
}
}
func (f fakeClientFactory) WorkflowClient(*cli.Context) workflowservice.WorkflowServiceClient {
panic("not implemented")
}
func (f fakeClientFactory) AdminClient(*cli.Context) adminservice.AdminServiceClient {
return f.adminClient
}
// The fake admin client accepts and returns canned responses
// It tracks whether the correct page token is passed in the request when iterating
func (f *fakeAdminClient) ListQueues(_ context.Context, req *adminservice.ListQueuesRequest, _ ...grpc.CallOption) (*adminservice.ListQueuesResponse, error) {
if f.err != nil {
return nil, f.err
}
if f.nextListQueueResponse >= len(f.listQueueResponses) {
return &adminservice.ListQueuesResponse{}, nil
}
if bytes.Compare(f.previousPageToken, req.NextPageToken) != 0 {
return nil, fmt.Errorf("expected page token %v, got %v", f.previousPageToken, req.NextPageToken)
}
resp := f.listQueueResponses[f.nextListQueueResponse]
f.nextListQueueResponse++
f.previousPageToken = resp.NextPageToken
return resp, nil
}
func (f *fakeAdminClient) DescribeCluster(
context.Context,
*adminservice.DescribeClusterRequest,
...grpc.CallOption,
) (*adminservice.DescribeClusterResponse, error) {
if f.err != nil {
return nil, f.err
}
// We _must_ return a non-nil result if the error isn't nil
return &adminservice.DescribeClusterResponse{}, nil
}
func (f *fakeAdminClient) GetDLQTasks(
context.Context,
*adminservice.GetDLQTasksRequest,
...grpc.CallOption,
) (*adminservice.GetDLQTasksResponse, error) {
if f.err != nil {
return nil, f.err
}
return &adminservice.GetDLQTasksResponse{}, nil
}
func (f *fakeAdminClient) PurgeDLQTasks(
context.Context,
*adminservice.PurgeDLQTasksRequest,
...grpc.CallOption,
) (*adminservice.PurgeDLQTasksResponse, error) {
if f.err != nil {
return nil, f.err
}
return &adminservice.PurgeDLQTasksResponse{}, nil
}
func (f *fakeAdminClient) MergeDLQTasks(
context.Context,
*adminservice.MergeDLQTasksRequest,
...grpc.CallOption,
) (*adminservice.MergeDLQTasksResponse, error) {
if f.err != nil {
return nil, f.err
}
return &adminservice.MergeDLQTasksResponse{}, nil
}
func appendArg(args []string, name string, val string) []string {
if val == "" {
return args
}
return append(args, "--"+name, val)
}