github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/apiserver/params/params_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package params_test
     5  
     6  import (
     7  	"encoding/json"
     8  	stdtesting "testing"
     9  
    10  	jc "github.com/juju/testing/checkers"
    11  	gc "gopkg.in/check.v1"
    12  	"gopkg.in/juju/charm.v6-unstable"
    13  
    14  	"github.com/juju/juju/apiserver/params"
    15  	"github.com/juju/juju/constraints"
    16  	"github.com/juju/juju/instance"
    17  	"github.com/juju/juju/network"
    18  	"github.com/juju/juju/state"
    19  	"github.com/juju/juju/state/multiwatcher"
    20  	"github.com/juju/juju/status"
    21  	"github.com/juju/juju/testing"
    22  )
    23  
    24  // TestPackage integrates the tests into gotest.
    25  func TestPackage(t *stdtesting.T) {
    26  	gc.TestingT(t)
    27  }
    28  
    29  type MarshalSuite struct{}
    30  
    31  var _ = gc.Suite(&MarshalSuite{})
    32  
    33  var marshalTestCases = []struct {
    34  	about string
    35  	// Value holds a real Go struct.
    36  	value multiwatcher.Delta
    37  	// JSON document.
    38  	json string
    39  }{{
    40  	about: "MachineInfo Delta",
    41  	value: multiwatcher.Delta{
    42  		Entity: &multiwatcher.MachineInfo{
    43  			ModelUUID:  "uuid",
    44  			Id:         "Benji",
    45  			InstanceId: "Shazam",
    46  			JujuStatus: multiwatcher.StatusInfo{
    47  				Current: status.StatusError,
    48  				Message: "foo",
    49  			},
    50  			MachineStatus: multiwatcher.StatusInfo{
    51  				Current: status.StatusPending,
    52  			},
    53  			Life:                    multiwatcher.Life("alive"),
    54  			Series:                  "trusty",
    55  			SupportedContainers:     []instance.ContainerType{instance.LXC},
    56  			Jobs:                    []multiwatcher.MachineJob{state.JobManageModel.ToParams()},
    57  			Addresses:               []network.Address{},
    58  			HardwareCharacteristics: &instance.HardwareCharacteristics{},
    59  		},
    60  	},
    61  	json: `["machine","change",{"ModelUUID":"uuid","Id":"Benji","InstanceId":"Shazam","JujuStatus":{"Err":null,"Current":"error","Message":"foo","Since":null,"Version":"","Data":null},"MachineStatus":{"Err":null,"Current":"pending","Message":"","Since":null,"Version":"","Data":null},"Life":"alive","Series":"trusty","SupportedContainers":["lxc"],"SupportedContainersKnown":false,"HardwareCharacteristics":{},"Jobs":["JobManageModel"],"Addresses":[],"HasVote":false,"WantsVote":false}]`,
    62  }, {
    63  	about: "ServiceInfo Delta",
    64  	value: multiwatcher.Delta{
    65  		Entity: &multiwatcher.ServiceInfo{
    66  			ModelUUID:   "uuid",
    67  			Name:        "Benji",
    68  			Exposed:     true,
    69  			CharmURL:    "cs:quantal/name",
    70  			Life:        multiwatcher.Life("dying"),
    71  			OwnerTag:    "test-owner",
    72  			MinUnits:    42,
    73  			Constraints: constraints.MustParse("arch=armhf mem=1024M"),
    74  			Config: charm.Settings{
    75  				"hello": "goodbye",
    76  				"foo":   false,
    77  			},
    78  			Status: multiwatcher.StatusInfo{
    79  				Current: status.StatusActive,
    80  				Message: "all good",
    81  			},
    82  		},
    83  	},
    84  	json: `["service","change",{"ModelUUID": "uuid", "CharmURL": "cs:quantal/name","Name":"Benji","Exposed":true,"Life":"dying","OwnerTag":"test-owner","MinUnits":42,"Constraints":{"arch":"armhf", "mem": 1024},"Config": {"hello":"goodbye","foo":false},"Subordinate":false,"Status":{"Current":"active", "Message":"all good", "Version": "", "Err": null, "Data": null, "Since": null}}]`,
    85  }, {
    86  	about: "UnitInfo Delta",
    87  	value: multiwatcher.Delta{
    88  		Entity: &multiwatcher.UnitInfo{
    89  			ModelUUID: "uuid",
    90  			Name:      "Benji",
    91  			Service:   "Shazam",
    92  			Series:    "precise",
    93  			CharmURL:  "cs:~user/precise/wordpress-42",
    94  			Ports: []network.Port{{
    95  				Protocol: "http",
    96  				Number:   80,
    97  			}},
    98  			PortRanges: []network.PortRange{{
    99  				FromPort: 80,
   100  				ToPort:   80,
   101  				Protocol: "http",
   102  			}},
   103  			PublicAddress:  "testing.invalid",
   104  			PrivateAddress: "10.0.0.1",
   105  			MachineId:      "1",
   106  			WorkloadStatus: multiwatcher.StatusInfo{
   107  				Current: status.StatusActive,
   108  				Message: "all good",
   109  			},
   110  			JujuStatus: multiwatcher.StatusInfo{
   111  				Current: status.StatusIdle,
   112  			},
   113  		},
   114  	},
   115  	json: `["unit","change",{"ModelUUID":"uuid","Name":"Benji","Service":"Shazam","Series":"precise","CharmURL":"cs:~user/precise/wordpress-42","PublicAddress":"testing.invalid","PrivateAddress":"10.0.0.1","MachineId":"1","Ports":[{"Protocol":"http","Number":80}],"PortRanges":[{"FromPort":80,"ToPort":80,"Protocol":"http"}],"Subordinate":false,"WorkloadStatus":{"Err":null,"Current":"active","Message":"all good","Since":null,"Version":"","Data":null},"JujuStatus":{"Err":null,"Current":"idle","Message":"","Since":null,"Version":"","Data":null}}]`,
   116  }, {
   117  	about: "RelationInfo Delta",
   118  	value: multiwatcher.Delta{
   119  		Entity: &multiwatcher.RelationInfo{
   120  			ModelUUID: "uuid",
   121  			Key:       "Benji",
   122  			Id:        4711,
   123  			Endpoints: []multiwatcher.Endpoint{
   124  				{ServiceName: "logging", Relation: charm.Relation{Name: "logging-directory", Role: "requirer", Interface: "logging", Optional: false, Limit: 1, Scope: "container"}},
   125  				{ServiceName: "wordpress", Relation: charm.Relation{Name: "logging-dir", Role: "provider", Interface: "logging", Optional: false, Limit: 0, Scope: "container"}}},
   126  		},
   127  	},
   128  	json: `["relation","change",{"ModelUUID": "uuid", "Key":"Benji", "Id": 4711, "Endpoints": [{"ServiceName":"logging", "Relation":{"Name":"logging-directory", "Role":"requirer", "Interface":"logging", "Optional":false, "Limit":1, "Scope":"container"}}, {"ServiceName":"wordpress", "Relation":{"Name":"logging-dir", "Role":"provider", "Interface":"logging", "Optional":false, "Limit":0, "Scope":"container"}}]}]`,
   129  }, {
   130  	about: "AnnotationInfo Delta",
   131  	value: multiwatcher.Delta{
   132  		Entity: &multiwatcher.AnnotationInfo{
   133  			ModelUUID: "uuid",
   134  			Tag:       "machine-0",
   135  			Annotations: map[string]string{
   136  				"foo":   "bar",
   137  				"arble": "2 4",
   138  			},
   139  		},
   140  	},
   141  	json: `["annotation","change",{"ModelUUID": "uuid", "Tag":"machine-0","Annotations":{"foo":"bar","arble":"2 4"}}]`,
   142  }, {
   143  	about: "Delta Removed True",
   144  	value: multiwatcher.Delta{
   145  		Removed: true,
   146  		Entity: &multiwatcher.RelationInfo{
   147  			ModelUUID: "uuid",
   148  			Key:       "Benji",
   149  		},
   150  	},
   151  	json: `["relation","remove",{"ModelUUID": "uuid", "Key":"Benji", "Id": 0, "Endpoints": null}]`,
   152  }}
   153  
   154  func (s *MarshalSuite) TestDeltaMarshalJSON(c *gc.C) {
   155  	for _, t := range marshalTestCases {
   156  		c.Log(t.about)
   157  		output, err := t.value.MarshalJSON()
   158  		c.Check(err, jc.ErrorIsNil)
   159  		// We check unmarshalled output both to reduce the fragility of the
   160  		// tests (because ordering in the maps can change) and to verify that
   161  		// the output is well-formed.
   162  		var unmarshalledOutput interface{}
   163  		err = json.Unmarshal(output, &unmarshalledOutput)
   164  		c.Check(err, jc.ErrorIsNil)
   165  		var expected interface{}
   166  		err = json.Unmarshal([]byte(t.json), &expected)
   167  		c.Check(err, jc.ErrorIsNil)
   168  		c.Check(unmarshalledOutput, jc.DeepEquals, expected)
   169  	}
   170  }
   171  
   172  func (s *MarshalSuite) TestDeltaUnmarshalJSON(c *gc.C) {
   173  	for i, t := range marshalTestCases {
   174  		c.Logf("test %d. %s", i, t.about)
   175  		var unmarshalled multiwatcher.Delta
   176  		err := json.Unmarshal([]byte(t.json), &unmarshalled)
   177  		c.Check(err, jc.ErrorIsNil)
   178  		c.Check(unmarshalled, gc.DeepEquals, t.value)
   179  	}
   180  }
   181  
   182  func (s *MarshalSuite) TestDeltaMarshalJSONCardinality(c *gc.C) {
   183  	err := json.Unmarshal([]byte(`[1,2]`), new(multiwatcher.Delta))
   184  	c.Check(err, gc.ErrorMatches, "Expected 3 elements in top-level of JSON but got 2")
   185  }
   186  
   187  func (s *MarshalSuite) TestDeltaMarshalJSONUnknownOperation(c *gc.C) {
   188  	err := json.Unmarshal([]byte(`["relation","masticate",{}]`), new(multiwatcher.Delta))
   189  	c.Check(err, gc.ErrorMatches, `Unexpected operation "masticate"`)
   190  }
   191  
   192  func (s *MarshalSuite) TestDeltaMarshalJSONUnknownEntity(c *gc.C) {
   193  	err := json.Unmarshal([]byte(`["qwan","change",{}]`), new(multiwatcher.Delta))
   194  	c.Check(err, gc.ErrorMatches, `Unexpected entity name "qwan"`)
   195  }
   196  
   197  type ErrorResultsSuite struct{}
   198  
   199  var _ = gc.Suite(&ErrorResultsSuite{})
   200  
   201  func (s *ErrorResultsSuite) TestOneError(c *gc.C) {
   202  	for i, test := range []struct {
   203  		results  params.ErrorResults
   204  		errMatch string
   205  	}{
   206  		{
   207  			errMatch: "expected 1 result, got 0",
   208  		}, {
   209  			results: params.ErrorResults{
   210  				[]params.ErrorResult{{nil}},
   211  			},
   212  		}, {
   213  			results: params.ErrorResults{
   214  				[]params.ErrorResult{{nil}, {nil}},
   215  			},
   216  			errMatch: "expected 1 result, got 2",
   217  		}, {
   218  			results: params.ErrorResults{
   219  				[]params.ErrorResult{
   220  					{&params.Error{Message: "test error"}},
   221  				},
   222  			},
   223  			errMatch: "test error",
   224  		},
   225  	} {
   226  		c.Logf("test %d", i)
   227  		err := test.results.OneError()
   228  		if test.errMatch == "" {
   229  			c.Check(err, jc.ErrorIsNil)
   230  		} else {
   231  			c.Check(err, gc.ErrorMatches, test.errMatch)
   232  		}
   233  	}
   234  }
   235  
   236  func (s *ErrorResultsSuite) TestCombine(c *gc.C) {
   237  	for i, test := range []struct {
   238  		msg      string
   239  		results  params.ErrorResults
   240  		errMatch string
   241  	}{
   242  		{
   243  			msg: "no results, no error",
   244  		}, {
   245  			msg: "single nil result",
   246  			results: params.ErrorResults{
   247  				[]params.ErrorResult{{nil}},
   248  			},
   249  		}, {
   250  			msg: "multiple nil results",
   251  			results: params.ErrorResults{
   252  				[]params.ErrorResult{{nil}, {nil}},
   253  			},
   254  		}, {
   255  			msg: "one error result",
   256  			results: params.ErrorResults{
   257  				[]params.ErrorResult{
   258  					{&params.Error{Message: "test error"}},
   259  				},
   260  			},
   261  			errMatch: "test error",
   262  		}, {
   263  			msg: "mixed error results",
   264  			results: params.ErrorResults{
   265  				[]params.ErrorResult{
   266  					{&params.Error{Message: "test error"}},
   267  					{nil},
   268  					{&params.Error{Message: "second error"}},
   269  				},
   270  			},
   271  			errMatch: "test error\nsecond error",
   272  		},
   273  	} {
   274  		c.Logf("test %d: %s", i, test.msg)
   275  		err := test.results.Combine()
   276  		if test.errMatch == "" {
   277  			c.Check(err, jc.ErrorIsNil)
   278  		} else {
   279  			c.Check(err, gc.ErrorMatches, test.errMatch)
   280  		}
   281  	}
   282  }
   283  
   284  type importSuite struct{}
   285  
   286  var _ = gc.Suite(&importSuite{})
   287  
   288  func (*importSuite) TestParamsDoesNotDependOnState(c *gc.C) {
   289  	imports := testing.FindJujuCoreImports(c, "github.com/juju/juju/apiserver/params")
   290  	for _, i := range imports {
   291  		c.Assert(i, gc.Not(gc.Equals), "state")
   292  	}
   293  }