2025-12-22 13:37:57 +08:00
|
|
|
|
package adapter
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"context"
|
|
|
|
|
|
"sync"
|
|
|
|
|
|
"testing"
|
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/ThreeDotsLabs/watermill/message"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 简单的测试日志适配器
|
|
|
|
|
|
type testLogger struct{}
|
|
|
|
|
|
|
|
|
|
|
|
func (t *testLogger) InfoContext(ctx context.Context, msg string, args ...interface{}) {}
|
|
|
|
|
|
func (t *testLogger) DebugContext(ctx context.Context, msg string, args ...interface{}) {}
|
|
|
|
|
|
func (t *testLogger) WarnContext(ctx context.Context, msg string, args ...interface{}) {}
|
|
|
|
|
|
func (t *testLogger) ErrorContext(ctx context.Context, msg string, args ...interface{}) {}
|
|
|
|
|
|
func (t *testLogger) Info(msg string, args ...interface{}) {}
|
|
|
|
|
|
func (t *testLogger) Debug(msg string, args ...interface{}) {}
|
|
|
|
|
|
func (t *testLogger) Warn(msg string, args ...interface{}) {}
|
|
|
|
|
|
func (t *testLogger) Error(msg string, args ...interface{}) {}
|
|
|
|
|
|
|
|
|
|
|
|
func TestTCPPublisherSubscriber_Integration(t *testing.T) {
|
|
|
|
|
|
testLogger := &testLogger{}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建 Subscriber
|
|
|
|
|
|
subscriberConfig := TCPSubscriberConfig{
|
|
|
|
|
|
ListenAddr: "127.0.0.1:18080",
|
|
|
|
|
|
}
|
|
|
|
|
|
subscriber, err := NewTCPSubscriber(subscriberConfig, testLogger)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatalf("Failed to create subscriber: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
defer subscriber.Close()
|
|
|
|
|
|
|
|
|
|
|
|
// 等待服务器启动
|
|
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
|
|
|
|
|
|
|
|
// 订阅 topic
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
topic := "test-topic"
|
|
|
|
|
|
msgChan, err := subscriber.Subscribe(ctx, topic)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatalf("Failed to subscribe: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建 Publisher
|
|
|
|
|
|
publisherConfig := TCPPublisherConfig{
|
|
|
|
|
|
ServerAddr: "127.0.0.1:18080",
|
|
|
|
|
|
ConnectTimeout: 5 * time.Second,
|
|
|
|
|
|
}
|
|
|
|
|
|
publisher, err := NewTCPPublisher(publisherConfig, testLogger)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatalf("Failed to create publisher: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
defer publisher.Close()
|
|
|
|
|
|
|
|
|
|
|
|
// 测试发送和接收消息
|
|
|
|
|
|
testPayload := []byte("Hello, TCP Watermill!")
|
|
|
|
|
|
testMsg := message.NewMessage("test-msg-1", testPayload)
|
|
|
|
|
|
|
|
|
|
|
|
// 启动接收协程
|
|
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
|
wg.Add(1)
|
|
|
|
|
|
go func() {
|
|
|
|
|
|
defer wg.Done()
|
|
|
|
|
|
select {
|
|
|
|
|
|
case receivedMsg := <-msgChan:
|
|
|
|
|
|
if string(receivedMsg.Payload) != string(testPayload) {
|
|
|
|
|
|
t.Errorf("Payload mismatch: got %s, want %s", receivedMsg.Payload, testPayload)
|
|
|
|
|
|
}
|
|
|
|
|
|
if receivedMsg.UUID != testMsg.UUID {
|
|
|
|
|
|
t.Errorf("UUID mismatch: got %s, want %s", receivedMsg.UUID, testMsg.UUID)
|
|
|
|
|
|
}
|
|
|
|
|
|
// ACK 消息
|
|
|
|
|
|
receivedMsg.Ack()
|
|
|
|
|
|
case <-time.After(5 * time.Second):
|
|
|
|
|
|
t.Error("Timeout waiting for message")
|
|
|
|
|
|
}
|
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
|
|
// 发送消息
|
|
|
|
|
|
err = publisher.Publish(topic, testMsg)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatalf("Failed to publish message: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 等待接收完成
|
|
|
|
|
|
wg.Wait()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func TestTCPPublisherSubscriber_MultipleMessages(t *testing.T) {
|
|
|
|
|
|
testLogger := &testLogger{}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建 Subscriber
|
|
|
|
|
|
subscriberConfig := TCPSubscriberConfig{
|
|
|
|
|
|
ListenAddr: "127.0.0.1:18081",
|
|
|
|
|
|
}
|
|
|
|
|
|
subscriber, err := NewTCPSubscriber(subscriberConfig, testLogger)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatalf("Failed to create subscriber: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
defer subscriber.Close()
|
|
|
|
|
|
|
|
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
|
|
|
|
|
|
|
|
// 订阅
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
topic := "test-topic-multi"
|
|
|
|
|
|
msgChan, err := subscriber.Subscribe(ctx, topic)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatalf("Failed to subscribe: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建 Publisher
|
|
|
|
|
|
publisherConfig := TCPPublisherConfig{
|
|
|
|
|
|
ServerAddr: "127.0.0.1:18081",
|
|
|
|
|
|
ConnectTimeout: 5 * time.Second,
|
|
|
|
|
|
}
|
|
|
|
|
|
publisher, err := NewTCPPublisher(publisherConfig, testLogger)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatalf("Failed to create publisher: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
defer publisher.Close()
|
|
|
|
|
|
|
|
|
|
|
|
// 准备多条消息
|
|
|
|
|
|
messageCount := 10
|
|
|
|
|
|
messages := make([]*message.Message, messageCount)
|
|
|
|
|
|
for i := 0; i < messageCount; i++ {
|
|
|
|
|
|
payload := []byte("Message " + string(rune('0'+i)))
|
|
|
|
|
|
messages[i] = message.NewMessage("msg-"+string(rune('0'+i)), payload)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 启动接收协程
|
|
|
|
|
|
receivedCount := 0
|
|
|
|
|
|
var mu sync.Mutex
|
|
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
|
|
|
|
|
|
|
for i := 0; i < messageCount; i++ {
|
|
|
|
|
|
wg.Add(1)
|
|
|
|
|
|
go func() {
|
|
|
|
|
|
defer wg.Done()
|
|
|
|
|
|
select {
|
|
|
|
|
|
case receivedMsg := <-msgChan:
|
|
|
|
|
|
mu.Lock()
|
|
|
|
|
|
receivedCount++
|
|
|
|
|
|
mu.Unlock()
|
|
|
|
|
|
receivedMsg.Ack()
|
|
|
|
|
|
case <-time.After(10 * time.Second):
|
|
|
|
|
|
t.Error("Timeout waiting for message")
|
|
|
|
|
|
}
|
|
|
|
|
|
}()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 发送消息(并发发送)
|
|
|
|
|
|
err = publisher.Publish(topic, messages...)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatalf("Failed to publish messages: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 等待接收完成
|
|
|
|
|
|
wg.Wait()
|
|
|
|
|
|
|
|
|
|
|
|
if receivedCount != messageCount {
|
|
|
|
|
|
t.Errorf("Received count mismatch: got %d, want %d", receivedCount, messageCount)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func TestTCPPublisherSubscriber_Nack(t *testing.T) {
|
|
|
|
|
|
testLogger := &testLogger{}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建 Subscriber
|
|
|
|
|
|
subscriberConfig := TCPSubscriberConfig{
|
|
|
|
|
|
ListenAddr: "127.0.0.1:18082",
|
|
|
|
|
|
}
|
|
|
|
|
|
subscriber, err := NewTCPSubscriber(subscriberConfig, testLogger)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatalf("Failed to create subscriber: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
defer subscriber.Close()
|
|
|
|
|
|
|
|
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
|
|
|
|
|
|
|
|
// 订阅
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
topic := "test-topic-nack"
|
|
|
|
|
|
msgChan, err := subscriber.Subscribe(ctx, topic)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatalf("Failed to subscribe: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建 Publisher
|
|
|
|
|
|
publisherConfig := TCPPublisherConfig{
|
|
|
|
|
|
ServerAddr: "127.0.0.1:18082",
|
|
|
|
|
|
ConnectTimeout: 5 * time.Second,
|
|
|
|
|
|
}
|
|
|
|
|
|
publisher, err := NewTCPPublisher(publisherConfig, testLogger)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatalf("Failed to create publisher: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
defer publisher.Close()
|
|
|
|
|
|
|
|
|
|
|
|
// 准备消息
|
|
|
|
|
|
testMsg := message.NewMessage("nack-test", []byte("This will be nacked"))
|
|
|
|
|
|
|
|
|
|
|
|
// 启动接收协程,这次 NACK
|
|
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
|
wg.Add(1)
|
|
|
|
|
|
go func() {
|
|
|
|
|
|
defer wg.Done()
|
|
|
|
|
|
select {
|
|
|
|
|
|
case receivedMsg := <-msgChan:
|
|
|
|
|
|
// NACK 消息
|
|
|
|
|
|
receivedMsg.Nack()
|
|
|
|
|
|
case <-time.After(5 * time.Second):
|
|
|
|
|
|
t.Error("Timeout waiting for message")
|
|
|
|
|
|
}
|
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
|
|
// 发送消息,由于不等待ACK,应该立即返回成功
|
|
|
|
|
|
// 注意:即使消费者NACK,发布者也会返回成功
|
|
|
|
|
|
err = publisher.Publish(topic, testMsg)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Errorf("Expected no error (fire-and-forget), got: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
wg.Wait()
|
|
|
|
|
|
}
|
2025-12-26 13:47:55 +08:00
|
|
|
|
|