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  }