113 lines
4.3 KiB
Go
113 lines
4.3 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
intentdomain "github.com/bridge/ai-customer-service/internal/domain/intent"
|
|
"github.com/bridge/ai-customer-service/internal/domain/message"
|
|
"github.com/bridge/ai-customer-service/internal/domain/platformevent"
|
|
"github.com/bridge/ai-customer-service/internal/platformadapter"
|
|
"github.com/bridge/ai-customer-service/internal/service/dialog"
|
|
"github.com/bridge/ai-customer-service/internal/service/handoff"
|
|
)
|
|
|
|
type stubPlatformDialogProcessor struct {
|
|
result *dialog.Result
|
|
err error
|
|
msg *message.UnifiedMessage
|
|
}
|
|
|
|
func (s *stubPlatformDialogProcessor) Process(_ context.Context, msg *message.UnifiedMessage) (*dialog.Result, error) {
|
|
s.msg = msg
|
|
if s.err != nil {
|
|
return nil, s.err
|
|
}
|
|
return s.result, nil
|
|
}
|
|
|
|
type stubPlatformEventWriter struct {
|
|
events []platformevent.Event
|
|
err error
|
|
}
|
|
|
|
func (s *stubPlatformEventWriter) InsertPendingBatch(_ context.Context, events []platformevent.Event) error {
|
|
s.events = append(s.events, events...)
|
|
return s.err
|
|
}
|
|
|
|
func TestPlatformWebhookHandler_ShouldEnqueueMessageReceivedAndReplyGenerated(t *testing.T) {
|
|
registry := platformadapter.NewRegistry(platformadapter.NewSub2APIAdapter())
|
|
processor := &stubPlatformDialogProcessor{result: &dialog.Result{SessionID: "sess-1", Reply: "好的", Intent: &intentdomain.Result{Intent: intentdomain.IntentRefund, Confidence: 0.9}}}
|
|
writer := &stubPlatformEventWriter{}
|
|
handler := NewPlatformWebhookHandler(processor, registry, writer)
|
|
|
|
body := `{"message_id":"m1","channel":"sub2api","open_id":"u1","content":"我要退款"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/customer-service/platforms/sub2api/webhook", strings.NewReader(body))
|
|
rr := httptest.NewRecorder()
|
|
handler.Handle(rr, req)
|
|
|
|
if rr.Code != http.StatusOK {
|
|
t.Fatalf("status = %d, want 200; body=%s", rr.Code, rr.Body.String())
|
|
}
|
|
if processor.msg == nil || processor.msg.OpenID != "u1" {
|
|
t.Fatalf("processor msg = %+v, want mapped message", processor.msg)
|
|
}
|
|
if !strings.Contains(rr.Body.String(), `"accepted":true`) {
|
|
t.Fatalf("response body = %s, want accepted=true", rr.Body.String())
|
|
}
|
|
if len(writer.events) != 4 {
|
|
t.Fatalf("events len = %d, want 4", len(writer.events))
|
|
}
|
|
if writer.events[0].EventType != platformevent.TypeMessageReceived {
|
|
t.Fatalf("first event type = %s", writer.events[0].EventType)
|
|
}
|
|
if writer.events[len(writer.events)-1].EventType != platformevent.TypeReplyGenerated {
|
|
t.Fatalf("last event type = %s", writer.events[len(writer.events)-1].EventType)
|
|
}
|
|
}
|
|
|
|
func TestPlatformWebhookHandler_ShouldEnqueueHandoffAndTicketCreatedWhenNeeded(t *testing.T) {
|
|
registry := platformadapter.NewRegistry(platformadapter.NewSub2APIAdapter())
|
|
processor := &stubPlatformDialogProcessor{result: &dialog.Result{
|
|
SessionID: "sess-1",
|
|
Reply: "已转人工",
|
|
Intent: &intentdomain.Result{Intent: intentdomain.IntentHandoff, Confidence: 0.88},
|
|
Handoff: &handoff.Decision{ShouldHandoff: true, Priority: "P1", Reason: "complaint"},
|
|
TicketID: "ticket-1",
|
|
}}
|
|
writer := &stubPlatformEventWriter{}
|
|
handler := NewPlatformWebhookHandler(processor, registry, writer)
|
|
|
|
body := `{"message_id":"m1","channel":"sub2api","open_id":"u1","content":"我要投诉"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/customer-service/platforms/sub2api/webhook", strings.NewReader(body))
|
|
rr := httptest.NewRecorder()
|
|
handler.Handle(rr, req)
|
|
|
|
if rr.Code != http.StatusOK {
|
|
t.Fatalf("status = %d, want 200; body=%s", rr.Code, rr.Body.String())
|
|
}
|
|
if len(writer.events) != 6 {
|
|
t.Fatalf("events len = %d, want 6", len(writer.events))
|
|
}
|
|
if writer.events[3].EventType != platformevent.TypeHandoffTriggered {
|
|
t.Fatalf("handoff event type = %s", writer.events[3].EventType)
|
|
}
|
|
if writer.events[4].EventType != platformevent.TypeTicketCreated {
|
|
t.Fatalf("ticket event type = %s", writer.events[4].EventType)
|
|
}
|
|
}
|
|
|
|
func TestPlatformWebhookHandler_ShouldRejectUnknownPlatform(t *testing.T) {
|
|
handler := NewPlatformWebhookHandler(&stubPlatformDialogProcessor{}, platformadapter.NewRegistry(platformadapter.NewSub2APIAdapter()), &stubPlatformEventWriter{})
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/customer-service/platforms/unknown/webhook", strings.NewReader(`{}`))
|
|
rr := httptest.NewRecorder()
|
|
handler.Handle(rr, req)
|
|
if rr.Code != http.StatusNotFound {
|
|
t.Fatalf("status = %d, want 404", rr.Code)
|
|
}
|
|
}
|