Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable test devices to have multiple MAC addresses #56

Merged
merged 1 commit into from
Aug 23, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 66 additions & 25 deletions testservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,11 @@ type TestServer struct {
}

type TestDevice struct {
IPAddresses []string
SystemId string
MACAddress string
Parent string
Hostname string
IPAddresses []string
SystemId string
MACAddresses []string
Parent string
Hostname string

// Not part of the device definition but used by the template.
APIVersion string
Expand Down Expand Up @@ -663,11 +663,8 @@ func devicesTopLevelHandler(server *TestServer, w http.ResponseWriter, r *http.R
}
}

func macMatches(device *TestDevice, macs []string, hasMac bool) bool {
if !hasMac {
return true
}
return contains(macs, device.MACAddress)
func macMatches(mac string, device *TestDevice) bool {
return contains(device.MACAddresses, mac)
}

// deviceListingHandler handles requests for '/devices/'.
Expand All @@ -676,13 +673,25 @@ func deviceListingHandler(server *TestServer, w http.ResponseWriter, r *http.Req
checkError(err)
// TODO(mfoord): support filtering by hostname and id
macs, hasMac := values["mac_address"]
var matchedDevices []string
for _, device := range server.devices {
if macMatches(device, macs, hasMac) {
matchedDevices = append(matchedDevices, renderDevice(device))
var matchedDevices []*TestDevice
if !hasMac {
for _, device := range server.devices {
matchedDevices = append(matchedDevices, device)
}
} else {
for _, mac := range macs {
for _, device := range server.devices {
if macMatches(mac, device) {
matchedDevices = append(matchedDevices, device)
}
}
}
}
json := fmt.Sprintf("[%v]", strings.Join(matchedDevices, ", "))
deviceChunks := make([]string, len(matchedDevices))
for i := range matchedDevices {
deviceChunks[i] = renderDevice(matchedDevices[i])
}
json := fmt.Sprintf("[%v]", strings.Join(deviceChunks, ", "))

w.WriteHeader(http.StatusOK)
fmt.Fprint(w, json)
Expand All @@ -696,16 +705,31 @@ var templateFuncs = template.FuncMap{
}
return strings.Join(pieces, ", ")
},
"last": func(items []string) []string {
if len(items) == 0 {
return []string{}
}
return items[len(items)-1:]
},
"allButLast": func(items []string) []string {
if len(items) < 2 {
return []string{}
}
return items[0 : len(items)-1]
},
}

const (
// The json template for generating new devices.
// TODO(mfoord): set resource_uri in MAC addresses
deviceTemplate = `{
"macaddress_set": [
"macaddress_set": [{{range .MACAddresses | allButLast}}
{
"mac_address": "{{.MACAddress}}"
}
"mac_address": "{{.}}"
},{{end}}{{range .MACAddresses | last}}
{
"mac_address": "{{.}}"
}{{end}}
],
"zone": {
"resource_uri": "/MAAS/api/{{.APIVersion}}/zones/default/",
Expand Down Expand Up @@ -741,6 +765,23 @@ func getValue(values url.Values, value string) (string, bool) {
return result[0], true
}

func getValues(values url.Values, key string) ([]string, bool) {
result, hasResult := values[key]
if !hasResult {
return nil, false
}
var output []string
for _, val := range result {
if val != "" {
output = append(output, val)
}
}
if len(output) == 0 {
return nil, false
}
return output, true
}

// newDeviceHandler creates, stores and returns new devices.
func newDeviceHandler(server *TestServer, w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
Expand All @@ -753,23 +794,23 @@ func newDeviceHandler(server *TestServer, w http.ResponseWriter, r *http.Request
systemId := fmt.Sprintf("node-%v", uuid)
// At least one MAC address must be specified.
// TODO(mfoord) we only support a single MAC in the test server.
mac, hasMac := getValue(values, "mac_addresses")
macs, hasMacs := getValues(values, "mac_addresses")

// hostname and parent are optional.
// TODO(mfoord): we require both to be set in the test server.
hostname, hasHostname := getValue(values, "hostname")
parent, hasParent := getValue(values, "parent")
if !hasHostname || !hasMac || !hasParent {
if !hasHostname || !hasMacs || !hasParent {
w.WriteHeader(http.StatusBadRequest)
return
}

device := &TestDevice{
MACAddress: mac,
APIVersion: server.version,
Parent: parent,
Hostname: hostname,
SystemId: systemId,
MACAddresses: macs,
APIVersion: server.version,
Parent: parent,
Hostname: hostname,
SystemId: systemId,
}

deviceJSON := renderDevice(device)
Expand Down
55 changes: 47 additions & 8 deletions testservice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,12 @@ func (suite *TestServerSuite) TestSetVersionJSON(c *C) {
c.Assert(string(content), Equals, capabilities)
}

func (suite *TestServerSuite) createDevice(c *C, mac, hostname, parent string) string {
func (suite *TestServerSuite) createDevice(c *C, macs, hostname, parent string) string {
devicesURL := fmt.Sprintf("/api/%s/devices/", suite.server.version) + "?op=new"
values := url.Values{}
values.Add("mac_addresses", mac)
for _, mac := range strings.Split(macs, ",") {
values.Add("mac_addresses", mac)
}
values.Add("hostname", hostname)
values.Add("parent", parent)
result := suite.post(c, devicesURL, values)
Expand Down Expand Up @@ -110,15 +112,19 @@ func (suite *TestServerSuite) get(c *C, url string) JSONObject {
return result
}

func checkDevice(c *C, device map[string]JSONObject, mac, hostname, parent string) {
func checkDevice(c *C, device map[string]JSONObject, macs, hostname, parent string) {
macSlice := strings.Split(macs, ",")
macArray, err := device["macaddress_set"].GetArray()
c.Assert(err, IsNil)
c.Assert(macArray, HasLen, 1)
macMap, err := macArray[0].GetMap()
c.Assert(err, IsNil)
c.Assert(macArray, HasLen, len(macSlice))

actualMac := getString(c, macMap, "mac_address")
c.Assert(actualMac, Equals, mac)
for i := range macArray {
macMap, err := macArray[i].GetMap()
c.Assert(err, IsNil)

actualMac := getString(c, macMap, "mac_address")
c.Check(actualMac, Equals, macSlice[i])
}

actualParent := getString(c, device, "parent")
c.Assert(actualParent, Equals, parent)
Expand Down Expand Up @@ -205,6 +211,18 @@ func (suite *TestServerSuite) TestGetDevice(c *C) {
c.Assert(actualId, Equals, systemId)
}

func (suite *TestServerSuite) TestGetDeviceWithMultipleMacs(c *C) {
systemId := suite.createDevice(c, "foo,boo", "bar", "baz")
deviceURL := fmt.Sprintf("/api/%v/devices/%v/", suite.server.version, systemId)

result := suite.get(c, deviceURL)
resultMap, err := result.GetMap()
c.Assert(err, IsNil)
checkDevice(c, resultMap, "foo,boo", "bar", "baz")
actualId, err := resultMap["system_id"].GetString()
c.Assert(actualId, Equals, systemId)
}

func (suite *TestServerSuite) TestDevicesList(c *C) {
firstId := suite.createDevice(c, "foo", "bar", "baz")
c.Assert(firstId, Not(Equals), "")
Expand Down Expand Up @@ -252,6 +270,27 @@ func (suite *TestServerSuite) TestDevicesListMacFiltering(c *C) {
checkDevice(c, deviceMap, "foo", "bar", "baz")
}

func (suite *TestServerSuite) TestDevicesListMacFilteringMultipleAddresses(c *C) {
firstId := suite.createDevice(c, "foo,boo", "bar", "baz")
c.Assert(firstId, Not(Equals), "")
secondId := suite.createDevice(c, "bam,boom", "bing", "bong")
c.Assert(secondId, Not(Equals), "")

op := "?op=list&mac_address=foo&mac_address=boo"
devicesURL := fmt.Sprintf("/api/%s/devices/", suite.server.version) + op
result := suite.get(c, devicesURL)

devicesArray, err := result.GetArray()
c.Assert(err, IsNil)
c.Assert(devicesArray, HasLen, 2)
deviceMap, err := devicesArray[0].GetMap()
c.Assert(err, IsNil)
checkDevice(c, deviceMap, "foo,boo", "bar", "baz")
deviceMap, err = devicesArray[1].GetMap()
c.Assert(err, IsNil)
checkDevice(c, deviceMap, "foo,boo", "bar", "baz")
}

func (suite *TestServerSuite) TestDeviceClaimStickyIPRequiresAddress(c *C) {
systemId := suite.createDevice(c, "foo", "bar", "baz")
op := "?op=claim_sticky_ip_address"
Expand Down