@@ -3,6 +3,7 @@ package tests
33import (
44 "encoding/json"
55 "fmt"
6+ "net"
67 "os"
78 "testing"
89 "time"
@@ -1533,3 +1534,124 @@ func TestTaskResultsEndToEnd(t *testing.T) {
15331534 t .Errorf ("expected result text, got %q" , string (data ))
15341535 }
15351536}
1537+
1538+ // TestTaskSubmitServerStandalone tests the standalone tasksubmit.Server.
1539+ func TestTaskSubmitServerStandalone (t * testing.T ) {
1540+ t .Parallel ()
1541+ env := NewTestEnv (t )
1542+
1543+ // Daemon A with built-in task submit DISABLED — we'll use the standalone server
1544+ a := env .AddDaemon (func (c * daemon.Config ) { c .DisableTaskSubmit = true })
1545+ b := env .AddDaemon ()
1546+
1547+ // Start standalone tasksubmit.Server on daemon A
1548+ accepted := make (chan * tasksubmit.SubmitRequest , 1 )
1549+ srv := tasksubmit .NewServer (a .Driver , func (conn net.Conn , req * tasksubmit.SubmitRequest ) bool {
1550+ accepted <- req
1551+ return true
1552+ })
1553+ go srv .ListenAndServe ()
1554+ time .Sleep (100 * time .Millisecond ) // wait for listen
1555+
1556+ // B submits a task to A via the tasksubmit client
1557+ client , err := tasksubmit .Dial (b .Driver , a .Daemon .Addr ())
1558+ if err != nil {
1559+ t .Fatalf ("dial: %v" , err )
1560+ }
1561+ defer client .Close ()
1562+
1563+ resp , err := client .SubmitTask ("standalone test task" , a .Daemon .Addr ().String ())
1564+ if err != nil {
1565+ t .Fatalf ("submit: %v" , err )
1566+ }
1567+ if resp .Status != tasksubmit .StatusAccepted {
1568+ t .Errorf ("expected accepted, got status %d" , resp .Status )
1569+ }
1570+ t .Logf ("response: status=%d message=%q" , resp .Status , resp .Message )
1571+
1572+ // Verify handler received the request
1573+ select {
1574+ case req := <- accepted :
1575+ if req .TaskDescription != "standalone test task" {
1576+ t .Errorf ("expected description, got %q" , req .TaskDescription )
1577+ }
1578+ t .Logf ("handler received: %q" , req .TaskDescription )
1579+ case <- time .After (3 * time .Second ):
1580+ t .Fatal ("handler did not receive request" )
1581+ }
1582+ }
1583+
1584+ // TestCalculateTimeStagedEdgeCases tests empty/invalid inputs for CalculateTimeStaged.
1585+ func TestCalculateTimeStagedEdgeCases (t * testing.T ) {
1586+ t .Parallel ()
1587+
1588+ // Empty StagedAt — should be a no-op
1589+ tf := & tasksubmit.TaskFile {TaskID : "calc-staged-empty" }
1590+ tf .CalculateTimeStaged ()
1591+ if tf .ExecuteStartedAt != "" {
1592+ t .Errorf ("expected empty ExecuteStartedAt for empty StagedAt, got %q" , tf .ExecuteStartedAt )
1593+ }
1594+ if tf .TimeStagedMs != 0 {
1595+ t .Errorf ("expected zero TimeStagedMs for empty StagedAt, got %d" , tf .TimeStagedMs )
1596+ }
1597+
1598+ // Invalid StagedAt — should be a no-op
1599+ tf2 := & tasksubmit.TaskFile {TaskID : "calc-staged-invalid" , StagedAt : "not-a-date" }
1600+ tf2 .CalculateTimeStaged ()
1601+ if tf2 .ExecuteStartedAt != "" {
1602+ t .Error ("expected empty ExecuteStartedAt for invalid StagedAt" )
1603+ }
1604+ }
1605+
1606+ // TestCalculateTimeCpuEdgeCases tests empty/invalid inputs for CalculateTimeCpu.
1607+ func TestCalculateTimeCpuEdgeCases (t * testing.T ) {
1608+ t .Parallel ()
1609+
1610+ // Empty ExecuteStartedAt — should be a no-op
1611+ tf := & tasksubmit.TaskFile {TaskID : "calc-cpu-empty" }
1612+ tf .CalculateTimeCpu ()
1613+ if tf .CompletedAt != "" {
1614+ t .Errorf ("expected empty CompletedAt for empty ExecuteStartedAt, got %q" , tf .CompletedAt )
1615+ }
1616+ if tf .TimeCpuMs != 0 {
1617+ t .Errorf ("expected zero TimeCpuMs for empty ExecuteStartedAt, got %d" , tf .TimeCpuMs )
1618+ }
1619+
1620+ // Invalid ExecuteStartedAt — should be a no-op
1621+ tf2 := & tasksubmit.TaskFile {TaskID : "calc-cpu-invalid" , ExecuteStartedAt : "garbage" }
1622+ tf2 .CalculateTimeCpu ()
1623+ if tf2 .CompletedAt != "" {
1624+ t .Error ("expected empty CompletedAt for invalid ExecuteStartedAt" )
1625+ }
1626+ }
1627+
1628+ // TestTaskSubmitServerReject tests the standalone server rejection path.
1629+ func TestTaskSubmitServerReject (t * testing.T ) {
1630+ t .Parallel ()
1631+ env := NewTestEnv (t )
1632+
1633+ a := env .AddDaemon (func (c * daemon.Config ) { c .DisableTaskSubmit = true })
1634+ b := env .AddDaemon ()
1635+
1636+ // Server that always rejects
1637+ srv := tasksubmit .NewServer (a .Driver , func (conn net.Conn , req * tasksubmit.SubmitRequest ) bool {
1638+ return false
1639+ })
1640+ go srv .ListenAndServe ()
1641+ time .Sleep (100 * time .Millisecond )
1642+
1643+ client , err := tasksubmit .Dial (b .Driver , a .Daemon .Addr ())
1644+ if err != nil {
1645+ t .Fatalf ("dial: %v" , err )
1646+ }
1647+ defer client .Close ()
1648+
1649+ resp , err := client .SubmitTask ("reject me" , a .Daemon .Addr ().String ())
1650+ if err != nil {
1651+ t .Fatalf ("submit: %v" , err )
1652+ }
1653+ if resp .Status != tasksubmit .StatusRejected {
1654+ t .Errorf ("expected rejected (status %d), got %d" , tasksubmit .StatusRejected , resp .Status )
1655+ }
1656+ t .Logf ("rejection response: status=%d message=%q" , resp .Status , resp .Message )
1657+ }
0 commit comments