github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/worker/uniter/runner/debug/client_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package debug_test 5 6 import ( 7 "encoding/base64" 8 "fmt" 9 "regexp" 10 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 goyaml "gopkg.in/yaml.v2" 14 15 "github.com/juju/juju/worker/uniter/runner/debug" 16 ) 17 18 type DebugHooksClientSuite struct{} 19 20 var _ = gc.Suite(&DebugHooksClientSuite{}) 21 22 func (*DebugHooksClientSuite) TestClientScript(c *gc.C) { 23 ctx := debug.NewHooksContext("foo/8") 24 25 // Test the variable substitutions. 26 result := debug.ClientScript(ctx, nil, "") 27 // No variables left behind. 28 c.Assert(result, gc.Not(gc.Matches), "(.|\n)*{unit_name}(.|\n)*") 29 c.Assert(result, gc.Not(gc.Matches), "(.|\n)*{tmux_conf}(.|\n)*") 30 c.Assert(result, gc.Not(gc.Matches), "(.|\n)*{entry_flock}(.|\n)*") 31 c.Assert(result, gc.Not(gc.Matches), "(.|\n)*{exit_flock}(.|\n)*") 32 // tmux new-session -d -s {unit_name} 33 c.Assert(result, gc.Matches, fmt.Sprintf("(.|\n)*tmux attach-session -t %s(.|\n)*", regexp.QuoteMeta(ctx.Unit))) 34 //) 9>{exit_flock} 35 c.Assert(result, gc.Matches, fmt.Sprintf("(.|\n)*\\) 9>%s(.|\n)*", regexp.QuoteMeta(ctx.ClientExitFileLock()))) 36 //) 8>{entry_flock} 37 c.Assert(result, gc.Matches, fmt.Sprintf("(.|\n)*\\) 8>%s(.|\n)*", regexp.QuoteMeta(ctx.ClientFileLock()))) 38 39 // nil is the same as empty slice is the same as "*". 40 // Also, if "*" is present as well as a named hook, 41 // it is equivalent to "*". 42 c.Check(debug.ClientScript(ctx, nil, ""), 43 gc.Equals, debug.ClientScript(ctx, []string{}, "")) 44 c.Check(debug.ClientScript(ctx, []string{"*"}, ""), 45 gc.Equals, debug.ClientScript(ctx, nil, "")) 46 c.Check(debug.ClientScript(ctx, []string{"*", "something"}, ""), 47 gc.Equals, debug.ClientScript(ctx, []string{"*"}, "")) 48 49 // debug.ClientScript does not validate hook names, as it doesn't have 50 // a full state API connection to determine valid relation hooks. 51 // Note: jam 2020-04-01, This is a very easy to get wrong test. 52 // Without escaping the '|' it was actually just asserting that 'base64 -d' existed in the 53 // file. 54 c.Check(debug.Base64HookArgs([]string{"something somethingelse"}, ""), 55 gc.Equals, "aG9va3M6Ci0gc29tZXRoaW5nIHNvbWV0aGluZ2Vsc2UK") 56 expected := fmt.Sprintf( 57 `(.|\n)*echo "aG9va3M6Ci0gc29tZXRoaW5nIHNvbWV0aGluZ2Vsc2UK" \| base64 -d > %s(.|\n)*`, 58 regexp.QuoteMeta(ctx.ClientFileLock()), 59 ) 60 c.Assert(debug.ClientScript(ctx, []string{"something somethingelse"}, ""), gc.Matches, expected) 61 expected = fmt.Sprintf( 62 `(.|\n)*echo "%s" \| base64 -d > %s(.|\n)*`, 63 debug.Base64HookArgs(nil, "breakpoint-string"), 64 regexp.QuoteMeta(ctx.ClientFileLock()), 65 ) 66 c.Assert(debug.ClientScript(ctx, []string{}, "breakpoint-string"), 67 gc.Matches, expected) 68 } 69 70 func (*DebugHooksClientSuite) TestBase64HookArgsNoValues(c *gc.C) { 71 // Tests of how we encode parameters for how debug-hooks will operate 72 testEncodeRoundTrips(c, nil, "", map[string]interface{}{}) 73 } 74 75 func (*DebugHooksClientSuite) TestBase64HookArgsHookList(c *gc.C) { 76 // Tests of how we encode parameters for how debug-hooks will operate 77 testEncodeRoundTrips(c, []string{"install", "start"}, "", map[string]interface{}{ 78 "hooks": []interface{}{"install", "start"}, 79 }) 80 } 81 82 func (*DebugHooksClientSuite) TestBase64HookArgsDebugAt(c *gc.C) { 83 // Tests of how we encode parameters for how debug-hooks will operate 84 testEncodeRoundTrips(c, nil, "all,broken", map[string]interface{}{ 85 "debug-at": "all,broken", 86 }) 87 } 88 89 func (*DebugHooksClientSuite) TestBase64HookArgsBoth(c *gc.C) { 90 // Tests of how we encode parameters for how debug-hooks will operate 91 testEncodeRoundTrips(c, []string{"db-relation-changed", "stop"}, "brokepoint", 92 map[string]interface{}{ 93 "hooks": []interface{}{"db-relation-changed", "stop"}, 94 "debug-at": "brokepoint", 95 }) 96 } 97 98 func testEncodeRoundTrips(c *gc.C, match []string, debugAt string, decoded map[string]interface{}) { 99 base64Args := debug.Base64HookArgs(match, debugAt) 100 args := decodeArgs(c, base64Args) 101 c.Check(args, gc.DeepEquals, decoded) 102 } 103 104 func decodeArgs(c *gc.C, base64Args string) map[string]interface{} { 105 c.Assert(base64Args, gc.Not(gc.Equals), "") 106 yamlArgs, err := base64.StdEncoding.DecodeString(base64Args) 107 c.Assert(err, jc.ErrorIsNil) 108 var decoded map[string]interface{} 109 c.Assert(goyaml.Unmarshal(yamlArgs, &decoded), jc.ErrorIsNil) 110 return decoded 111 }