github.com/vnpaycloud-console/gophercloud/v2@v2.0.5/openstack/containerinfra/v1/nodegroups/testing/fixtures_test.go (about)

     1  package testing
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/vnpaycloud-console/gophercloud/v2"
    10  	"github.com/vnpaycloud-console/gophercloud/v2/openstack/containerinfra/v1/nodegroups"
    11  	th "github.com/vnpaycloud-console/gophercloud/v2/testhelper"
    12  	fake "github.com/vnpaycloud-console/gophercloud/v2/testhelper/client"
    13  )
    14  
    15  const (
    16  	clusterUUID    = "bda75056-3a57-4ada-b943-658ac27beea0"
    17  	badClusterUUID = "252e2f37-d83e-4848-be39-eed1b41211ac"
    18  
    19  	nodeGroup1UUID   = "b2e581be-2eec-45b8-921a-c85fbc23aaa3"
    20  	nodeGroup2UUID   = "2457febf-520f-4be3-abb9-96b892d7b5a0"
    21  	badNodeGroupUUID = "4973f3aa-40a2-4857-bf9e-c15faffb08c8"
    22  )
    23  
    24  var (
    25  	nodeGroup1Created, _ = time.Parse(time.RFC3339, "2019-10-18T14:03:37+00:00")
    26  	nodeGroup1Updated, _ = time.Parse(time.RFC3339, "2019-10-18T14:18:35+00:00")
    27  
    28  	nodeGroup2Created, _ = time.Parse(time.RFC3339, "2019-10-18T14:03:37+00:00")
    29  	nodeGroup2Updated, _ = time.Parse(time.RFC3339, "2019-10-18T14:18:36+00:00")
    30  )
    31  
    32  var expectedNodeGroup1 = nodegroups.NodeGroup{
    33  	ID:               9,
    34  	UUID:             nodeGroup1UUID,
    35  	Name:             "default-master",
    36  	ClusterID:        clusterUUID,
    37  	ProjectID:        "e91d02d561374de6b49960a27b3f08d0",
    38  	DockerVolumeSize: nil,
    39  	Labels: map[string]string{
    40  		"kube_tag": "v1.14.7",
    41  	},
    42  	Links: []gophercloud.Link{
    43  		{
    44  			Href: "http://123.456.789.0:9511/v1/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups/b2e581be-2eec-45b8-921a-c85fbc23aaa3",
    45  			Rel:  "self",
    46  		},
    47  		{
    48  			Href: "http://123.456.789.0:9511/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups/b2e581be-2eec-45b8-921a-c85fbc23aaa3",
    49  			Rel:  "bookmark",
    50  		},
    51  	},
    52  	FlavorID:      "",
    53  	ImageID:       "Fedora-AtomicHost-29-20190820.0.x86_64",
    54  	NodeAddresses: []string{"172.24.4.19"},
    55  	NodeCount:     1,
    56  	Role:          "master",
    57  	MinNodeCount:  1,
    58  	MaxNodeCount:  nil,
    59  	IsDefault:     true,
    60  	StackID:       "3cd55bb0-1115-4838-8eca-cefc13f7a21b",
    61  	Status:        "UPDATE_COMPLETE",
    62  	StatusReason:  "Stack UPDATE completed successfully",
    63  	Version:       "",
    64  	CreatedAt:     nodeGroup1Created,
    65  	UpdatedAt:     nodeGroup1Updated,
    66  }
    67  
    68  var expectedCreatedNodeGroup = nodegroups.NodeGroup{
    69  	UUID:      "12542dd8-9588-42a7-a2ff-06f49049920c",
    70  	Name:      "test-ng",
    71  	ClusterID: clusterUUID,
    72  	ProjectID: "e91d02d561374de6b49960a27b3f08d0",
    73  	Labels: map[string]string{
    74  		"kube_tag": "v1.14.7",
    75  	},
    76  	Links: []gophercloud.Link{
    77  		{
    78  			Href: "http://123.456.789.0:9511/v1/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups/12542dd8-9588-42a7-a2ff-06f49049920c",
    79  			Rel:  "self",
    80  		},
    81  		{
    82  			Href: "http://123.456.789.0:9511/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups/12542dd8-9588-42a7-a2ff-06f49049920c",
    83  			Rel:  "bookmark",
    84  		},
    85  	},
    86  	FlavorID:     "m1.small",
    87  	ImageID:      "Fedora-AtomicHost-29-20190820.0.x86_64",
    88  	NodeCount:    1,
    89  	MinNodeCount: 1,
    90  	Role:         "worker",
    91  }
    92  
    93  var maxNodesThree = 3
    94  var expectedUpdatedNodeGroup = nodegroups.NodeGroup{
    95  	ID:        10,
    96  	UUID:      nodeGroup2UUID,
    97  	Name:      "default-worker",
    98  	ClusterID: clusterUUID,
    99  	ProjectID: "e91d02d561374de6b49960a27b3f08d0",
   100  	Labels: map[string]string{
   101  		"kube_tag": "v1.14.7",
   102  	},
   103  	Links: []gophercloud.Link{
   104  		{
   105  			Href: "http://123.456.789.0:9511/v1/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups/2457febf-520f-4be3-abb9-96b892d7b5a0",
   106  			Rel:  "self",
   107  		},
   108  		{
   109  			Href: "http://123.456.789.0:9511/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups/2457febf-520f-4be3-abb9-96b892d7b5a0",
   110  			Rel:  "bookmark",
   111  		},
   112  	},
   113  	FlavorID:      "m1.small",
   114  	ImageID:       "Fedora-AtomicHost-29-20190820.0.x86_64",
   115  	NodeAddresses: []string{"172.24.4.17"},
   116  	NodeCount:     1,
   117  	MinNodeCount:  1,
   118  	MaxNodeCount:  &maxNodesThree,
   119  	IsDefault:     true,
   120  	Role:          "worker",
   121  	StackID:       "3cd55bb0-1115-4838-8eca-cefc13f7a21b",
   122  	Status:        "UPDATE_COMPLETE",
   123  	StatusReason:  "Stack UPDATE completed successfully",
   124  	CreatedAt:     nodeGroup2Created,
   125  	UpdatedAt:     nodeGroup2Updated,
   126  }
   127  
   128  func handleGetNodeGroupSuccess(t *testing.T) {
   129  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups/"+nodeGroup1UUID, func(w http.ResponseWriter, r *http.Request) {
   130  		th.TestMethod(t, r, http.MethodGet)
   131  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   132  
   133  		w.Header().Add("Content-Type", "application/json")
   134  		w.WriteHeader(http.StatusOK)
   135  
   136  		fmt.Fprint(w, nodeGroupGetResponse)
   137  	})
   138  }
   139  
   140  func handleGetNodeGroupNotFound(t *testing.T) {
   141  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups/"+badNodeGroupUUID, func(w http.ResponseWriter, r *http.Request) {
   142  		th.TestMethod(t, r, http.MethodGet)
   143  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   144  
   145  		w.Header().Add("Content-Type", "application/json")
   146  		w.WriteHeader(http.StatusNotFound)
   147  
   148  		fmt.Fprint(w, nodeGroupGetNotFoundResponse)
   149  	})
   150  }
   151  
   152  func handleGetNodeGroupClusterNotFound(t *testing.T) {
   153  	th.Mux.HandleFunc("/v1/clusters/"+badClusterUUID+"/nodegroups/"+badNodeGroupUUID, func(w http.ResponseWriter, r *http.Request) {
   154  		th.TestMethod(t, r, http.MethodGet)
   155  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   156  
   157  		w.Header().Add("Content-Type", "application/json")
   158  		w.WriteHeader(http.StatusNotFound)
   159  
   160  		fmt.Fprint(w, nodeGroupGetClusterNotFoundResponse)
   161  	})
   162  }
   163  
   164  func handleListNodeGroupsSuccess(t *testing.T) {
   165  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups", func(w http.ResponseWriter, r *http.Request) {
   166  		th.TestMethod(t, r, http.MethodGet)
   167  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   168  
   169  		w.Header().Add("Content-Type", "application/json")
   170  		w.WriteHeader(http.StatusOK)
   171  
   172  		fmt.Fprint(w, nodeGroupListResponse)
   173  	})
   174  }
   175  
   176  func handleListNodeGroupsLimitSuccess(t *testing.T) {
   177  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups", func(w http.ResponseWriter, r *http.Request) {
   178  		th.TestMethod(t, r, http.MethodGet)
   179  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   180  
   181  		w.Header().Add("Content-Type", "application/json")
   182  		w.WriteHeader(http.StatusOK)
   183  
   184  		if err := r.ParseForm(); err != nil {
   185  			t.Errorf("Failed to parse request form %v", err)
   186  		}
   187  		if marker, ok := r.Form["marker"]; !ok {
   188  			// No marker, this is the first request.
   189  			th.TestFormValues(t, r, map[string]string{"limit": "1"})
   190  			fmt.Fprintf(w, nodeGroupListLimitResponse1, th.Endpoint())
   191  		} else {
   192  			switch marker[0] {
   193  			case nodeGroup1UUID:
   194  				// Marker is the UUID of the first node group, return the second.
   195  				fmt.Fprintf(w, nodeGroupListLimitResponse2, th.Endpoint())
   196  			case nodeGroup2UUID:
   197  				// Marker is the UUID of the second node group, there are no more to return.
   198  				fmt.Fprint(w, nodeGroupListLimitResponse3)
   199  			}
   200  		}
   201  	})
   202  }
   203  
   204  func handleListNodeGroupsClusterNotFound(t *testing.T) {
   205  	th.Mux.HandleFunc("/v1/clusters/"+badClusterUUID+"/nodegroups", func(w http.ResponseWriter, r *http.Request) {
   206  		th.TestMethod(t, r, http.MethodGet)
   207  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   208  
   209  		w.Header().Add("Content-Type", "application/json")
   210  		w.WriteHeader(http.StatusNotFound)
   211  
   212  		fmt.Fprint(w, nodeGroupListClusterNotFoundResponse)
   213  	})
   214  }
   215  
   216  func handleCreateNodeGroupSuccess(t *testing.T) {
   217  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups", func(w http.ResponseWriter, r *http.Request) {
   218  		th.TestMethod(t, r, http.MethodPost)
   219  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   220  
   221  		w.Header().Add("Content-Type", "application/json")
   222  		w.WriteHeader(http.StatusAccepted)
   223  
   224  		fmt.Fprint(w, nodeGroupCreateResponse)
   225  	})
   226  }
   227  
   228  func handleCreateNodeGroupDuplicate(t *testing.T) {
   229  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups", func(w http.ResponseWriter, r *http.Request) {
   230  		th.TestMethod(t, r, http.MethodPost)
   231  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   232  
   233  		w.Header().Add("Content-Type", "application/json")
   234  		w.WriteHeader(http.StatusConflict)
   235  
   236  		fmt.Fprint(w, nodeGroupCreateDuplicateResponse)
   237  	})
   238  }
   239  
   240  func handleCreateNodeGroupMaster(t *testing.T) {
   241  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups", func(w http.ResponseWriter, r *http.Request) {
   242  		th.TestMethod(t, r, http.MethodPost)
   243  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   244  
   245  		w.Header().Add("Content-Type", "application/json")
   246  		w.WriteHeader(http.StatusBadRequest)
   247  
   248  		fmt.Fprint(w, nodeGroupCreateMasterResponse)
   249  	})
   250  }
   251  
   252  func handleCreateNodeGroupBadSizes(t *testing.T) {
   253  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups", func(w http.ResponseWriter, r *http.Request) {
   254  		th.TestMethod(t, r, http.MethodPost)
   255  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   256  
   257  		w.Header().Add("Content-Type", "application/json")
   258  		w.WriteHeader(http.StatusConflict)
   259  
   260  		fmt.Fprint(w, nodeGroupCreateBadSizesResponse)
   261  	})
   262  }
   263  
   264  func handleUpdateNodeGroupSuccess(t *testing.T) {
   265  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups/"+nodeGroup2UUID, func(w http.ResponseWriter, r *http.Request) {
   266  		th.TestMethod(t, r, http.MethodPatch)
   267  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   268  
   269  		w.Header().Add("Content-Type", "application/json")
   270  		w.WriteHeader(http.StatusAccepted)
   271  
   272  		fmt.Fprint(w, nodeGroupUpdateResponse)
   273  	})
   274  }
   275  
   276  func handleUpdateNodeGroupInternal(t *testing.T) {
   277  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups/"+nodeGroup2UUID, func(w http.ResponseWriter, r *http.Request) {
   278  		th.TestMethod(t, r, http.MethodPatch)
   279  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   280  
   281  		w.Header().Add("Content-Type", "application/json")
   282  		w.WriteHeader(http.StatusBadRequest)
   283  
   284  		fmt.Fprint(w, nodeGroupUpdateInternalResponse)
   285  	})
   286  }
   287  
   288  func handleUpdateNodeGroupBadField(t *testing.T) {
   289  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups/"+nodeGroup2UUID, func(w http.ResponseWriter, r *http.Request) {
   290  		th.TestMethod(t, r, http.MethodPatch)
   291  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   292  
   293  		w.Header().Add("Content-Type", "application/json")
   294  		w.WriteHeader(http.StatusBadRequest)
   295  
   296  		fmt.Fprint(w, nodeGroupUpdateBadFieldResponse)
   297  	})
   298  }
   299  
   300  func handleUpdateNodeGroupBadMin(t *testing.T) {
   301  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups/"+nodeGroup2UUID, func(w http.ResponseWriter, r *http.Request) {
   302  		th.TestMethod(t, r, http.MethodPatch)
   303  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   304  
   305  		w.Header().Add("Content-Type", "application/json")
   306  		w.WriteHeader(http.StatusConflict)
   307  
   308  		fmt.Fprint(w, nodeGroupUpdateBadMinResponse)
   309  	})
   310  }
   311  
   312  func handleDeleteNodeGroupSuccess(t *testing.T) {
   313  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups/"+nodeGroup2UUID, func(w http.ResponseWriter, r *http.Request) {
   314  		th.TestMethod(t, r, http.MethodDelete)
   315  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   316  
   317  		w.WriteHeader(http.StatusNoContent)
   318  	})
   319  }
   320  
   321  func handleDeleteNodeGroupNotFound(t *testing.T) {
   322  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups/"+badNodeGroupUUID, func(w http.ResponseWriter, r *http.Request) {
   323  		th.TestMethod(t, r, http.MethodDelete)
   324  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   325  
   326  		w.Header().Add("Content-Type", "application/json")
   327  		w.WriteHeader(http.StatusNotFound)
   328  
   329  		fmt.Fprint(w, nodeGroupDeleteNotFoundResponse)
   330  	})
   331  }
   332  
   333  func handleDeleteNodeGroupClusterNotFound(t *testing.T) {
   334  	th.Mux.HandleFunc("/v1/clusters/"+badClusterUUID+"/nodegroups/"+badNodeGroupUUID, func(w http.ResponseWriter, r *http.Request) {
   335  		th.TestMethod(t, r, http.MethodDelete)
   336  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   337  
   338  		w.Header().Add("Content-Type", "application/json")
   339  		w.WriteHeader(http.StatusNotFound)
   340  
   341  		fmt.Fprint(w, nodeGroupDeleteClusterNotFoundResponse)
   342  	})
   343  }
   344  
   345  func handleDeleteNodeGroupDefault(t *testing.T) {
   346  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups/"+nodeGroup2UUID, func(w http.ResponseWriter, r *http.Request) {
   347  		th.TestMethod(t, r, http.MethodDelete)
   348  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   349  
   350  		w.Header().Add("Content-Type", "application/json")
   351  		w.WriteHeader(http.StatusBadRequest)
   352  
   353  		fmt.Fprint(w, nodeGroupDeleteDefaultResponse)
   354  	})
   355  }
   356  
   357  var nodeGroupGetResponse = fmt.Sprintf(`
   358  {
   359    "links":[
   360      {
   361        "href":"http://123.456.789.0:9511/v1/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups/b2e581be-2eec-45b8-921a-c85fbc23aaa3",
   362        "rel":"self"
   363      },
   364      {
   365        "href":"http://123.456.789.0:9511/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups/b2e581be-2eec-45b8-921a-c85fbc23aaa3",
   366        "rel":"bookmark"
   367      }
   368    ],
   369    "labels":{
   370      "kube_tag":"v1.14.7"
   371    },
   372    "updated_at":"2019-10-18T14:18:35+00:00",
   373    "cluster_id":"%s",
   374    "min_node_count":1,
   375    "id":9,
   376    "uuid":"%s",
   377    "version":null,
   378    "role":"master",
   379    "node_count":1,
   380    "project_id":"e91d02d561374de6b49960a27b3f08d0",
   381    "status":"UPDATE_COMPLETE",
   382    "docker_volume_size":null,
   383    "max_node_count":null,
   384    "is_default":true,
   385    "image_id":"Fedora-AtomicHost-29-20190820.0.x86_64",
   386    "node_addresses":[
   387      "172.24.4.19"
   388    ],
   389    "status_reason":"Stack UPDATE completed successfully",
   390    "name":"default-master",
   391    "stack_id":"3cd55bb0-1115-4838-8eca-cefc13f7a21b",
   392    "created_at":"2019-10-18T14:03:37+00:00",
   393    "flavor_id":null
   394  }`, clusterUUID, nodeGroup1UUID)
   395  
   396  // nodeGroupGetNotFoundResponse is the returned error when there is a cluster with the requested ID but it does not have the requested node group.
   397  var nodeGroupGetNotFoundResponse = fmt.Sprintf(`
   398  {
   399    "errors":[
   400      {
   401        "status":404,
   402        "code":"client",
   403        "links":[
   404  
   405        ],
   406        "title":"Nodegroup %s could not be found",
   407        "request_id":""
   408      }
   409    ]
   410  }`, badNodeGroupUUID)
   411  
   412  // nodeGroupGetClusterNotFoundResponse is the returned error when there is no cluster with the requested ID.
   413  var nodeGroupGetClusterNotFoundResponse = fmt.Sprintf(`
   414  {
   415    "errors":[
   416      {
   417        "status":404,
   418        "code":"client",
   419        "links":[
   420  
   421        ],
   422        "title":"Cluster %s could not be found",
   423        "request_id":""
   424      }
   425    ]
   426  }`, badClusterUUID)
   427  
   428  var nodeGroupListResponse = fmt.Sprintf(`
   429  {
   430    "nodegroups":[
   431      {
   432        "status":"UPDATE_COMPLETE",
   433        "is_default":true,
   434        "uuid":"%s",
   435        "max_node_count":null,
   436        "stack_id":"3cd55bb0-1115-4838-8eca-cefc13f7a21b",
   437        "min_node_count":1,
   438        "image_id":"Fedora-AtomicHost-29-20190820.0.x86_64",
   439        "role":"master",
   440        "flavor_id":null,
   441        "node_count":1,
   442        "name":"default-master"
   443      },
   444      {
   445        "status":"UPDATE_COMPLETE",
   446        "is_default":true,
   447        "uuid":"%s",
   448        "max_node_count":null,
   449        "stack_id":"3cd55bb0-1115-4838-8eca-cefc13f7a21b",
   450        "min_node_count":1,
   451        "image_id":"Fedora-AtomicHost-29-20190820.0.x86_64",
   452        "role":"worker",
   453        "flavor_id":"m1.small",
   454        "node_count":1,
   455        "name":"default-worker"
   456      }
   457    ]
   458  }`, nodeGroup1UUID, nodeGroup2UUID)
   459  
   460  // nodeGroupListLimitResponse1 is the first response when requesting the list of node groups with a limit of 1.
   461  // It returns the URL for the next page with the marker of the first node group.
   462  var nodeGroupListLimitResponse1 = fmt.Sprintf(`
   463  {
   464    "nodegroups":[
   465      {
   466        "status":"UPDATE_COMPLETE",
   467        "is_default":true,
   468        "name":"default-master",
   469        "max_node_count":null,
   470        "stack_id":"3cd55bb0-1115-4838-8eca-cefc13f7a21b",
   471        "min_node_count":1,
   472        "image_id":"Fedora-AtomicHost-29-20190820.0.x86_64",
   473        "cluster_id":"bda75056-3a57-4ada-b943-658ac27beea0",
   474        "flavor_id":null,
   475        "role":"master",
   476        "node_count":1,
   477        "uuid":"%s"
   478      }
   479    ],
   480    "next":"%%s/v1/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups?sort_key=id&sort_dir=asc&limit=1&marker=%s"
   481  }`, nodeGroup1UUID, nodeGroup1UUID)
   482  
   483  // nodeGroupListLimitResponse2 is returned when making a request to the URL given by "next" in the first response.
   484  var nodeGroupListLimitResponse2 = fmt.Sprintf(`
   485  {
   486    "nodegroups":[
   487      {
   488        "status":"UPDATE_COMPLETE",
   489        "is_default":true,
   490        "name":"default-worker",
   491        "max_node_count":null,
   492        "stack_id":"3cd55bb0-1115-4838-8eca-cefc13f7a21b",
   493        "min_node_count":1,
   494        "image_id":"Fedora-AtomicHost-29-20190820.0.x86_64",
   495        "cluster_id":"bda75056-3a57-4ada-b943-658ac27beea0",
   496        "flavor_id":"m1.small",
   497        "role":"worker",
   498        "node_count":1,
   499        "uuid":"%s"
   500      }
   501    ],
   502    "next":"%%s/v1/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups?sort_key=id&sort_dir=asc&limit=1&marker=%s"
   503  }`, nodeGroup2UUID, nodeGroup2UUID)
   504  
   505  // nodeGroupListLimitResponse3 is the response when listing node groups using a marker and all node groups have already been returned.
   506  var nodeGroupListLimitResponse3 = `{"nodegroups": []}`
   507  
   508  // nodeGroupListClusterNotFoundResponse is the error returned when the list operation fails because there is no cluster with the requested ID.
   509  var nodeGroupListClusterNotFoundResponse = fmt.Sprintf(`
   510  {
   511    "errors":[
   512      {
   513        "status":404,
   514        "code":"client",
   515        "links":[
   516  
   517        ],
   518        "title":"Cluster %s could not be found",
   519        "request_id":""
   520      }
   521    ]
   522  }`, badClusterUUID)
   523  
   524  var nodeGroupCreateResponse = fmt.Sprintf(`
   525  {
   526    "uuid":"12542dd8-9588-42a7-a2ff-06f49049920c",
   527    "links":[
   528      {
   529        "href":"http://123.456.789.0:9511/v1/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups/12542dd8-9588-42a7-a2ff-06f49049920c",
   530        "rel":"self"
   531      },
   532      {
   533        "href":"http://123.456.789.0:9511/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups/12542dd8-9588-42a7-a2ff-06f49049920c",
   534        "rel":"bookmark"
   535      }
   536    ],
   537    "max_node_count":null,
   538    "labels":{
   539      "kube_tag":"v1.14.7"
   540    },
   541    "min_node_count":1,
   542    "image_id":"Fedora-AtomicHost-29-20190820.0.x86_64",
   543    "cluster_id":"%s",
   544    "flavor_id":"m1.small",
   545    "role":"worker",
   546    "node_count":1,
   547    "project_id":"e91d02d561374de6b49960a27b3f08d0",
   548    "name":"test-ng"
   549  }`, clusterUUID)
   550  
   551  var nodeGroupCreateDuplicateResponse = `
   552  {
   553    "errors":[
   554      {
   555        "status":409,
   556        "code":"client",
   557        "links":[
   558  
   559        ],
   560        "title":"A node group with name default-worker already exists in the cluster kube",
   561        "detail":"A node group with name default-worker already exists in the cluster kube.",
   562        "request_id":""
   563      }
   564    ]
   565  }`
   566  
   567  var nodeGroupCreateMasterResponse = `
   568  {
   569    "errors":[
   570      {
   571        "status":400,
   572        "code":"client",
   573        "links":[
   574  
   575        ],
   576        "title":"Creating master nodegroups is currently not supported",
   577        "detail":"Creating master nodegroups is currently not supported.",
   578        "request_id":""
   579      }
   580    ]
   581  }`
   582  
   583  var nodeGroupCreateBadSizesResponse = `
   584  {
   585    "errors":[
   586      {
   587        "status":409,
   588        "code":"client",
   589        "links":[
   590  
   591        ],
   592        "title":"max_node_count for new-ng is invalid (min_node_count (5) should be less or equal to max_node_count (3))",
   593        "detail":"max_node_count for new-ng is invalid (min_node_count (5) should be less or equal to max_node_count (3)).",
   594        "request_id":""
   595      }
   596    ]
   597  }`
   598  
   599  var nodeGroupUpdateResponse = fmt.Sprintf(`
   600  {
   601    "links":[
   602      {
   603        "href":"http://123.456.789.0:9511/v1/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups/2457febf-520f-4be3-abb9-96b892d7b5a0",
   604        "rel":"self"
   605      },
   606      {
   607        "href":"http://123.456.789.0:9511/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups/2457febf-520f-4be3-abb9-96b892d7b5a0",
   608        "rel":"bookmark"
   609      }
   610    ],
   611    "labels":{
   612      "kube_tag":"v1.14.7"
   613    },
   614    "updated_at":"2019-10-18T14:18:36+00:00",
   615    "cluster_id":"%s",
   616    "min_node_count":1,
   617    "id":10,
   618    "uuid":"%s",
   619    "version":null,
   620    "role":"worker",
   621    "node_count":1,
   622    "project_id":"e91d02d561374de6b49960a27b3f08d0",
   623    "status":"UPDATE_COMPLETE",
   624    "docker_volume_size":null,
   625    "max_node_count":3,
   626    "is_default":true,
   627    "image_id":"Fedora-AtomicHost-29-20190820.0.x86_64",
   628    "node_addresses":[
   629      "172.24.4.17"
   630    ],
   631    "status_reason":"Stack UPDATE completed successfully",
   632    "name":"default-worker",
   633    "stack_id":"3cd55bb0-1115-4838-8eca-cefc13f7a21b",
   634    "created_at":"2019-10-18T14:03:37+00:00",
   635    "flavor_id":"m1.small"
   636  }`, clusterUUID, nodeGroup2UUID)
   637  
   638  var nodeGroupUpdateInternalResponse = `
   639  {
   640    "errors":[
   641      {
   642        "status":400,
   643        "code":"client",
   644        "links":[
   645  
   646        ],
   647        "title":"'/name' is an internal attribute and can not be updated",
   648        "detail":"'/name' is an internal attribute and can not be updated",
   649        "request_id":""
   650      }
   651    ]
   652  }`
   653  
   654  var nodeGroupUpdateBadFieldResponse = `
   655  {
   656    "errors":[
   657      {
   658        "status":400,
   659        "code":"client",
   660        "links":[
   661  
   662        ],
   663        "title":"Couldn't apply patch '[{'path': '/bad_field', 'value': u'abc123', 'op': u'replace'}]'",
   664        "detail":"Couldn't apply patch '[{'path': '/bad_field', 'value': u'abc123', 'op': u'replace'}]'. Reason: can't replace non-existent object 'bad_field'",
   665        "request_id":""
   666      }
   667    ]
   668  }`
   669  
   670  var nodeGroupUpdateBadMinResponse = `
   671  {
   672    "errors":[
   673      {
   674        "status":409,
   675        "code":"client",
   676        "links":[
   677  
   678        ],
   679        "title":"max_node_count for test-ng is invalid (min_node_count (5) should be less or equal to max_node_count (3))",
   680        "detail":"max_node_count for test-ng is invalid (min_node_count (5) should be less or equal to max_node_count (3)).",
   681        "request_id":""
   682      }
   683    ]
   684  }`
   685  
   686  var nodeGroupDeleteNotFoundResponse = fmt.Sprintf(`
   687  {
   688    "errors":[
   689      {
   690        "status":404,
   691        "code":"client",
   692        "links":[
   693  
   694        ],
   695        "title":"Nodegroup %s could not be found",
   696        "detail":"Nodegroup %s could not be found.\nTraceback (most recent call last):\n\n  File \"/opt/stack/magnum/magnum/conductor/handlers/indirection_api.py\", line 33, in _object_dispatch\n    return getattr(target, method)(context, *args, **kwargs)\n\n  File \"/usr/local/lib/python2.7/dist-packages/oslo_versionedobjects/base.py\", line 184, in wrapper\n    result = fn(cls, context, *args, **kwargs)\n\n  File \"/opt/stack/magnum/magnum/objects/nodegroup.py\", line 83, in get\n    return cls.get_by_uuid(context, cluster_id, nodegroup_id)\n\n  File \"/usr/local/lib/python2.7/dist-packages/oslo_versionedobjects/base.py\", line 184, in wrapper\n    result = fn(cls, context, *args, **kwargs)\n\n  File \"/opt/stack/magnum/magnum/objects/nodegroup.py\", line 109, in get_by_uuid\n    db_nodegroup = cls.dbapi.get_nodegroup_by_uuid(context, cluster, uuid)\n\n  File \"/opt/stack/magnum/magnum/db/sqlalchemy/api.py\", line 866, in get_nodegroup_by_uuid\n    raise exception.NodeGroupNotFound(nodegroup=nodegroup_uuid)\n\nNodeGroupNotFound: Nodegroup %s could not be found.\n",
   697        "request_id":""
   698      }
   699    ]
   700  }`, badNodeGroupUUID, badNodeGroupUUID, badNodeGroupUUID)
   701  
   702  var nodeGroupDeleteClusterNotFoundResponse = fmt.Sprintf(`
   703  {
   704    "errors":[
   705      {
   706        "status":404,
   707        "code":"client",
   708        "links":[
   709  
   710        ],
   711        "title":"Cluster %s could not be found",
   712        "detail":"Cluster %s could not be found.\nTraceback (most recent call last):\n\n  File \"/opt/stack/magnum/magnum/conductor/handlers/indirection_api.py\", line 33, in _object_dispatch\n    return getattr(target, method)(context, *args, **kwargs)\n\n  File \"/usr/local/lib/python2.7/dist-packages/oslo_versionedobjects/base.py\", line 184, in wrapper\n    result = fn(cls, context, *args, **kwargs)\n\n  File \"/opt/stack/magnum/magnum/objects/cluster.py\", line 198, in get_by_uuid\n    db_cluster = cls.dbapi.get_cluster_by_uuid(context, uuid)\n\n  File \"/opt/stack/magnum/magnum/db/sqlalchemy/api.py\", line 238, in get_cluster_by_uuid\n    raise exception.ClusterNotFound(cluster=cluster_uuid)\n\nClusterNotFound: Cluster %s could not be found.\n",
   713        "request_id":""
   714      }
   715    ]
   716  }`, badClusterUUID, badClusterUUID, badClusterUUID)
   717  
   718  var nodeGroupDeleteDefaultResponse = `
   719  {
   720    "errors":[
   721      {
   722        "status":400,
   723        "code":"client",
   724        "links":[
   725  
   726        ],
   727        "title":"Deleting a default nodegroup is not supported",
   728        "detail":"Deleting a default nodegroup is not supported.",
   729        "request_id":""
   730      }
   731    ]
   732  }`