Skip to content

Commit 97a214e

Browse files
committed
Test coverage push #4: 79% → 79.5%
Add 18 new tests across 3 test files: - ipc_ops_test: SetTags error paths, beacon register/list, registry operations, daemon custom config, IPC after deregister - handshake_test: trust persistence load/verify, trust load from disk - tasksubmit_test: unmarshal type mismatches, frame read/write round-trips, oversized frame rejection, status update and result message marshaling, TaskFile time utility edge cases Remove dead RecvResult from tasksubmit client. Key coverage improvements: - handleBeaconRegister: 0% → 100% - handleBeaconList: 0% → 100% - loadTrust: 25% → 81% - handleSetTags: 55% → 75% - handleSetHostname: 71% → 82% - handleSetTaskExec: 59% → 71%
1 parent a6bcf2e commit 97a214e

4 files changed

Lines changed: 691 additions & 9 deletions

File tree

pkg/tasksubmit/client.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,6 @@ func (c *Client) SendResults(msg *TaskResultMessage) error {
7676
return WriteFrame(c.conn, frame)
7777
}
7878

79-
// RecvResult reads a task result from the connection.
80-
func (c *Client) RecvResult() (*TaskResult, error) {
81-
frame, err := ReadFrame(c.conn)
82-
if err != nil {
83-
return nil, err
84-
}
85-
return UnmarshalTaskResult(frame)
86-
}
87-
8879
// Close closes the connection.
8980
func (c *Client) Close() error {
9081
return c.conn.Close()

tests/handshake_test.go

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package tests
22

33
import (
4+
"encoding/json"
45
"os"
56
"path/filepath"
67
"testing"
@@ -564,5 +565,195 @@ func TestHandshakeRejectReason(t *testing.T) {
564565
t.Log("reject with reason succeeded, pending cleared")
565566
}
566567

568+
// TestHandshakeTrustLoadVerify tests that loadTrust correctly populates trust state from file.
569+
func TestHandshakeTrustLoadVerify(t *testing.T) {
570+
t.Parallel()
571+
env := NewTestEnv(t)
572+
573+
identityDir := t.TempDir()
574+
identityPath := filepath.Join(identityDir, "identity.json")
575+
trustPath := filepath.Join(identityDir, "trust.json")
576+
577+
infoA := env.AddDaemon(func(c *daemon.Config) {
578+
c.Encrypt = true
579+
c.IdentityPath = identityPath
580+
})
581+
infoB := env.AddDaemon(func(c *daemon.Config) {
582+
c.Encrypt = true
583+
c.IdentityPath = filepath.Join(t.TempDir(), "identity.json")
584+
})
585+
586+
drvA := infoA.Driver
587+
drvB := infoB.Driver
588+
589+
// Establish mutual trust
590+
drvA.Handshake(infoB.Daemon.NodeID(), "persist-load")
591+
592+
deadline := time.After(5 * time.Second)
593+
for {
594+
pending, _ := drvB.PendingHandshakes()
595+
if pl, _ := pending["pending"].([]interface{}); len(pl) > 0 {
596+
break
597+
}
598+
select {
599+
case <-deadline:
600+
t.Fatal("timed out waiting for handshake")
601+
case <-time.After(10 * time.Millisecond):
602+
}
603+
}
604+
605+
drvB.Handshake(infoA.Daemon.NodeID(), "persist-load-back")
606+
607+
// Wait for mutual trust
608+
deadline = time.After(5 * time.Second)
609+
for {
610+
trustA, _ := drvA.TrustedPeers()
611+
trustedA, _ := trustA["trusted"].([]interface{})
612+
if len(trustedA) > 0 {
613+
break
614+
}
615+
select {
616+
case <-deadline:
617+
t.Fatal("timed out waiting for trust")
618+
case <-time.After(10 * time.Millisecond):
619+
}
620+
}
621+
622+
// Verify trust file was created and contains correct data
623+
data, err := os.ReadFile(trustPath)
624+
if err != nil {
625+
t.Fatalf("read trust file: %v", err)
626+
}
627+
628+
var snap struct {
629+
Trusted []struct {
630+
NodeID uint32 `json:"node_id"`
631+
PublicKey string `json:"public_key"`
632+
ApprovedAt string `json:"approved_at"`
633+
Mutual bool `json:"mutual"`
634+
} `json:"trusted"`
635+
Pending []struct {
636+
NodeID uint32 `json:"node_id"`
637+
} `json:"pending"`
638+
}
639+
if err := json.Unmarshal(data, &snap); err != nil {
640+
t.Fatalf("unmarshal trust file: %v", err)
641+
}
642+
643+
if len(snap.Trusted) == 0 {
644+
t.Fatal("trust file should have at least one trusted peer")
645+
}
646+
647+
// Verify B's node ID is in the trusted list
648+
foundB := false
649+
for _, entry := range snap.Trusted {
650+
if entry.NodeID == infoB.Daemon.NodeID() {
651+
foundB = true
652+
if entry.PublicKey == "" {
653+
t.Error("trusted entry should have a public key")
654+
}
655+
if entry.ApprovedAt == "" {
656+
t.Error("trusted entry should have approved_at timestamp")
657+
}
658+
t.Logf("trust entry: node=%d mutual=%v approved=%s", entry.NodeID, entry.Mutual, entry.ApprovedAt)
659+
}
660+
}
661+
if !foundB {
662+
t.Errorf("B (node %d) not found in trust file", infoB.Daemon.NodeID())
663+
}
664+
665+
// Verify the saved data can be parsed back as valid timestamps
666+
for _, entry := range snap.Trusted {
667+
if _, err := time.Parse(time.RFC3339, entry.ApprovedAt); err != nil {
668+
t.Errorf("invalid approved_at timestamp %q: %v", entry.ApprovedAt, err)
669+
}
670+
}
671+
672+
t.Logf("trust file verified: %d trusted, %d pending", len(snap.Trusted), len(snap.Pending))
673+
}
674+
675+
// TestHandshakeTrustLoadFromDisk tests that a daemon loads trust records from a pre-existing trust.json.
676+
func TestHandshakeTrustLoadFromDisk(t *testing.T) {
677+
t.Parallel()
678+
env := NewTestEnv(t)
679+
680+
identityDir := t.TempDir()
681+
identityPath := filepath.Join(identityDir, "identity.json")
682+
trustPath := filepath.Join(identityDir, "trust.json")
683+
684+
// Write a trust.json file before creating the daemon
685+
trustJSON := `{
686+
"trusted": [
687+
{
688+
"node_id": 99999,
689+
"public_key": "dGVzdC1wdWJrZXk=",
690+
"approved_at": "2025-01-01T00:00:00Z",
691+
"mutual": true
692+
}
693+
],
694+
"pending": [
695+
{
696+
"node_id": 88888,
697+
"public_key": "cGVuZGluZy1rZXk=",
698+
"justification": "test pending",
699+
"received_at": "2025-01-02T00:00:00Z"
700+
}
701+
]
702+
}`
703+
if err := os.WriteFile(trustPath, []byte(trustJSON), 0600); err != nil {
704+
t.Fatalf("write trust.json: %v", err)
705+
}
706+
707+
// Create daemon — loadTrust should populate from the file
708+
info := env.AddDaemon(func(c *daemon.Config) {
709+
c.Encrypt = true
710+
c.IdentityPath = identityPath
711+
})
712+
713+
// Verify trusted peers were loaded
714+
trust, err := info.Driver.TrustedPeers()
715+
if err != nil {
716+
t.Fatalf("TrustedPeers: %v", err)
717+
}
718+
719+
trustedList, _ := trust["trusted"].([]interface{})
720+
found99999 := false
721+
for _, tp := range trustedList {
722+
rec := tp.(map[string]interface{})
723+
if uint32(rec["node_id"].(float64)) == 99999 {
724+
found99999 = true
725+
if m, ok := rec["mutual"].(bool); !ok || !m {
726+
t.Errorf("expected mutual=true for loaded trust record")
727+
}
728+
}
729+
}
730+
if !found99999 {
731+
t.Errorf("node 99999 not found in loaded trust records (got %d trusted)", len(trustedList))
732+
}
733+
734+
// Verify pending handshakes were loaded
735+
pending, err := info.Driver.PendingHandshakes()
736+
if err != nil {
737+
t.Fatalf("PendingHandshakes: %v", err)
738+
}
739+
740+
pendingList, _ := pending["pending"].([]interface{})
741+
found88888 := false
742+
for _, p := range pendingList {
743+
req := p.(map[string]interface{})
744+
if uint32(req["node_id"].(float64)) == 88888 {
745+
found88888 = true
746+
if j, ok := req["justification"].(string); !ok || j != "test pending" {
747+
t.Errorf("expected justification 'test pending', got %q", j)
748+
}
749+
}
750+
}
751+
if !found88888 {
752+
t.Errorf("node 88888 not found in loaded pending handshakes (got %d pending)", len(pendingList))
753+
}
754+
755+
t.Logf("loaded from disk: %d trusted, %d pending", len(trustedList), len(pendingList))
756+
}
757+
567758
var _ = driver.Connect // keep driver import
568759
var _ = os.Remove // keep os import

0 commit comments

Comments
 (0)