github.com/jbking/gohan@v0.0.0-20151217002006-b41ccf1c2a96/server/server_test.go (about)

     1  // Copyright (C) 2015 NTT Innovation Institute, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    12  // implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  package server_test
    17  
    18  import (
    19  	"bytes"
    20  	"encoding/json"
    21  	"fmt"
    22  	"io"
    23  	"net/http"
    24  	"strconv"
    25  	"strings"
    26  	"testing"
    27  
    28  	"github.com/coreos/go-etcd/etcd"
    29  	. "github.com/onsi/ginkgo"
    30  	. "github.com/onsi/gomega"
    31  
    32  	"github.com/cloudwan/gohan/db"
    33  	"github.com/cloudwan/gohan/db/transaction"
    34  	"github.com/cloudwan/gohan/schema"
    35  	srv "github.com/cloudwan/gohan/server"
    36  	gohan_sync "github.com/cloudwan/gohan/sync"
    37  	gohan_etcd "github.com/cloudwan/gohan/sync/etcd"
    38  	"github.com/cloudwan/gohan/util"
    39  )
    40  
    41  var (
    42  	server           *srv.Server
    43  	baseURL          = "http://localhost:19090"
    44  	schemaURL        = baseURL + "/gohan/v0.1/schemas"
    45  	networkPluralURL = baseURL + "/v2.0/networks"
    46  	subnetPluralURL  = baseURL + "/v2.0/subnets"
    47  	testPluralURL    = baseURL + "/v2.0/tests"
    48  )
    49  
    50  var _ = Describe("Server package test", func() {
    51  
    52  	AfterEach(func() {
    53  		tx, err := testDB.Begin()
    54  		Expect(err).ToNot(HaveOccurred(), "Failed to create transaction.")
    55  		defer tx.Close()
    56  		for _, schema := range schema.GetManager().Schemas() {
    57  			if whitelist[schema.ID] {
    58  				continue
    59  			}
    60  			err = clearTable(tx, schema)
    61  			Expect(err).ToNot(HaveOccurred(), "Failed to clear table.")
    62  		}
    63  		err = tx.Commit()
    64  		Expect(err).ToNot(HaveOccurred(), "Failed to commite transaction.")
    65  	})
    66  
    67  	Describe("Http request", func() {
    68  		Context("with invalid request body", func() {
    69  			malformedRequestBody := "malformed"
    70  
    71  			It("should not create network", func() {
    72  				data := testURL("POST", networkPluralURL, adminTokenID,
    73  					malformedRequestBody, http.StatusBadRequest)
    74  				Expect(data).To(HaveKeyWithValue("error", ContainSubstring("parse data")))
    75  			})
    76  
    77  			It("should not update network", func() {
    78  				network := getNetwork("yellow", adminTenantID)
    79  				testURL("POST", networkPluralURL, adminTokenID, network, http.StatusCreated)
    80  
    81  				data := testURL("PUT", getNetworkSingularURL("yellow"),
    82  					adminTokenID, malformedRequestBody, http.StatusBadRequest)
    83  				Expect(data).To(HaveKeyWithValue("error", ContainSubstring("parse data")))
    84  			})
    85  		})
    86  
    87  		Context("getting from baseURL", func() {
    88  			It("should return 404(Not Found)", func() {
    89  				testURL("GET", baseURL, adminTokenID, nil, http.StatusNotFound)
    90  			})
    91  		})
    92  
    93  		Context("getting networks while no networks", func() {
    94  			It("should return 200(OK) status code", func() {
    95  				testURL("GET", networkPluralURL, adminTokenID, nil, http.StatusOK)
    96  			})
    97  		})
    98  
    99  		It("should not authorize getting networks with no token", func() {
   100  			testURL("GET", networkPluralURL, "", nil, http.StatusUnauthorized)
   101  		})
   102  
   103  		Context("having one network", func() {
   104  			var result interface{}
   105  
   106  			network := getNetwork("red", "red")
   107  
   108  			BeforeEach(func() {
   109  				result = testURL("POST", networkPluralURL, adminTokenID, network, http.StatusCreated)
   110  				Expect(result).To(HaveKeyWithValue("network", util.MatchAsJSON(network)))
   111  			})
   112  
   113  			It("should get networks list", func() {
   114  				result = testURL("GET", networkPluralURL, adminTokenID, nil, http.StatusOK)
   115  				Expect(result).To(HaveKeyWithValue("networks", ConsistOf(util.MatchAsJSON(network))))
   116  			})
   117  
   118  			It("should get particular network", func() {
   119  				result = testURL("GET", getNetworkSingularURL("red"), adminTokenID, nil, http.StatusOK)
   120  				Expect(result).To(HaveKeyWithValue("network", util.MatchAsJSON(network)))
   121  			})
   122  
   123  			It("should not get invalid network", func() {
   124  				testURL("GET", baseURL+"/v2.0/network/unknownID", adminTokenID, nil, http.StatusNotFound)
   125  			})
   126  
   127  			It("should delete particular network", func() {
   128  				testURL("DELETE", getNetworkSingularURL("red"), adminTokenID, nil, http.StatusNoContent)
   129  			})
   130  
   131  			Describe("updating network using PUT", func() {
   132  				networkUpdate := map[string]interface{}{
   133  					"name": "NetworkRed2",
   134  				}
   135  				invalidNetwork := map[string]interface{}{
   136  					"id":   10,
   137  					"name": "NetworkRed",
   138  				}
   139  				networkUpdated := network
   140  				networkUpdated["name"] = "NetworkRed2"
   141  
   142  				It("should not update network with invalid or the same network", func() {
   143  					testURL("PUT", getNetworkSingularURL("red"), adminTokenID, invalidNetwork, http.StatusBadRequest)
   144  					testURL("PUT", getNetworkSingularURL("red"), adminTokenID, network, http.StatusBadRequest)
   145  				})
   146  
   147  				It("should update and get updated network", func() {
   148  					result = testURL("PUT", getNetworkSingularURL("red"), adminTokenID, networkUpdate, http.StatusOK)
   149  					Expect(result).To(HaveKeyWithValue("network", util.MatchAsJSON(networkUpdated)))
   150  					result = testURL("GET", getNetworkSingularURL("red"), adminTokenID, nil, http.StatusOK)
   151  					Expect(result).To(HaveKeyWithValue("network", util.MatchAsJSON(networkUpdated)))
   152  				})
   153  			})
   154  
   155  			Describe("updating network using PATCH", func() {
   156  				networkUpdate := map[string]interface{}{
   157  					"name": "NetworkRed2",
   158  				}
   159  				invalidNetwork := map[string]interface{}{
   160  					"id":   10,
   161  					"name": "NetworkRed",
   162  				}
   163  				networkUpdated := network
   164  				networkUpdated["name"] = "NetworkRed2"
   165  
   166  				It("should not update network with invalid or the same network", func() {
   167  					testURL("PATCH", getNetworkSingularURL("red"), adminTokenID, invalidNetwork, http.StatusBadRequest)
   168  					testURL("PATCH", getNetworkSingularURL("red"), adminTokenID, network, http.StatusBadRequest)
   169  				})
   170  
   171  				It("should update and get updated network", func() {
   172  					result = testURL("PATCH", getNetworkSingularURL("red"), adminTokenID, networkUpdate, http.StatusOK)
   173  					By(fmt.Sprintf("%s", result))
   174  					Expect(result).To(HaveKeyWithValue("network", util.MatchAsJSON(networkUpdated)))
   175  					result = testURL("GET", getNetworkSingularURL("red"), adminTokenID, nil, http.StatusOK)
   176  					Expect(result).To(HaveKeyWithValue("network", util.MatchAsJSON(networkUpdated)))
   177  				})
   178  			})
   179  		})
   180  
   181  		Context("trying to create network with no tenant_id", func() {
   182  			It("should add adminTenantID as a default.", func() {
   183  				networkRed := getNetwork("red", "red")
   184  				delete(networkRed, "tenant_id")
   185  
   186  				data := testURL("POST", networkPluralURL, adminTokenID, networkRed, http.StatusCreated)
   187  				Expect(data).To(HaveKeyWithValue("network", HaveKeyWithValue("tenant_id", adminTenantID)))
   188  			})
   189  		})
   190  	})
   191  
   192  	Describe("PaginationAndSorting", func() {
   193  		It("should work", func() {
   194  			By("creating 2 networks")
   195  			networkRed := getNetwork("red", "red")
   196  			testURL("POST", networkPluralURL, adminTokenID, networkRed, http.StatusCreated)
   197  			networkBlue := getNetwork("blue", "red")
   198  			testURL("POST", networkPluralURL, adminTokenID, networkBlue, http.StatusCreated)
   199  
   200  			By("assuring 2 networks were returned")
   201  			result := testURL("GET", networkPluralURL, adminTokenID, nil, http.StatusOK)
   202  			res := result.(map[string]interface{})
   203  			networks := res["networks"].([]interface{})
   204  			Expect(networks).To(HaveLen(2))
   205  
   206  			By("assuring returned networks are sorted")
   207  			res = result.(map[string]interface{})
   208  			networks = res["networks"].([]interface{})
   209  			n0, n1 := networks[0].(map[string]interface{}), networks[1].(map[string]interface{})
   210  			Expect(n0).To(HaveKeyWithValue("id", "networkblue"))
   211  			Expect(n1).To(HaveKeyWithValue("id", "networkred"))
   212  
   213  			By("assuring pagination works")
   214  			result = testURL("GET", networkPluralURL+"?limit=1&offset=1&sort_order=desc", adminTokenID, nil, http.StatusOK)
   215  			res = result.(map[string]interface{})
   216  			networks = res["networks"].([]interface{})
   217  			n0 = networks[0].(map[string]interface{})
   218  			Expect(networks).To(HaveLen(1))
   219  			Expect(n0).To(HaveKeyWithValue("id", "networkblue"))
   220  
   221  			result, resp := httpRequest("GET", networkPluralURL+"?limit=1&offset=1", adminTokenID, nil)
   222  			Expect(resp.StatusCode).To(Equal(http.StatusOK))
   223  			res = result.(map[string]interface{})
   224  			networks = res["networks"].([]interface{})
   225  			n0 = networks[0].(map[string]interface{})
   226  			Expect(networks).To(HaveLen(1))
   227  			Expect(n0).To(HaveKeyWithValue("id", "networkred"))
   228  
   229  			testURL("GET", networkPluralURL+"?limit=-1", adminTokenID, nil, http.StatusBadRequest)
   230  			testURL("GET", networkPluralURL+"?offset=-1", adminTokenID, nil, http.StatusBadRequest)
   231  			testURL("GET", networkPluralURL+"?sort_key=bad_key", adminTokenID, nil, http.StatusBadRequest)
   232  			testURL("GET", networkPluralURL+"?sort_order=bad_order", adminTokenID, nil, http.StatusBadRequest)
   233  
   234  			Expect(resp.Header.Get("X-Total-Count")).To(Equal("2"))
   235  			testURL("DELETE", getNetworkSingularURL("red"), adminTokenID, nil, http.StatusNoContent)
   236  			testURL("DELETE", getNetworkSingularURL("blue"), adminTokenID, nil, http.StatusNoContent)
   237  		})
   238  	})
   239  
   240  	Describe("Subnets", func() {
   241  		It("should work", func() {
   242  			network := getNetwork("red", "red")
   243  			testURL("POST", networkPluralURL, adminTokenID, network, http.StatusCreated)
   244  
   245  			subnet := getSubnet("red", "red", "")
   246  
   247  			delete(subnet, "network_id")
   248  
   249  			var result interface{}
   250  			testURL("POST", subnetPluralURL, adminTokenID, subnet, http.StatusBadRequest)
   251  			result = testURL("POST", getSubnetFullPluralURL("red"), adminTokenID, subnet, http.StatusCreated)
   252  
   253  			subnet["network_id"] = "networkred"
   254  			Expect(result).To(HaveKeyWithValue("subnet", util.MatchAsJSON(subnet)))
   255  
   256  			result = testURL("GET", getSubnetSingularURL("red"), adminTokenID, subnet, http.StatusOK)
   257  			Expect(result).To(HaveKeyWithValue("subnet", util.MatchAsJSON(subnet)))
   258  
   259  			noCidrSubnet := getSubnet("NoCIDR", "red", "networkred")
   260  			delete(noCidrSubnet, "cidr")
   261  			testURL("POST", getSubnetFullPluralURL("red"), adminTokenID, noCidrSubnet, http.StatusBadRequest)
   262  
   263  			subnetUpdate := map[string]interface{}{
   264  				"name": "subnetRed2",
   265  			}
   266  			testURL("PUT", getSubnetSingularURL("red"), adminTokenID, subnetUpdate, http.StatusOK)
   267  
   268  			testURL("DELETE", getNetworkSingularURL("red"), adminTokenID, nil, http.StatusConflict)
   269  			testURL("DELETE", getSubnetSingularURL("red"), adminTokenID, nil, http.StatusNoContent)
   270  			testURL("DELETE", getNetworkSingularURL("red"), adminTokenID, nil, http.StatusNoContent)
   271  			result = testURL("GET", networkPluralURL, adminTokenID, nil, http.StatusOK)
   272  			Expect(result).To(HaveKeyWithValue("networks", BeEmpty()))
   273  			testURL("DELETE", getNetworkSingularURL("red"), adminTokenID, nil, http.StatusNotFound)
   274  		})
   275  	})
   276  
   277  	Describe("NullableProperties", func() {
   278  		It("should work", func() {
   279  			network := getNetwork("red", "red")
   280  			testURL("POST", networkPluralURL, adminTokenID, network, http.StatusCreated)
   281  
   282  			// Create subnet with null name. Ensure it's not defaulted to ""
   283  			subnet := getSubnet("red", "red", "networkred")
   284  			subnet["name"] = nil
   285  			testURL("POST", subnetPluralURL, adminTokenID, subnet, http.StatusCreated)
   286  
   287  			result := testURL("GET", getSubnetSingularURL("red"), adminTokenID, nil, http.StatusOK)
   288  			Expect(result).To(HaveKey("subnet"))
   289  			Expect(result.(map[string]interface{})["subnet"]).To(HaveKeyWithValue("name", BeNil()))
   290  
   291  			subnetUpdateName := map[string]interface{}{
   292  				"name": "Red network",
   293  			}
   294  			testURL("PUT", getSubnetSingularURL("red"), adminTokenID, subnetUpdateName, http.StatusOK)
   295  			result = testURL("GET", getSubnetSingularURL("red"), adminTokenID, nil, http.StatusOK)
   296  			Expect(result).To(HaveKeyWithValue("subnet", HaveKeyWithValue("name", subnetUpdateName["name"])))
   297  
   298  			// Test setting nullable property to null
   299  			subnetUpdateNullName := map[string]interface{}{
   300  				"name": nil,
   301  			}
   302  			testURL("PUT", getSubnetSingularURL("red"), adminTokenID, subnetUpdateNullName, http.StatusOK)
   303  			result = testURL("GET", getSubnetSingularURL("red"), adminTokenID, nil, http.StatusOK)
   304  			Expect(result).To(HaveKey("subnet"))
   305  			Expect(result.(map[string]interface{})["subnet"]).To(HaveKeyWithValue("name", BeNil()))
   306  
   307  			testURL("DELETE", getSubnetSingularURL("red"), adminTokenID, nil, http.StatusNoContent)
   308  			testURL("DELETE", getNetworkSingularURL("red"), adminTokenID, nil, http.StatusNoContent)
   309  		})
   310  	})
   311  
   312  	Describe("MemberToken", func() {
   313  		It("should work", func() {
   314  			network := getNetwork("red", "red")
   315  
   316  			testURL("GET", baseURL, memberTokenID, nil, http.StatusNotFound)
   317  			testURL("GET", networkPluralURL, memberTokenID, nil, http.StatusOK)
   318  			testURL("GET", networkPluralURL, "", nil, http.StatusUnauthorized)
   319  			testURL("GET", schemaURL, memberTokenID, nil, http.StatusOK)
   320  
   321  			network = map[string]interface{}{
   322  				"id":   "networkred",
   323  				"name": "Networkred",
   324  			}
   325  			networkExpected := map[string]interface{}{
   326  				"id":          "networkred",
   327  				"name":        "Networkred",
   328  				"description": "",
   329  				"tenant_id":   memberTenantID,
   330  			}
   331  
   332  			invalidNetwork := getNetwork("red", "demo")
   333  			invalidNetwork["tenant_id"] = "demo"
   334  
   335  			resultExpected := map[string]interface{}{
   336  				"network": networkExpected,
   337  			}
   338  
   339  			testURL("POST", networkPluralURL, memberTokenID, invalidNetwork, http.StatusUnauthorized)
   340  			result := testURL("POST", networkPluralURL, memberTokenID, network, http.StatusCreated)
   341  			Expect(result).To(util.MatchAsJSON(resultExpected))
   342  
   343  			result = testURL("GET", networkPluralURL, memberTokenID, nil, http.StatusOK)
   344  			Expect(result).To(HaveKeyWithValue("networks", ConsistOf(util.MatchAsJSON(networkExpected))))
   345  
   346  			result = testURL("GET", getNetworkSingularURL("red"), memberTokenID, nil, http.StatusOK)
   347  			Expect(result).To(HaveKeyWithValue("network", networkExpected))
   348  
   349  			result = testURL("GET", baseURL+"/_all", memberTokenID, nil, http.StatusOK)
   350  			Expect(result).To(HaveLen(3))
   351  			Expect(result).To(HaveKeyWithValue("networks", []interface{}{networkExpected}))
   352  			Expect(result).To(HaveKey("schemas"))
   353  			Expect(result).To(HaveKey("tests"))
   354  
   355  			testURL("GET", baseURL+"/v2.0/network/unknownID", memberTokenID, nil, http.StatusNotFound)
   356  
   357  			testURL("POST", subnetPluralURL, memberTokenID, getSubnet("red", "red", "networkred"), http.StatusUnauthorized)
   358  			testURL("GET", getSubnetSingularURL("red"), memberTokenID, nil, http.StatusUnauthorized)
   359  			testURL("PUT", getSubnetSingularURL("red"), memberTokenID, getSubnet("red", "red", "networkred"), http.StatusUnauthorized)
   360  
   361  			testURL("PUT", getNetworkSingularURL("red"), memberTokenID, invalidNetwork, http.StatusUnauthorized)
   362  			testURL("PUT", getNetworkSingularURL("red"), memberTokenID, network, http.StatusBadRequest)
   363  
   364  			testURL("DELETE", getSubnetSingularURL("red"), memberTokenID, nil, http.StatusUnauthorized)
   365  			testURL("DELETE", getNetworkSingularURL("red"), memberTokenID, nil, http.StatusNoContent)
   366  			testURL("DELETE", getNetworkSingularURL("red"), memberTokenID, nil, http.StatusNotFound)
   367  		})
   368  	})
   369  
   370  	Describe("StringQueries", func() {
   371  		It("should work", func() {
   372  			testURL("POST", networkPluralURL, adminTokenID, getNetwork("red", "red"), http.StatusCreated)
   373  			testURL("POST", networkPluralURL, adminTokenID, getNetwork("red1", "red"), http.StatusCreated)
   374  
   375  			testURL("POST", networkPluralURL, adminTokenID, getNetwork("red2", "blue"), http.StatusCreated)
   376  			testURL("POST", networkPluralURL, adminTokenID, getNetwork("red3", "blue"), http.StatusCreated)
   377  
   378  			result := testURL("GET", networkPluralURL, adminTokenID, nil, http.StatusOK)
   379  			Expect(result).To(HaveKeyWithValue("networks", ConsistOf(
   380  				util.MatchAsJSON(getNetwork("red", "red")),
   381  				util.MatchAsJSON(getNetwork("red1", "red")),
   382  				util.MatchAsJSON(getNetwork("red2", "blue")),
   383  				util.MatchAsJSON(getNetwork("red3", "blue")))))
   384  
   385  			result = testURL("GET", networkPluralURL+"?tenant_id=red", adminTokenID, nil, http.StatusOK)
   386  			Expect(result).To(HaveKeyWithValue("networks", ConsistOf(
   387  				util.MatchAsJSON(getNetwork("red", "red")),
   388  				util.MatchAsJSON(getNetwork("red1", "red")))))
   389  
   390  			result = testURL("GET", networkPluralURL+"?id=networkred&id=networkred1", adminTokenID, nil, http.StatusOK)
   391  			Expect(result).To(HaveKeyWithValue("networks", ConsistOf(
   392  				util.MatchAsJSON(getNetwork("red", "red")),
   393  				util.MatchAsJSON(getNetwork("red1", "red")))))
   394  
   395  			result = testURL("GET", networkPluralURL+"?id=networkred&id=networkred1&id=networkred2&tenant_id=blue", adminTokenID, nil, http.StatusOK)
   396  			Expect(result).To(HaveKeyWithValue("networks", ConsistOf(
   397  				util.MatchAsJSON(getNetwork("red2", "blue")))))
   398  			testURL("DELETE", getNetworkSingularURL("red"), adminTokenID, nil, http.StatusNoContent)
   399  			testURL("DELETE", getNetworkSingularURL("red1"), adminTokenID, nil, http.StatusNoContent)
   400  			testURL("DELETE", getNetworkSingularURL("red2"), adminTokenID, nil, http.StatusNoContent)
   401  			testURL("DELETE", getNetworkSingularURL("red3"), adminTokenID, nil, http.StatusNoContent)
   402  		})
   403  	})
   404  
   405  	Describe("BoolQueries", func() {
   406  		It("should work", func() {
   407  			network1 := getNetwork("red1", "red")
   408  			network1["shared"] = true
   409  			network2 := getNetwork("red2", "red")
   410  			network2["shared"] = true
   411  			network3 := getNetwork("red3", "red")
   412  			network4 := getNetwork("red4", "red")
   413  
   414  			testURL("POST", networkPluralURL, adminTokenID, network1, http.StatusCreated)
   415  			testURL("POST", networkPluralURL, adminTokenID, network2, http.StatusCreated)
   416  			testURL("POST", networkPluralURL, adminTokenID, network3, http.StatusCreated)
   417  			testURL("POST", networkPluralURL, adminTokenID, network4, http.StatusCreated)
   418  
   419  			result := testURL("GET", networkPluralURL+"?shared=true", adminTokenID, nil, http.StatusOK)
   420  			Expect(result).To(HaveKeyWithValue("networks", ConsistOf(
   421  				util.MatchAsJSON(network1),
   422  				util.MatchAsJSON(network2))))
   423  			result = testURL("GET", networkPluralURL+"?shared=True", adminTokenID, nil, http.StatusOK)
   424  			Expect(result).To(HaveKeyWithValue("networks", ConsistOf(
   425  				util.MatchAsJSON(network1),
   426  				util.MatchAsJSON(network2))))
   427  
   428  			result = testURL("GET", networkPluralURL+"?shared=false", adminTokenID, nil, http.StatusOK)
   429  			Expect(result).To(HaveKeyWithValue("networks", ConsistOf(
   430  				util.MatchAsJSON(network3),
   431  				util.MatchAsJSON(network4))))
   432  			result = testURL("GET", networkPluralURL+"?shared=False", adminTokenID, nil, http.StatusOK)
   433  			Expect(result).To(HaveKeyWithValue("networks", ConsistOf(
   434  				util.MatchAsJSON(network3),
   435  				util.MatchAsJSON(network4))))
   436  		})
   437  	})
   438  
   439  	Describe("FullParentPath", func() {
   440  		It("should work", func() {
   441  			networkRed := getNetwork("red", "red")
   442  			networkBlue := getNetwork("blue", "red")
   443  			subnetRed := getSubnet("red", "red", "networkred")
   444  			subnetBlue := getSubnet("blue", "red", "networkred")
   445  			subnetYellow := getSubnet("yellow", "red", "networkblue")
   446  
   447  			testURL("POST", networkPluralURL, adminTokenID, networkRed, http.StatusCreated)
   448  			testURL("POST", networkPluralURL, adminTokenID, networkBlue, http.StatusCreated)
   449  			testURL("POST", getSubnetFullPluralURL("red"), adminTokenID, subnetRed, http.StatusCreated)
   450  			testURL("POST", getSubnetFullPluralURL("red"), adminTokenID, subnetBlue, http.StatusCreated)
   451  			testURL("POST", getSubnetFullPluralURL("blue"), adminTokenID, subnetYellow, http.StatusCreated)
   452  			result := testURL("GET", getSubnetFullPluralURL("red"), adminTokenID, nil, http.StatusOK)
   453  			Expect(result).To(HaveKeyWithValue("subnets", ConsistOf(
   454  				util.MatchAsJSON(subnetBlue),
   455  				util.MatchAsJSON(subnetRed))))
   456  
   457  			subnetRed["name"] = "subnetRedUpdated"
   458  
   459  			testURL("PUT", getSubnetFullSingularURL("red", "red"), adminTokenID, map[string]interface{}{"name": "subnetRedUpdated"}, http.StatusOK)
   460  			result = testURL("GET", getSubnetFullPluralURL("red"), adminTokenID, nil, http.StatusOK)
   461  			Expect(result).To(HaveKeyWithValue("subnets", ConsistOf(
   462  				util.MatchAsJSON(subnetBlue),
   463  				util.MatchAsJSON(subnetRed))))
   464  
   465  			testURL("DELETE", getSubnetFullSingularURL("red", "red"), adminTokenID, nil, http.StatusNoContent)
   466  			testURL("DELETE", getSubnetFullSingularURL("red", "blue"), adminTokenID, nil, http.StatusNoContent)
   467  		})
   468  	})
   469  
   470  	Describe("ExtensionErrorReporting", func() {
   471  		It("should work", func() {
   472  			dummyError := map[string]interface{}{
   473  				"error": "Dummy error.",
   474  			}
   475  			result := testURL("POST", testPluralURL, adminTokenID, map[string]interface{}{
   476  				"id": "dummyid",
   477  			}, 390)
   478  			Expect(result).To(util.MatchAsJSON(dummyError))
   479  		})
   480  	})
   481  
   482  	Describe("WrappedResourceRequests", func() {
   483  		It("should work", func() {
   484  			testURL("GET", getNetworkSingularURL("cyan"), adminTokenID, nil, http.StatusNotFound)
   485  
   486  			network := getNetwork("cyan", adminTenantID)
   487  			wrappedRequest := map[string]interface{}{"network": network}
   488  			testURL("POST", networkPluralURL, adminTokenID, wrappedRequest, http.StatusCreated)
   489  			defer testURL("DELETE", getNetworkSingularURL("cyan"), adminTokenID, nil, http.StatusNoContent)
   490  
   491  			wrappedRequest = map[string]interface{}{
   492  				"network": map[string]interface{}{
   493  					"name": "UpdatedName",
   494  				},
   495  			}
   496  			response := testURL("PUT", getNetworkSingularURL("cyan"), adminTokenID, wrappedRequest, http.StatusOK)
   497  			Expect(response).To(HaveKeyWithValue("network", HaveKeyWithValue("name", "UpdatedName")))
   498  		})
   499  	})
   500  
   501  	Describe("ResourceSharing", func() {
   502  		It("should work", func() {
   503  			memberNetwork := map[string]interface{}{
   504  				"id":          "networkbeige",
   505  				"name":        "Networkbeige",
   506  				"description": "The Beige Network",
   507  				"tenant_id":   memberTenantID,
   508  			}
   509  			testURL("POST", networkPluralURL, powerUserTokenID, memberNetwork, http.StatusCreated)
   510  
   511  			powerUserNetwork := getNetwork("pink", powerUserTenantID)
   512  			testURL("POST", networkPluralURL, powerUserTokenID, powerUserNetwork, http.StatusCreated)
   513  			defer testURL("DELETE", getNetworkSingularURL("pink"), powerUserTokenID, nil, http.StatusNoContent)
   514  
   515  			expectedNetworks := []interface{}{
   516  				HaveKeyWithValue("tenant_id", memberTenantID),
   517  				HaveKeyWithValue("tenant_id", powerUserTenantID),
   518  			}
   519  			memberNetworks := testURL("GET", networkPluralURL, memberTokenID, nil, http.StatusOK)
   520  			Expect(memberNetworks).To(HaveKeyWithValue("networks", ConsistOf(expectedNetworks...)))
   521  			powerUserNetworks := testURL("GET", networkPluralURL, powerUserTokenID, nil, http.StatusOK)
   522  			Expect(powerUserNetworks).To(HaveKeyWithValue("networks", ConsistOf(expectedNetworks...)))
   523  
   524  			pinkUpdate := map[string]interface{}{
   525  				"description": "Updated Pink Network",
   526  			}
   527  			testURL("PUT", getNetworkSingularURL("pink"), memberTokenID, pinkUpdate, http.StatusOK)
   528  			beigeUpdate := map[string]interface{}{
   529  				"description": "Updated Beige Network",
   530  			}
   531  			testURL("PUT", getNetworkSingularURL("beige"), powerUserTokenID, beigeUpdate, http.StatusOK)
   532  
   533  			testURL("DELETE", getNetworkSingularURL("pink"), memberTokenID, nil, http.StatusNotFound)
   534  		})
   535  	})
   536  
   537  	Describe("Sync", func() {
   538  		It("should work", func() {
   539  			manager := schema.GetManager()
   540  			networkSchema, _ := manager.Schema("network")
   541  			network := getNetwork("Red", "red")
   542  			networkResource, err := manager.LoadResource("network", network)
   543  			Expect(err).ToNot(HaveOccurred())
   544  			testDB1 := &srv.DbSyncWrapper{DB: testDB}
   545  			tx, err := testDB1.Begin()
   546  			Expect(err).ToNot(HaveOccurred())
   547  			Expect(tx.Create(networkResource)).To(Succeed())
   548  			Expect(tx.Commit()).To(Succeed())
   549  			tx.Close()
   550  
   551  			Expect(server.Sync()).To(Succeed())
   552  
   553  			sync := gohan_etcd.NewSync(nil)
   554  
   555  			writtenConfigRaw, err := sync.Fetch("config/" + networkResource.Path())
   556  			Expect(err).ToNot(HaveOccurred())
   557  			writtenConfig, ok := writtenConfigRaw.(*etcd.Response)
   558  			Expect(ok).To(BeTrue())
   559  
   560  			var configContentsRaw interface{}
   561  			Expect(json.Unmarshal([]byte(writtenConfig.Node.Value), &configContentsRaw)).To(Succeed())
   562  			configContents, ok := configContentsRaw.(map[string]interface{})
   563  			Expect(ok).To(BeTrue())
   564  			Expect(configContents).To(HaveKeyWithValue("version", float64(1)))
   565  			var configNetworkRaw interface{}
   566  			Expect(json.Unmarshal([]byte(configContents["body"].(string)), &configNetworkRaw)).To(Succeed())
   567  			configNetwork, ok := configNetworkRaw.(map[string]interface{})
   568  			Expect(ok).To(BeTrue())
   569  			Expect(configNetwork).To(util.MatchAsJSON(network))
   570  
   571  			tx, err = testDB1.Begin()
   572  			Expect(err).ToNot(HaveOccurred())
   573  			Expect(tx.Delete(networkSchema, networkResource.ID())).To(Succeed())
   574  			Expect(tx.Commit()).To(Succeed())
   575  			tx.Close()
   576  
   577  			Expect(server.Sync()).To(Succeed())
   578  
   579  			_, err = sync.Fetch(networkResource.Path())
   580  			Expect(err).To(HaveOccurred(), "Failed to sync db resource deletion to sync backend")
   581  		})
   582  	})
   583  
   584  	Describe("Updating the state", func() {
   585  		const (
   586  			statePrefix      = "/state"
   587  			monitoringPrefix = "/monitoring"
   588  		)
   589  		var (
   590  			networkSchema   *schema.Schema
   591  			networkResource *schema.Resource
   592  			wrappedTestDB   db.DB
   593  			possibleEvent   gohan_sync.Event
   594  		)
   595  
   596  		BeforeEach(func() {
   597  			manager := schema.GetManager()
   598  			var ok bool
   599  			networkSchema, ok = manager.Schema("network")
   600  			Expect(ok).To(BeTrue())
   601  			network := getNetwork("Red", "red")
   602  			var err error
   603  			networkResource, err = manager.LoadResource("network", network)
   604  			Expect(err).ToNot(HaveOccurred())
   605  			wrappedTestDB = &srv.DbSyncWrapper{DB: testDB}
   606  			tx, err := wrappedTestDB.Begin()
   607  			defer tx.Close()
   608  			Expect(err).ToNot(HaveOccurred())
   609  			Expect(tx.Create(networkResource)).To(Succeed())
   610  			Expect(tx.Commit()).To(Succeed())
   611  		})
   612  
   613  		Describe("Updating state", func() {
   614  			Context("Invoked correctly", func() {
   615  				It("Should work", func() {
   616  					possibleEvent = gohan_sync.Event{
   617  						Action: "this is ignored here",
   618  						Data: map[string]interface{}{
   619  							"version": float64(1),
   620  							"error":   "",
   621  							"state":   "Ni malvarmetas",
   622  						},
   623  						Key: statePrefix + networkResource.Path(),
   624  					}
   625  					Expect(srv.StateUpdate(&possibleEvent, server)).To(Succeed())
   626  
   627  					tx, err := wrappedTestDB.Begin()
   628  					Expect(err).ToNot(HaveOccurred())
   629  					defer tx.Close()
   630  					afterState, err := tx.StateFetch(networkSchema, networkResource.ID(), nil)
   631  					Expect(err).ToNot(HaveOccurred())
   632  					Expect(tx.Commit()).To(Succeed())
   633  					Expect(afterState.ConfigVersion).To(Equal(int64(1)))
   634  					Expect(afterState.StateVersion).To(Equal(int64(1)))
   635  					Expect(afterState.State).To(Equal("Ni malvarmetas"))
   636  					Expect(afterState.Error).To(Equal(""))
   637  					Expect(afterState.Monitoring).To(Equal(""))
   638  				})
   639  
   640  				It("Should ignore backwards updates", func() {
   641  					possibleEvent = gohan_sync.Event{
   642  						Action: "this is ignored here",
   643  						Data: map[string]interface{}{
   644  							"version": float64(1),
   645  							"error":   "",
   646  							"state":   "Ni malvarmetas",
   647  						},
   648  						Key: statePrefix + networkResource.Path(),
   649  					}
   650  					Expect(srv.StateUpdate(&possibleEvent, server)).To(Succeed())
   651  					possibleEvent = gohan_sync.Event{
   652  						Action: "this is ignored here",
   653  						Data: map[string]interface{}{
   654  							"version": float64(0),
   655  							"error":   "",
   656  							"state":   "Ni varmegas",
   657  						},
   658  						Key: statePrefix + networkResource.Path(),
   659  					}
   660  					Expect(srv.StateUpdate(&possibleEvent, server)).To(Succeed())
   661  
   662  					tx, err := wrappedTestDB.Begin()
   663  					Expect(err).ToNot(HaveOccurred())
   664  					defer tx.Close()
   665  					afterState, err := tx.StateFetch(networkSchema, networkResource.ID(), nil)
   666  					Expect(err).ToNot(HaveOccurred())
   667  					Expect(tx.Commit()).To(Succeed())
   668  					Expect(afterState.ConfigVersion).To(Equal(int64(1)))
   669  					Expect(afterState.StateVersion).To(Equal(int64(1)))
   670  					Expect(afterState.State).To(Equal("Ni malvarmetas"))
   671  					Expect(afterState.Error).To(Equal(""))
   672  					Expect(afterState.Monitoring).To(Equal(""))
   673  				})
   674  
   675  				It("Should ignore status updates beyond the most recent config version", func() {
   676  					possibleEvent = gohan_sync.Event{
   677  						Action: "this is ignored here",
   678  						Data: map[string]interface{}{
   679  							"version": float64(1),
   680  							"error":   "",
   681  							"state":   "Ni malvarmetas",
   682  						},
   683  						Key: statePrefix + networkResource.Path(),
   684  					}
   685  					Expect(srv.StateUpdate(&possibleEvent, server)).To(Succeed())
   686  					possibleEvent = gohan_sync.Event{
   687  						Action: "this is ignored here",
   688  						Data: map[string]interface{}{
   689  							"version": float64(1),
   690  							"error":   "",
   691  							"state":   "Ni varmegas",
   692  						},
   693  						Key: statePrefix + networkResource.Path(),
   694  					}
   695  					Expect(srv.StateUpdate(&possibleEvent, server)).To(Succeed())
   696  
   697  					tx, err := wrappedTestDB.Begin()
   698  					Expect(err).ToNot(HaveOccurred())
   699  					defer tx.Close()
   700  					afterState, err := tx.StateFetch(networkSchema, networkResource.ID(), nil)
   701  					Expect(err).ToNot(HaveOccurred())
   702  					Expect(tx.Commit()).To(Succeed())
   703  					Expect(afterState.ConfigVersion).To(Equal(int64(1)))
   704  					Expect(afterState.StateVersion).To(Equal(int64(1)))
   705  					Expect(afterState.State).To(Equal("Ni malvarmetas"))
   706  					Expect(afterState.Error).To(Equal(""))
   707  					Expect(afterState.Monitoring).To(Equal(""))
   708  				})
   709  			})
   710  
   711  			Context("Invoked incorrectly", func() {
   712  				It("With wrong key should return nil", func() {
   713  					possibleEvent = gohan_sync.Event{
   714  						Action: "this is ignored here",
   715  						Data: map[string]interface{}{
   716  							"version": float64(1),
   717  							"error":   "",
   718  							"state":   "Ni malvarmetas",
   719  						},
   720  						Key: statePrefix + strings.Replace(networkResource.Path(), "network", "netwerk", 1),
   721  					}
   722  					err := srv.StateUpdate(&possibleEvent, server)
   723  					Expect(err).ToNot(HaveOccurred())
   724  				})
   725  
   726  				It("With wrong resource ID should return the proper error", func() {
   727  					possibleEvent = gohan_sync.Event{
   728  						Action: "this is ignored here",
   729  						Data: map[string]interface{}{
   730  							"version": float64(1),
   731  							"error":   "",
   732  							"state":   "Ni malvarmetas",
   733  						},
   734  						Key: statePrefix + networkResource.Path() + "malesta",
   735  					}
   736  					err := srv.StateUpdate(&possibleEvent, server)
   737  					Expect(err).To(MatchError(ContainSubstring("Failed to fetch")))
   738  				})
   739  
   740  				It("Without version should return the proper error", func() {
   741  					possibleEvent = gohan_sync.Event{
   742  						Action: "this is ignored here",
   743  						Data: map[string]interface{}{
   744  							"error": "",
   745  							"state": "Ni malvarmetas",
   746  						},
   747  						Key: statePrefix + networkResource.Path(),
   748  					}
   749  					err := srv.StateUpdate(&possibleEvent, server)
   750  					Expect(err).To(MatchError(ContainSubstring("No version")))
   751  				})
   752  			})
   753  		})
   754  
   755  		Context("Updating the monitoring state", func() {
   756  			Context("Invoked correctly", func() {
   757  				It("Should work", func() {
   758  					possibleEvent = gohan_sync.Event{
   759  						Action: "this is ignored here",
   760  						Data: map[string]interface{}{
   761  							"version": float64(1),
   762  							"error":   "",
   763  							"state":   "Ni malvarmetas",
   764  						},
   765  						Key: statePrefix + networkResource.Path(),
   766  					}
   767  					Expect(srv.StateUpdate(&possibleEvent, server)).To(Succeed())
   768  					possibleEvent = gohan_sync.Event{
   769  						Action: "this is ignored here",
   770  						Data: map[string]interface{}{
   771  							"monitoring": "Ni rigardas tio",
   772  						},
   773  						Key: monitoringPrefix + networkResource.Path(),
   774  					}
   775  					Expect(srv.MonitoringUpdate(&possibleEvent, server)).To(Succeed())
   776  
   777  					tx, err := wrappedTestDB.Begin()
   778  					Expect(err).ToNot(HaveOccurred())
   779  					defer tx.Close()
   780  					afterMonitoring, err := tx.StateFetch(networkSchema, networkResource.ID(), nil)
   781  					Expect(err).ToNot(HaveOccurred())
   782  					Expect(tx.Commit()).To(Succeed())
   783  					Expect(afterMonitoring.ConfigVersion).To(Equal(int64(1)))
   784  					Expect(afterMonitoring.StateVersion).To(Equal(int64(1)))
   785  					Expect(afterMonitoring.State).To(Equal("Ni malvarmetas"))
   786  					Expect(afterMonitoring.Error).To(Equal(""))
   787  					Expect(afterMonitoring.Monitoring).To(Equal("Ni rigardas tio"))
   788  				})
   789  
   790  				It("Should igonre updates if state is not up to date", func() {
   791  					possibleEvent = gohan_sync.Event{
   792  						Action: "this is ignored here",
   793  						Data: map[string]interface{}{
   794  							"monitoring": "Ni rigardas tio",
   795  						},
   796  						Key: monitoringPrefix + networkResource.Path(),
   797  					}
   798  					Expect(srv.MonitoringUpdate(&possibleEvent, server)).To(Succeed())
   799  
   800  					tx, err := wrappedTestDB.Begin()
   801  					Expect(err).ToNot(HaveOccurred())
   802  					defer tx.Close()
   803  					afterMonitoring, err := tx.StateFetch(networkSchema, networkResource.ID(), nil)
   804  					Expect(err).ToNot(HaveOccurred())
   805  					Expect(tx.Commit()).To(Succeed())
   806  					Expect(afterMonitoring.ConfigVersion).To(Equal(int64(1)))
   807  					Expect(afterMonitoring.StateVersion).To(Equal(int64(0)))
   808  					Expect(afterMonitoring.State).To(Equal(""))
   809  					Expect(afterMonitoring.Error).To(Equal(""))
   810  					Expect(afterMonitoring.Monitoring).To(Equal(""))
   811  				})
   812  			})
   813  
   814  			Context("Invoked incorrectly", func() {
   815  				It("With wrong key should return nil", func() {
   816  					possibleEvent = gohan_sync.Event{
   817  						Action: "this is ignored here",
   818  						Data: map[string]interface{}{
   819  							"monitoring": "Ni rigardas tio",
   820  						},
   821  						Key: monitoringPrefix + strings.Replace(networkResource.Path(), "network", "netwerk", 1),
   822  					}
   823  					err := srv.MonitoringUpdate(&possibleEvent, server)
   824  					Expect(err).ToNot(HaveOccurred())
   825  				})
   826  
   827  				It("With wrong resource ID should return the proper error", func() {
   828  					possibleEvent = gohan_sync.Event{
   829  						Action: "this is ignored here",
   830  						Data: map[string]interface{}{
   831  							"monitoring": "Ni rigardas tio",
   832  						},
   833  						Key: monitoringPrefix + networkResource.Path() + "malesta",
   834  					}
   835  					err := srv.MonitoringUpdate(&possibleEvent, server)
   836  					Expect(err).To(MatchError(ContainSubstring("Failed to fetch")))
   837  				})
   838  
   839  				It("Without monitoring should return the proper error", func() {
   840  					possibleEvent = gohan_sync.Event{
   841  						Action: "this is ignored here",
   842  						Data: map[string]interface{}{
   843  							"version": float64(1),
   844  							"error":   "",
   845  							"state":   "Ni malvarmetas",
   846  						},
   847  						Key: statePrefix + networkResource.Path(),
   848  					}
   849  					Expect(srv.StateUpdate(&possibleEvent, server)).To(Succeed())
   850  					possibleEvent = gohan_sync.Event{
   851  						Action: "this is ignored here",
   852  						Data:   map[string]interface{}{},
   853  						Key:    monitoringPrefix + networkResource.Path(),
   854  					}
   855  					err := srv.MonitoringUpdate(&possibleEvent, server)
   856  					Expect(err).To(MatchError(ContainSubstring("No monitoring")))
   857  				})
   858  			})
   859  		})
   860  	})
   861  
   862  	Describe("Resource Actions", func() {
   863  		responderPluralURL := baseURL + "/v2.0/responders"
   864  
   865  		BeforeEach(func() {
   866  			responder := map[string]interface{}{
   867  				"id":        "r1",
   868  				"pattern":   "Hello %s!",
   869  				"tenant_id": memberTenantID,
   870  			}
   871  			testURL("POST", responderPluralURL, adminTokenID, responder, http.StatusCreated)
   872  		})
   873  
   874  		It("should work", func() {
   875  			testHelloAction := map[string]interface{}{
   876  				"name": "Heisenberg",
   877  			}
   878  
   879  			result := testURL("POST", responderPluralURL+"/r1/hello", memberTokenID, testHelloAction, http.StatusOK)
   880  			Expect(result).To(Equal(map[string]interface{}{
   881  				"output": "Hello, Heisenberg!",
   882  			}))
   883  		})
   884  
   885  		It("should be unauthorized", func() {
   886  			testHiAction := map[string]interface{}{
   887  				"name": "Heisenberg",
   888  			}
   889  
   890  			result := testURL("POST", responderPluralURL+"/r1/hi", memberTokenID, testHiAction, http.StatusUnauthorized)
   891  			Expect(result).To(HaveKey("error"))
   892  		})
   893  
   894  		It("should be invalid requests", func() {
   895  			badAction1 := map[string]interface{}{}
   896  			result := testURL("POST", responderPluralURL+"/r1/hello", memberTokenID, badAction1, http.StatusBadRequest)
   897  			Expect(result).To(HaveKey("error"))
   898  
   899  			badAction2 := map[string]interface{}{
   900  				"hello": "Heisenberg",
   901  				"hi":    "Heisenberg",
   902  			}
   903  			result = testURL("POST", responderPluralURL+"/r1/hello", memberTokenID, badAction2, http.StatusBadRequest)
   904  			Expect(result).To(HaveKey("error"))
   905  
   906  			badAction3 := map[string]interface{}{
   907  				"hello": map[string]interface{}{
   908  					"familyName": "Heisenberg",
   909  				},
   910  			}
   911  			result = testURL("POST", responderPluralURL+"/r1/hello", memberTokenID, badAction3, http.StatusBadRequest)
   912  			Expect(result).To(HaveKey("error"))
   913  
   914  			unknownAction := map[string]interface{}{
   915  				"name": "Heisenberg",
   916  			}
   917  			result = testURL("POST", responderPluralURL+"/r1/dzien_dobry", memberTokenID, unknownAction, http.StatusNotFound)
   918  
   919  			result = testURL("POST", responderPluralURL+"/r1/dzien_dobry", adminTokenID, unknownAction, http.StatusNotFound)
   920  		})
   921  	})
   922  })
   923  
   924  func BenchmarkPOSTAPI(b *testing.B) {
   925  	err := initBenchmarkDatabase()
   926  	if err != nil {
   927  		b.Fatal(err)
   928  	}
   929  
   930  	err = startTestServer("./server_test_mysql_config.yaml")
   931  	if err != nil {
   932  		b.Fatal(err)
   933  	}
   934  
   935  	b.ResetTimer()
   936  	for i := 0; i < b.N; i++ {
   937  		network := getNetwork("red"+strconv.Itoa(i), "red")
   938  		httpRequest("POST", networkPluralURL, adminTokenID, network)
   939  	}
   940  }
   941  
   942  func BenchmarkGETAPI(b *testing.B) {
   943  	err := initBenchmarkDatabase()
   944  	if err != nil {
   945  		b.Fatal(err)
   946  	}
   947  
   948  	err = startTestServer("./server_test_mysql_config.yaml")
   949  	if err != nil {
   950  		b.Fatal(err)
   951  	}
   952  
   953  	network := getNetwork("red", "red")
   954  	httpRequest("POST", networkPluralURL, adminTokenID, network)
   955  
   956  	b.ResetTimer()
   957  	for i := 0; i < b.N; i++ {
   958  		httpRequest("GET", getNetworkSingularURL("red"), adminTokenID, nil)
   959  	}
   960  }
   961  
   962  func initBenchmarkDatabase() error {
   963  	schema.ClearManager()
   964  	manager := schema.GetManager()
   965  	manager.LoadSchemasFromFiles("../tests/test_schema.yaml", "../etc/schema/gohan.json")
   966  	err := db.InitDBWithSchemas("mysql", "root@tcp(localhost:3306)/gohan_test", false, false)
   967  	if err != nil {
   968  		return err
   969  	}
   970  	return nil
   971  }
   972  
   973  func startTestServer(config string) error {
   974  	var err error
   975  	server, err = srv.NewServer(config)
   976  	if err != nil {
   977  		return err
   978  	}
   979  	go func() {
   980  		err := server.Start()
   981  		if err != nil {
   982  			return
   983  		}
   984  	}()
   985  	defer server.Stop()
   986  	return nil
   987  }
   988  
   989  func getNetwork(color string, tenant string) map[string]interface{} {
   990  	return map[string]interface{}{
   991  		"id":                "network" + color,
   992  		"name":              "Network" + color,
   993  		"description":       "The " + color + " Network",
   994  		"tenant_id":         tenant,
   995  		"route_targets":     []string{"1000:10000", "2000:20000"},
   996  		"shared":            false,
   997  		"providor_networks": map[string]interface{}{"segmentation_id": 12, "segmentation_type": "vlan"},
   998  	}
   999  }
  1000  
  1001  func getSubnet(color string, tenant string, parent string) map[string]interface{} {
  1002  	return map[string]interface{}{
  1003  		"id":          "subnet" + color,
  1004  		"name":        "Subnet" + color,
  1005  		"description": "The " + color + " Subnet",
  1006  		"tenant_id":   tenant,
  1007  		"cidr":        "10.0.0.0/24",
  1008  		"network_id":  parent,
  1009  	}
  1010  }
  1011  
  1012  func getNetworkSingularURL(color string) string {
  1013  	s, _ := schema.GetManager().Schema("network")
  1014  	return baseURL + s.URL + "/network" + color
  1015  }
  1016  
  1017  func getSubnetSingularURL(color string) string {
  1018  	s, _ := schema.GetManager().Schema("subnet")
  1019  	return baseURL + s.URL + "/subnet" + color
  1020  }
  1021  
  1022  func getSubnetFullSingularURL(networkColor, subnetColor string) string {
  1023  	return getSubnetFullPluralURL(networkColor) + "/subnet" + subnetColor
  1024  }
  1025  
  1026  func getSubnetFullPluralURL(networkColor string) string {
  1027  	s, _ := schema.GetManager().Schema("network")
  1028  	return baseURL + s.URL + "/network" + networkColor + "/subnets"
  1029  }
  1030  
  1031  func testURL(method, url, token string, postData interface{}, expectedCode int) interface{} {
  1032  	data, resp := httpRequest(method, url, token, postData)
  1033  	jsonData, _ := json.MarshalIndent(data, "", "    ")
  1034  	ExpectWithOffset(1, resp.StatusCode).To(Equal(expectedCode), string(jsonData))
  1035  	return data
  1036  }
  1037  
  1038  func httpRequest(method, url, token string, postData interface{}) (interface{}, *http.Response) {
  1039  	client := &http.Client{}
  1040  	var reader io.Reader
  1041  	if postData != nil {
  1042  		jsonByte, err := json.Marshal(postData)
  1043  		Expect(err).ToNot(HaveOccurred())
  1044  		reader = bytes.NewBuffer(jsonByte)
  1045  	}
  1046  	request, err := http.NewRequest(method, url, reader)
  1047  	Expect(err).ToNot(HaveOccurred())
  1048  	request.Header.Set("X-Auth-Token", token)
  1049  	var data interface{}
  1050  	resp, err := client.Do(request)
  1051  	Expect(err).ToNot(HaveOccurred())
  1052  	defer resp.Body.Close()
  1053  	decoder := json.NewDecoder(resp.Body)
  1054  	decoder.Decode(&data)
  1055  	return data, resp
  1056  }
  1057  
  1058  func clearTable(tx transaction.Transaction, s *schema.Schema) error {
  1059  	for _, schema := range schema.GetManager().Schemas() {
  1060  		if schema.ParentSchema == s {
  1061  			err := clearTable(tx, schema)
  1062  			if err != nil {
  1063  				return err
  1064  			}
  1065  		}
  1066  	}
  1067  	resources, _, err := tx.List(s, nil, nil)
  1068  	if err != nil {
  1069  		return err
  1070  	}
  1071  	for _, resource := range resources {
  1072  		err = tx.Delete(s, resource.ID())
  1073  		if err != nil {
  1074  			return err
  1075  		}
  1076  	}
  1077  	return nil
  1078  }