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