@@ -11,6 +11,27 @@ import (
1111 "github.com/sipeed/picoclaw/pkg/cron"
1212)
1313
14+ type mockCronExecutor struct {
15+ response string
16+ err error
17+ calls int
18+ lastMsg string
19+ lastSess string
20+ lastChan string
21+ lastChat string
22+ }
23+
24+ func (m * mockCronExecutor ) ProcessDirectWithChannel (
25+ ctx context.Context , content , sessionKey , channel , chatID string ,
26+ ) (string , error ) {
27+ m .calls ++
28+ m .lastMsg = content
29+ m .lastSess = sessionKey
30+ m .lastChan = channel
31+ m .lastChat = chatID
32+ return m .response , m .err
33+ }
34+
1435func newTestCronTool (t * testing.T ) * CronTool {
1536 t .Helper ()
1637 storePath := filepath .Join (t .TempDir (), "cron.json" )
@@ -114,3 +135,76 @@ func TestCronTool_NonCommandJobAllowedFromRemoteChannel(t *testing.T) {
114135 t .Fatalf ("expected non-command reminder to succeed from remote channel, got: %s" , result .ForLLM )
115136 }
116137}
138+
139+ func TestCronTool_ExecuteJob_DeliverFalsePublishesAgentResponse (t * testing.T ) {
140+ storePath := filepath .Join (t .TempDir (), "cron.json" )
141+ cronService := cron .NewCronService (storePath , nil )
142+ msgBus := bus .NewMessageBus ()
143+ executor := & mockCronExecutor {response : "agent reply" }
144+ cfg := config .DefaultConfig ()
145+ tool , err := NewCronTool (cronService , executor , msgBus , t .TempDir (), true , 0 , cfg )
146+ if err != nil {
147+ t .Fatalf ("NewCronTool() error: %v" , err )
148+ }
149+
150+ job := & cron.CronJob {
151+ ID : "job-1" ,
152+ Payload : cron.CronPayload {
153+ Message : "summarize status" ,
154+ Deliver : false ,
155+ Channel : "telegram" ,
156+ To : "chat-42" ,
157+ },
158+ }
159+
160+ if got := tool .ExecuteJob (context .Background (), job ); got != "ok" {
161+ t .Fatalf ("ExecuteJob() = %q, want ok" , got )
162+ }
163+ if executor .calls != 1 {
164+ t .Fatalf ("executor calls = %d, want 1" , executor .calls )
165+ }
166+ if executor .lastSess != "cron-job-1" {
167+ t .Fatalf ("sessionKey = %q, want %q" , executor .lastSess , "cron-job-1" )
168+ }
169+
170+ msg , ok := msgBus .SubscribeOutbound (context .Background ())
171+ if ! ok {
172+ t .Fatal ("expected outbound message" )
173+ }
174+ if msg .Content != "agent reply" {
175+ t .Fatalf ("outbound content = %q, want %q" , msg .Content , "agent reply" )
176+ }
177+ if msg .Channel != "telegram" || msg .ChatID != "chat-42" {
178+ t .Fatalf ("unexpected destination: %+v" , msg )
179+ }
180+ }
181+
182+ func TestCronTool_ExecuteJob_DeliverFalseSkipsEmptyAgentResponse (t * testing.T ) {
183+ storePath := filepath .Join (t .TempDir (), "cron.json" )
184+ cronService := cron .NewCronService (storePath , nil )
185+ msgBus := bus .NewMessageBus ()
186+ executor := & mockCronExecutor {response : " " }
187+ cfg := config .DefaultConfig ()
188+ tool , err := NewCronTool (cronService , executor , msgBus , t .TempDir (), true , 0 , cfg )
189+ if err != nil {
190+ t .Fatalf ("NewCronTool() error: %v" , err )
191+ }
192+
193+ job := & cron.CronJob {
194+ ID : "job-2" ,
195+ Payload : cron.CronPayload {
196+ Message : "noop" ,
197+ Deliver : false ,
198+ },
199+ }
200+
201+ if got := tool .ExecuteJob (context .Background (), job ); got != "ok" {
202+ t .Fatalf ("ExecuteJob() = %q, want ok" , got )
203+ }
204+
205+ ctx , cancel := context .WithCancel (context .Background ())
206+ cancel ()
207+ if _ , ok := msgBus .SubscribeOutbound (ctx ); ok {
208+ t .Fatal ("did not expect outbound message for empty response" )
209+ }
210+ }
0 commit comments