github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/jujud/introspect/introspect_test.go (about)

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package introspect_test
     5  
     6  import (
     7  	"bufio"
     8  	"context"
     9  	"flag"
    10  	"fmt"
    11  	"io/ioutil"
    12  	"net"
    13  	"net/http"
    14  	"os"
    15  	"os/exec"
    16  	"path/filepath"
    17  	"runtime"
    18  	"strings"
    19  	stdtesting "testing"
    20  
    21  	"github.com/juju/cmd"
    22  	"github.com/juju/cmd/cmdtesting"
    23  	jc "github.com/juju/testing/checkers"
    24  	gc "gopkg.in/check.v1"
    25  	"gopkg.in/juju/names.v2"
    26  
    27  	"github.com/juju/juju/cmd/jujud/introspect"
    28  	cmdutil "github.com/juju/juju/cmd/jujud/util"
    29  	"github.com/juju/juju/testing"
    30  )
    31  
    32  type IntrospectCommandSuite struct {
    33  	testing.BaseSuite
    34  }
    35  
    36  func (s *IntrospectCommandSuite) SetUpTest(c *gc.C) {
    37  	if runtime.GOOS == "windows" {
    38  		c.Skip("introspection socket does not run on windows")
    39  	}
    40  	s.BaseSuite.SetUpTest(c)
    41  	s.PatchValue(&cmdutil.DataDir, c.MkDir())
    42  }
    43  
    44  var _ = gc.Suite(&IntrospectCommandSuite{})
    45  
    46  func (s *IntrospectCommandSuite) TestInitErrors(c *gc.C) {
    47  	s.assertInitError(c, "either a query path or a --listen address must be specified")
    48  	s.assertInitError(c, "a query path may not be specified with --listen", "query-path", "--listen=foo")
    49  	s.assertInitError(c, `unrecognized args: \["path"\]`, "query", "path")
    50  }
    51  
    52  func (*IntrospectCommandSuite) assertInitError(c *gc.C, expect string, args ...string) {
    53  	err := cmdtesting.InitCommand(&introspect.IntrospectCommand{}, args)
    54  	c.Assert(err, gc.ErrorMatches, expect)
    55  }
    56  
    57  func (*IntrospectCommandSuite) run(c *gc.C, args ...string) (*cmd.Context, error) {
    58  	return cmdtesting.RunCommand(c, &introspect.IntrospectCommand{
    59  		IntrospectionSocketName: func(tag names.Tag) string {
    60  			return filepath.Join(cmdutil.DataDir, "jujud-"+tag.String())
    61  		},
    62  	}, args...)
    63  }
    64  
    65  func (s *IntrospectCommandSuite) TestAutoDetectMachineAgent(c *gc.C) {
    66  	machineDir := filepath.Join(cmdutil.DataDir, "agents", "machine-1024")
    67  	err := os.MkdirAll(machineDir, 0755)
    68  	c.Assert(err, jc.ErrorIsNil)
    69  
    70  	_, err = s.run(c, "query")
    71  	c.Assert(err, gc.ErrorMatches, ".*jujud-machine-1024.*")
    72  }
    73  
    74  func (s *IntrospectCommandSuite) TestAutoDetectMachineAgentFails(c *gc.C) {
    75  	machineDir := filepath.Join(cmdutil.DataDir, "agents")
    76  	err := os.MkdirAll(machineDir, 0755)
    77  	c.Assert(err, jc.ErrorIsNil)
    78  
    79  	_, err = s.run(c, "query")
    80  	c.Assert(err, gc.ErrorMatches, "could not determine machine tag")
    81  }
    82  
    83  func (s *IntrospectCommandSuite) TestAgentSpecified(c *gc.C) {
    84  	_, err := s.run(c, "query", "--agent=unit-foo-0")
    85  	c.Assert(err, gc.ErrorMatches, ".*jujud-unit-foo-0.*")
    86  }
    87  
    88  func (s *IntrospectCommandSuite) TestQuery(c *gc.C) {
    89  	listener, err := net.Listen("unix", "@"+filepath.Join(cmdutil.DataDir, "jujud-machine-0"))
    90  	c.Assert(err, jc.ErrorIsNil)
    91  	defer listener.Close()
    92  
    93  	srv := newServer(listener)
    94  	go srv.Serve(listener)
    95  	defer srv.Shutdown(context.Background())
    96  
    97  	ctx, err := s.run(c, "query", "--agent=machine-0")
    98  	c.Assert(err, jc.ErrorIsNil)
    99  	c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "hello")
   100  }
   101  
   102  func (s *IntrospectCommandSuite) TestQueryFails(c *gc.C) {
   103  	listener, err := net.Listen("unix", "@"+filepath.Join(cmdutil.DataDir, "jujud-machine-0"))
   104  	c.Assert(err, jc.ErrorIsNil)
   105  	defer listener.Close()
   106  
   107  	srv := newServer(listener)
   108  	go srv.Serve(listener)
   109  	defer srv.Shutdown(context.Background())
   110  
   111  	ctx, err := s.run(c, "missing", "--agent=machine-0")
   112  	c.Assert(err, gc.ErrorMatches, `response returned 404 \(Not Found\)`)
   113  	c.Assert(cmdtesting.Stderr(ctx), gc.Equals, fmt.Sprintf(`
   114  Querying @%s introspection socket: missing
   115  404 page not found
   116  `[1:], filepath.Join(cmdutil.DataDir, "jujud-machine-0")))
   117  	c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "")
   118  
   119  	ctx, err = s.run(c, "badness", "--agent=machine-0")
   120  	c.Assert(err, gc.ErrorMatches, `response returned 500 \(Internal Server Error\)`)
   121  	c.Assert(cmdtesting.Stderr(ctx), gc.Equals, fmt.Sprintf(`
   122  Querying @%s introspection socket: badness
   123  argh
   124  `[1:], filepath.Join(cmdutil.DataDir, "jujud-machine-0")))
   125  	c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "")
   126  }
   127  
   128  func (s *IntrospectCommandSuite) TestListen(c *gc.C) {
   129  	socketName := filepath.Join(cmdutil.DataDir, "jujud-machine-0")
   130  	listener, err := net.Listen("unix", "@"+socketName)
   131  	c.Assert(err, jc.ErrorIsNil)
   132  	defer listener.Close()
   133  
   134  	srv := newServer(listener)
   135  	go srv.Serve(listener)
   136  	defer srv.Shutdown(context.Background())
   137  
   138  	ctx, cancel := context.WithCancel(context.Background())
   139  	defer cancel()
   140  	cmd := exec.CommandContext(ctx, os.Args[0], "-run-listen="+socketName)
   141  	stderr, err := cmd.StderrPipe()
   142  	c.Assert(err, jc.ErrorIsNil)
   143  	defer stderr.Close()
   144  	err = cmd.Start()
   145  	c.Assert(err, jc.ErrorIsNil)
   146  
   147  	scanner := bufio.NewScanner(stderr)
   148  	c.Assert(scanner.Scan(), jc.IsTrue)
   149  	line := scanner.Text()
   150  	c.Assert(line, gc.Matches, "Exposing @.* introspection socket on 127.0.0.1:.*")
   151  
   152  	fields := strings.Fields(line)
   153  	addr := fields[len(fields)-1]
   154  	resp, err := http.Get(fmt.Sprintf("http://%s/query", addr))
   155  	c.Assert(err, jc.ErrorIsNil)
   156  	defer resp.Body.Close()
   157  	c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
   158  	body, err := ioutil.ReadAll(resp.Body)
   159  	c.Assert(err, jc.ErrorIsNil)
   160  	c.Assert(string(body), gc.Equals, "hello")
   161  }
   162  
   163  func newServer(l net.Listener) *http.Server {
   164  	mux := http.NewServeMux()
   165  	mux.HandleFunc("/query", func(w http.ResponseWriter, r *http.Request) {
   166  		w.Write([]byte("hello"))
   167  	})
   168  	mux.HandleFunc("/badness", func(w http.ResponseWriter, r *http.Request) {
   169  		http.Error(w, "argh", http.StatusInternalServerError)
   170  	})
   171  	srv := &http.Server{}
   172  	srv.Handler = mux
   173  	return srv
   174  }
   175  
   176  var flagListen = flag.String("run-listen", "", "Name of the Unix socket to connect the introspect command to using --listen=:0")
   177  
   178  func TestRunListen(t *stdtesting.T) {
   179  	if *flagListen != "" {
   180  		introspectCommand := &introspect.IntrospectCommand{
   181  			IntrospectionSocketName: func(names.Tag) string {
   182  				return *flagListen
   183  			},
   184  		}
   185  		args := append(flag.Args(), "--listen=127.0.0.1:0", "--agent=machine-0")
   186  		if err := cmdtesting.InitCommand(introspectCommand, args); err != nil {
   187  			t.Fatal(err)
   188  		}
   189  		ctx, err := cmd.DefaultContext()
   190  		if err != nil {
   191  			t.Fatal(err)
   192  		}
   193  		if err := introspectCommand.Run(ctx); err != nil {
   194  			t.Fatal(err)
   195  		}
   196  	}
   197  }