master
go 74 lines 2.69 KB
Raw
1 package cli
2
3 import (
4 "testing"
5 "time"
6
7 "github.com/ipfs/kubo/config"
8 "github.com/ipfs/kubo/test/cli/harness"
9 "github.com/stretchr/testify/require"
10 )
11
12 const (
13 // testShutdownTimeout overrides DefaultShutdownTimeout so the test
14 // runs in seconds rather than the production default.
15 testShutdownTimeout = 10 * time.Second
16 // testShutdownCompletionBound is a soft upper bound for StopDaemon in
17 // this test. StopDaemon escalates SIGTERM, SIGTERM, SIGQUIT, SIGKILL
18 // itself (see harness/node.go), so anything close to this bound
19 // indicates kubo's own bounded-shutdown logic failed.
20 testShutdownCompletionBound = testShutdownTimeout + 5*time.Second
21 )
22
23 // TestShutdownTimeoutHonored exercises the bounded-shutdown logic end-to-end
24 // for the common case (no hung subsystems): the daemon must shut down
25 // cleanly well within the configured ShutdownTimeout, and pinned/MFS data
26 // must survive across the restart.
27 func TestShutdownTimeoutHonored(t *testing.T) {
28 t.Parallel()
29 h := harness.NewT(t)
30 node := h.NewNode().Init()
31 node.UpdateConfig(func(cfg *config.Config) {
32 cfg.Internal.ShutdownTimeout = config.NewOptionalDuration(testShutdownTimeout)
33 })
34 node.StartDaemon()
35
36 // Real data-path work that must survive shutdown.
37 addCID := node.PipeStrToIPFS("survives shutdown", "add", "-q").Stdout.Trimmed()
38 node.IPFS("files", "mkdir", "/persisted")
39
40 // "diag healthy" must succeed while the daemon is running normally.
41 require.Equal(t, 0, node.RunIPFS("diag", "healthy").ExitCode(),
42 "diag healthy should succeed before shutdown is initiated")
43
44 start := time.Now()
45 node.StopDaemon()
46 require.Less(t, time.Since(start), testShutdownCompletionBound,
47 "graceful shutdown should complete well within the configured ShutdownTimeout")
48
49 // Restart and verify data survived.
50 node.StartDaemon()
51 require.Contains(t, node.IPFS("pin", "ls").Stdout.String(), addCID,
52 "pinned CID should survive shutdown+restart")
53 require.Contains(t, node.IPFS("files", "ls").Stdout.String(), "persisted",
54 "MFS content should survive shutdown+restart")
55 }
56
57 // TestShutdownTimeoutDisabled verifies that ShutdownTimeout=0 opts out of
58 // the bounded-shutdown logic and behaves like legacy kubo (no watchdog,
59 // no app.Stop deadline). The daemon must still shut down cleanly because
60 // no subsystem is actually hung.
61 func TestShutdownTimeoutDisabled(t *testing.T) {
62 t.Parallel()
63 h := harness.NewT(t)
64 node := h.NewNode().Init()
65 node.UpdateConfig(func(cfg *config.Config) {
66 cfg.Internal.ShutdownTimeout = config.NewOptionalDuration(0)
67 })
68 node.StartDaemon()
69
70 start := time.Now()
71 node.StopDaemon()
72 require.Less(t, time.Since(start), testShutdownCompletionBound,
73 "graceful shutdown should still complete in reasonable time with ShutdownTimeout=0")
74 }