github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/metricsdebug/collectmetrics_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package metricsdebug_test
     5  
     6  import (
     7  	"github.com/juju/cmd/cmdtesting"
     8  	"github.com/juju/errors"
     9  	"github.com/juju/testing"
    10  	jc "github.com/juju/testing/checkers"
    11  	gc "gopkg.in/check.v1"
    12  	"gopkg.in/juju/charm.v6"
    13  	"gopkg.in/juju/names.v2"
    14  
    15  	"github.com/juju/juju/api"
    16  	"github.com/juju/juju/apiserver/params"
    17  	"github.com/juju/juju/cmd/juju/action"
    18  	"github.com/juju/juju/cmd/juju/metricsdebug"
    19  	"github.com/juju/juju/cmd/modelcmd"
    20  	coretesting "github.com/juju/juju/testing"
    21  )
    22  
    23  type collectMetricsSuite struct {
    24  	coretesting.FakeJujuXDGDataHomeSuite
    25  }
    26  
    27  var (
    28  	_ = gc.Suite(&collectMetricsSuite{})
    29  
    30  	actionTag1 = names.NewActionTag("01234567-89ab-cdef-0123-456789abcdef")
    31  	actionTag2 = names.NewActionTag("11234567-89ab-cdef-0123-456789abcdef")
    32  
    33  	tests = []struct {
    34  		about     string
    35  		args      []string
    36  		stdout    string
    37  		results   [][]params.ActionResult
    38  		actionMap map[string]params.ActionResult
    39  		err       string
    40  	}{{
    41  		about: "missing args",
    42  		err:   "you need to specify a unit or application.",
    43  	}, {
    44  		about: "invalid application name",
    45  		args:  []string{"application_1-0"},
    46  		err:   `"application_1-0" is not a valid unit or application`,
    47  	}, {
    48  		about: "all is well",
    49  		args:  []string{"uptime"},
    50  		results: [][]params.ActionResult{
    51  			{{
    52  				Action: &params.Action{
    53  					Tag: actionTag1.String(),
    54  				},
    55  			}},
    56  			{{
    57  				Action: &params.Action{
    58  					Tag: actionTag2.String(),
    59  				},
    60  			}},
    61  		},
    62  		actionMap: map[string]params.ActionResult{
    63  			actionTag1.Id(): {
    64  				Action: &params.Action{
    65  					Tag:      actionTag1.String(),
    66  					Receiver: "unit-uptime-0",
    67  				},
    68  				Output: map[string]interface{}{
    69  					"Stdout": "ok",
    70  					"Stderr": "",
    71  				},
    72  			},
    73  			actionTag2.Id(): {
    74  				Action: &params.Action{
    75  					Tag: actionTag2.String(),
    76  				},
    77  				Output: map[string]interface{}{
    78  					"Stdout": "ok",
    79  					"Stderr": "",
    80  				},
    81  			},
    82  		},
    83  	}, {
    84  		about: "invalid tag returned",
    85  		args:  []string{"uptime"},
    86  		results: [][]params.ActionResult{
    87  			{{
    88  				Action: &params.Action{
    89  					Tag: "invalid",
    90  				},
    91  			}},
    92  		},
    93  		stdout: `failed to collect metrics: "invalid" is not a valid tag\n`,
    94  	}, {
    95  		about: "no action found",
    96  		args:  []string{"uptime"},
    97  		results: [][]params.ActionResult{
    98  			{{
    99  				Action: &params.Action{
   100  					Tag: actionTag1.String(),
   101  				},
   102  			}},
   103  		},
   104  		stdout: "failed to collect metrics: plm\n",
   105  	}, {
   106  		about: "fail to parse result",
   107  		args:  []string{"uptime"},
   108  		results: [][]params.ActionResult{
   109  			{{
   110  				Action: &params.Action{
   111  					Tag: actionTag1.String(),
   112  				},
   113  			}},
   114  		},
   115  		actionMap: map[string]params.ActionResult{
   116  			actionTag1.Id(): {},
   117  		},
   118  		stdout: "failed to collect metrics: could not read stdout\n",
   119  	}, {
   120  		about: "no results on sendResults",
   121  		args:  []string{"uptime"},
   122  		results: [][]params.ActionResult{
   123  			{{
   124  				Action: &params.Action{
   125  					Tag: actionTag1.String(),
   126  				},
   127  			}},
   128  		},
   129  		actionMap: map[string]params.ActionResult{
   130  			actionTag1.Id(): {
   131  				Action: &params.Action{
   132  					Tag:      actionTag2.String(),
   133  					Receiver: "unit-uptime-0",
   134  				},
   135  				Output: map[string]interface{}{
   136  					"Stdout": "ok",
   137  					"Stderr": "",
   138  				},
   139  			},
   140  		},
   141  		stdout: "failed to send metrics for unit uptime/0: no results\n",
   142  	}, {
   143  		about: "too many sendResults",
   144  		args:  []string{"uptime"},
   145  		results: [][]params.ActionResult{
   146  			{{
   147  				Action: &params.Action{
   148  					Tag: actionTag1.String(),
   149  				},
   150  			}},
   151  			{{
   152  				Action: &params.Action{
   153  					Tag: actionTag1.String(),
   154  				},
   155  			}, {
   156  				Action: &params.Action{
   157  					Tag: actionTag2.String(),
   158  				},
   159  			}},
   160  		},
   161  		actionMap: map[string]params.ActionResult{
   162  			actionTag1.Id(): {
   163  				Action: &params.Action{
   164  					Tag:      actionTag2.String(),
   165  					Receiver: "unit-uptime-0",
   166  				},
   167  				Output: map[string]interface{}{
   168  					"Stdout": "ok",
   169  					"Stderr": "",
   170  				},
   171  			},
   172  		},
   173  		stdout: "failed to send metrics for unit uptime/0\n",
   174  	}, {
   175  		about: "sendResults error",
   176  		args:  []string{"uptime"},
   177  		results: [][]params.ActionResult{
   178  			{{
   179  				Action: &params.Action{
   180  					Tag: actionTag1.String(),
   181  				},
   182  			}},
   183  			{{
   184  				Error: &params.Error{
   185  					Message: "permission denied",
   186  				},
   187  			}},
   188  		},
   189  		actionMap: map[string]params.ActionResult{
   190  			actionTag1.Id(): {
   191  				Action: &params.Action{
   192  					Tag:      actionTag2.String(),
   193  					Receiver: "unit-uptime-0",
   194  				},
   195  				Output: map[string]interface{}{
   196  					"Stdout": "ok",
   197  					"Stderr": "",
   198  				},
   199  			},
   200  		},
   201  		stdout: "failed to send metrics for unit uptime/0: permission denied\n",
   202  	}, {
   203  		about: "couldn't get sendResults action",
   204  		args:  []string{"uptime"},
   205  		results: [][]params.ActionResult{
   206  			{{
   207  				Action: &params.Action{
   208  					Tag: actionTag1.String(),
   209  				},
   210  			}},
   211  			{{
   212  				Action: &params.Action{
   213  					Tag: actionTag2.String(),
   214  				},
   215  			}},
   216  		},
   217  		actionMap: map[string]params.ActionResult{
   218  			actionTag1.Id(): {
   219  				Action: &params.Action{
   220  					Tag:      actionTag2.String(),
   221  					Receiver: "unit-uptime-0",
   222  				},
   223  				Output: map[string]interface{}{
   224  					"Stdout": "ok",
   225  					"Stderr": "",
   226  				},
   227  			},
   228  		},
   229  		stdout: "failed to send metrics for unit uptime/0: plm\n",
   230  	}, {
   231  		about: "couldn't parse sendResults action",
   232  		args:  []string{"uptime"},
   233  		results: [][]params.ActionResult{
   234  			{{
   235  				Action: &params.Action{
   236  					Tag: actionTag1.String(),
   237  				},
   238  			}},
   239  			{{
   240  				Action: &params.Action{
   241  					Tag: actionTag2.String(),
   242  				},
   243  			}},
   244  		},
   245  		actionMap: map[string]params.ActionResult{
   246  			actionTag1.Id(): {
   247  				Action: &params.Action{
   248  					Tag:      actionTag2.String(),
   249  					Receiver: "unit-uptime-0",
   250  				},
   251  				Output: map[string]interface{}{
   252  					"Stdout": "ok",
   253  					"Stderr": "",
   254  				},
   255  			},
   256  			actionTag2.Id(): {},
   257  		},
   258  		stdout: "failed to send metrics for unit uptime/0: could not read stdout\n",
   259  	}, {
   260  		about: "sendResults action stderr",
   261  		args:  []string{"uptime"},
   262  		results: [][]params.ActionResult{
   263  			{{
   264  				Action: &params.Action{
   265  					Tag: actionTag1.String(),
   266  				},
   267  			}},
   268  			{{
   269  				Action: &params.Action{
   270  					Tag: actionTag2.String(),
   271  				},
   272  			}},
   273  		},
   274  		actionMap: map[string]params.ActionResult{
   275  			actionTag1.Id(): {
   276  				Action: &params.Action{
   277  					Tag:      actionTag2.String(),
   278  					Receiver: "unit-uptime-0",
   279  				},
   280  				Output: map[string]interface{}{
   281  					"Stdout": "ok",
   282  					"Stderr": "",
   283  				},
   284  			},
   285  			actionTag2.Id(): {
   286  				Action: &params.Action{
   287  					Tag:      actionTag2.String(),
   288  					Receiver: "unit-uptime-0",
   289  				},
   290  				Output: map[string]interface{}{
   291  					"Stdout": "garbage",
   292  					"Stderr": "kek",
   293  				},
   294  			},
   295  		},
   296  		stdout: "failed to send metrics for unit uptime/0: kek\n",
   297  	}}
   298  )
   299  
   300  func (s *collectMetricsSuite) TestCollectMetricsLocal(c *gc.C) {
   301  	runClient := &testRunClient{}
   302  	applicationClient := &testApplicationClient{}
   303  	applicationClient.charmURL = "local:quantal/charm"
   304  	s.PatchValue(metricsdebug.NewAPIConn, noConn)
   305  	s.PatchValue(metricsdebug.NewRunClient, metricsdebug.NewRunClientFnc(runClient))
   306  
   307  	for i, test := range tests {
   308  		c.Logf("running test %d: %v", i, test.about)
   309  		runClient.reset()
   310  		if test.results != nil {
   311  			runClient.results = test.results
   312  		}
   313  		metricsdebug.PatchGetActionResult(s.PatchValue, test.actionMap)
   314  		ctx, err := cmdtesting.RunCommand(c, metricsdebug.NewCollectMetricsCommandForTest(), test.args...)
   315  		if test.err != "" {
   316  			c.Assert(err, gc.ErrorMatches, test.err)
   317  		} else {
   318  			c.Assert(err, jc.ErrorIsNil)
   319  			c.Assert(cmdtesting.Stdout(ctx), gc.Matches, test.stdout)
   320  		}
   321  	}
   322  }
   323  
   324  func (s *collectMetricsSuite) TestCollectMetricsRemote(c *gc.C) {
   325  	runClient := &testRunClient{}
   326  	applicationClient := &testApplicationClient{}
   327  	applicationClient.charmURL = "quantal/charm"
   328  	s.PatchValue(metricsdebug.NewAPIConn, noConn)
   329  	s.PatchValue(metricsdebug.NewRunClient, metricsdebug.NewRunClientFnc(runClient))
   330  
   331  	for i, test := range tests {
   332  		c.Logf("running test %d: %v", i, test.about)
   333  		runClient.reset()
   334  		if test.results != nil {
   335  			runClient.results = test.results
   336  		}
   337  		metricsdebug.PatchGetActionResult(s.PatchValue, test.actionMap)
   338  		ctx, err := cmdtesting.RunCommand(c, metricsdebug.NewCollectMetricsCommandForTest(), test.args...)
   339  		if test.err != "" {
   340  			c.Assert(err, gc.ErrorMatches, test.err)
   341  		} else {
   342  			c.Assert(err, jc.ErrorIsNil)
   343  			c.Assert(cmdtesting.Stdout(ctx), gc.Matches, test.stdout)
   344  		}
   345  	}
   346  }
   347  
   348  type testRunClient struct {
   349  	action.APIClient
   350  	testing.Stub
   351  
   352  	results [][]params.ActionResult
   353  	err     string
   354  }
   355  
   356  // Run implements the runClient interface.
   357  func (t *testRunClient) Run(run params.RunParams) ([]params.ActionResult, error) {
   358  	t.AddCall("Run", run)
   359  	if t.err != "" {
   360  		return nil, errors.New(t.err)
   361  	}
   362  	if len(t.results) == 0 {
   363  		return nil, errors.New("no results")
   364  	}
   365  	r := t.results[0]
   366  	t.results = t.results[1:]
   367  	return r, nil
   368  }
   369  
   370  // Close implements the runClient interface.
   371  func (t *testRunClient) Close() error {
   372  	t.AddCall("Close")
   373  	return nil
   374  }
   375  
   376  func (t *testRunClient) reset() {
   377  	t.ResetCalls()
   378  	t.results = nil
   379  	t.err = ""
   380  }
   381  
   382  type testApplicationClient struct {
   383  	testing.Stub
   384  	charmURL string
   385  }
   386  
   387  func (t *testApplicationClient) GetCharmURL(service string) (*charm.URL, error) {
   388  	url := charm.MustParseURL(t.charmURL)
   389  	return url, t.NextErr()
   390  }
   391  
   392  func (t *testApplicationClient) Close() error {
   393  	return t.NextErr()
   394  }
   395  
   396  func noConn(_ modelcmd.ModelCommandBase) (api.Connection, error) {
   397  	return nil, nil
   398  }