1+ package transaction
2+
3+ import (
4+ "bytes"
5+ "encoding/json"
6+ "net/http/httptest"
7+ "testing"
8+ "time"
9+
10+ "github.com/gin-gonic/gin"
11+ "github.com/langgenius/dify-plugin-daemon/internal/core/io_tunnel/backwards_invocation"
12+ "github.com/langgenius/dify-plugin-daemon/pkg/entities/plugin_entities"
13+ "github.com/langgenius/dify-plugin-daemon/pkg/utils/parser"
14+ )
15+
16+ func TestHandle_SessionNotFound_WritesErrorResponse (t * testing.T ) {
17+ gin .SetMode (gin .TestMode )
18+
19+ // Arrange: craft a valid PluginUniversalEvent that will trigger the session handler path
20+ // with a backwards_request_id extracted from SessionMessage.Data
21+ const (
22+ testSessionID = "test-session-not-exist"
23+ testBackwardsReqID = "req-123"
24+ )
25+
26+ invokePayload := map [string ]any {
27+ "backwards_request_id" : testBackwardsReqID ,
28+ }
29+ invokePayloadBytes := parser .MarshalJsonBytes (invokePayload )
30+
31+ sessionMsg := plugin_entities.SessionMessage {
32+ Type : plugin_entities .SESSION_MESSAGE_TYPE_INVOKE ,
33+ Data : invokePayloadBytes ,
34+ }
35+ sessionMsgBytes := parser .MarshalJsonBytes (sessionMsg )
36+
37+ event := plugin_entities.PluginUniversalEvent {
38+ SessionId : testSessionID ,
39+ Event : plugin_entities .PLUGIN_EVENT_SESSION ,
40+ Data : json .RawMessage (sessionMsgBytes ),
41+ }
42+ body := bytes .NewReader (parser .MarshalJsonBytes (event ))
43+
44+ recorder := httptest .NewRecorder ()
45+ ctx , _ := gin .CreateTestContext (recorder )
46+ ctx .Request = httptest .NewRequest ("POST" , "/serverless" , body )
47+
48+ h := NewServerlessTransactionHandler (2 * time .Second )
49+
50+ // Act: handle the request; since no session exists in memory and the cache client
51+ // is not initialized in tests, session_manager.GetSession will fail and the
52+ // error branch should write a BackwardsInvocationResponseEvent to the response.
53+ h .Handle (ctx , "ignored" )
54+
55+ // Assert
56+ var resp backwards_invocation.BackwardsInvocationResponseEvent
57+ if err := json .Unmarshal (recorder .Body .Bytes (), & resp ); err != nil {
58+ t .Fatalf ("response should be JSON BackwardsInvocationResponseEvent, got error: %v, body: %s" , err , recorder .Body .String ())
59+ }
60+
61+ if resp .Event != backwards_invocation .REQUEST_EVENT_ERROR {
62+ t .Fatalf ("expected event=error, got %q" , resp .Event )
63+ }
64+ if resp .Message != "failed to get session info from cache" {
65+ t .Fatalf ("expected message 'failed to get session info from cache', got %q" , resp .Message )
66+ }
67+ if resp .BackwardsRequestId != testBackwardsReqID {
68+ t .Fatalf ("expected backwards_request_id=%q, got %q" , testBackwardsReqID , resp .BackwardsRequestId )
69+ }
70+
71+ // Data should include error_type, detail, and session_id
72+ m , ok := resp .Data .(map [string ]any )
73+ if ! ok {
74+ // json.Unmarshal into interface{} yields map[string]any by default; if not, re-marshal and unmarshal to map
75+ raw := parser .MarshalJsonBytes (resp .Data )
76+ var tmp map [string ]any
77+ if err := json .Unmarshal (raw , & tmp ); err == nil {
78+ m = tmp
79+ } else {
80+ t .Fatalf ("response data should be an object: %v" , err )
81+ }
82+ }
83+
84+ if v , _ := m ["error_type" ].(string ); v != "SessionNotFound" {
85+ t .Fatalf ("expected data.error_type=SessionNotFound, got %v" , m ["error_type" ])
86+ }
87+ if v , _ := m ["session_id" ].(string ); v != testSessionID {
88+ t .Fatalf ("expected data.session_id=%q, got %v" , testSessionID , m ["session_id" ])
89+ }
90+ if v , _ := m ["detail" ].(string ); v == "" {
91+ t .Fatalf ("expected non-empty data.detail, got empty" )
92+ }
93+ }
0 commit comments