github.com/gophercloud/gophercloud@v1.11.0/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/gophercloud/gophercloud"
    10  	"github.com/gophercloud/gophercloud/openstack/containerinfra/v1/nodegroups"
    11  	th "github.com/gophercloud/gophercloud/testhelper"
    12  	fake "github.com/gophercloud/gophercloud/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  		r.ParseForm()
   185  		if marker, ok := r.Form["marker"]; !ok {
   186  			// No marker, this is the first request.
   187  			th.TestFormValues(t, r, map[string]string{"limit": "1"})
   188  			fmt.Fprintf(w, nodeGroupListLimitResponse1, th.Endpoint())
   189  		} else {
   190  			switch marker[0] {
   191  			case nodeGroup1UUID:
   192  				// Marker is the UUID of the first node group, return the second.
   193  				fmt.Fprintf(w, nodeGroupListLimitResponse2, th.Endpoint())
   194  			case nodeGroup2UUID:
   195  				// Marker is the UUID of the second node group, there are no more to return.
   196  				fmt.Fprint(w, nodeGroupListLimitResponse3)
   197  			}
   198  		}
   199  	})
   200  }
   201  
   202  func handleListNodeGroupsClusterNotFound(t *testing.T) {
   203  	th.Mux.HandleFunc("/v1/clusters/"+badClusterUUID+"/nodegroups", func(w http.ResponseWriter, r *http.Request) {
   204  		th.TestMethod(t, r, http.MethodGet)
   205  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   206  
   207  		w.Header().Add("Content-Type", "application/json")
   208  		w.WriteHeader(http.StatusNotFound)
   209  
   210  		fmt.Fprint(w, nodeGroupListClusterNotFoundResponse)
   211  	})
   212  }
   213  
   214  func handleCreateNodeGroupSuccess(t *testing.T) {
   215  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups", func(w http.ResponseWriter, r *http.Request) {
   216  		th.TestMethod(t, r, http.MethodPost)
   217  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   218  
   219  		w.Header().Add("Content-Type", "application/json")
   220  		w.WriteHeader(http.StatusAccepted)
   221  
   222  		fmt.Fprintf(w, nodeGroupCreateResponse)
   223  	})
   224  }
   225  
   226  func handleCreateNodeGroupDuplicate(t *testing.T) {
   227  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups", func(w http.ResponseWriter, r *http.Request) {
   228  		th.TestMethod(t, r, http.MethodPost)
   229  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   230  
   231  		w.Header().Add("Content-Type", "application/json")
   232  		w.WriteHeader(http.StatusConflict)
   233  
   234  		fmt.Fprintf(w, nodeGroupCreateDuplicateResponse)
   235  	})
   236  }
   237  
   238  func handleCreateNodeGroupMaster(t *testing.T) {
   239  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups", func(w http.ResponseWriter, r *http.Request) {
   240  		th.TestMethod(t, r, http.MethodPost)
   241  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   242  
   243  		w.Header().Add("Content-Type", "application/json")
   244  		w.WriteHeader(http.StatusBadRequest)
   245  
   246  		fmt.Fprintf(w, nodeGroupCreateMasterResponse)
   247  	})
   248  }
   249  
   250  func handleCreateNodeGroupBadSizes(t *testing.T) {
   251  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups", func(w http.ResponseWriter, r *http.Request) {
   252  		th.TestMethod(t, r, http.MethodPost)
   253  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   254  
   255  		w.Header().Add("Content-Type", "application/json")
   256  		w.WriteHeader(http.StatusConflict)
   257  
   258  		fmt.Fprintf(w, nodeGroupCreateBadSizesResponse)
   259  	})
   260  }
   261  
   262  func handleUpdateNodeGroupSuccess(t *testing.T) {
   263  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups/"+nodeGroup2UUID, func(w http.ResponseWriter, r *http.Request) {
   264  		th.TestMethod(t, r, http.MethodPatch)
   265  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   266  
   267  		w.Header().Add("Content-Type", "application/json")
   268  		w.WriteHeader(http.StatusAccepted)
   269  
   270  		fmt.Fprintf(w, nodeGroupUpdateResponse)
   271  	})
   272  }
   273  
   274  func handleUpdateNodeGroupInternal(t *testing.T) {
   275  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups/"+nodeGroup2UUID, func(w http.ResponseWriter, r *http.Request) {
   276  		th.TestMethod(t, r, http.MethodPatch)
   277  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   278  
   279  		w.Header().Add("Content-Type", "application/json")
   280  		w.WriteHeader(http.StatusBadRequest)
   281  
   282  		fmt.Fprintf(w, nodeGroupUpdateInternalResponse)
   283  	})
   284  }
   285  
   286  func handleUpdateNodeGroupBadField(t *testing.T) {
   287  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups/"+nodeGroup2UUID, func(w http.ResponseWriter, r *http.Request) {
   288  		th.TestMethod(t, r, http.MethodPatch)
   289  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   290  
   291  		w.Header().Add("Content-Type", "application/json")
   292  		w.WriteHeader(http.StatusBadRequest)
   293  
   294  		fmt.Fprintf(w, nodeGroupUpdateBadFieldResponse)
   295  	})
   296  }
   297  
   298  func handleUpdateNodeGroupBadMin(t *testing.T) {
   299  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups/"+nodeGroup2UUID, func(w http.ResponseWriter, r *http.Request) {
   300  		th.TestMethod(t, r, http.MethodPatch)
   301  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   302  
   303  		w.Header().Add("Content-Type", "application/json")
   304  		w.WriteHeader(http.StatusConflict)
   305  
   306  		fmt.Fprintf(w, nodeGroupUpdateBadMinResponse)
   307  	})
   308  }
   309  
   310  func handleDeleteNodeGroupSuccess(t *testing.T) {
   311  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups/"+nodeGroup2UUID, func(w http.ResponseWriter, r *http.Request) {
   312  		th.TestMethod(t, r, http.MethodDelete)
   313  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   314  
   315  		w.WriteHeader(http.StatusNoContent)
   316  	})
   317  }
   318  
   319  func handleDeleteNodeGroupNotFound(t *testing.T) {
   320  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups/"+badNodeGroupUUID, func(w http.ResponseWriter, r *http.Request) {
   321  		th.TestMethod(t, r, http.MethodDelete)
   322  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   323  
   324  		w.Header().Add("Content-Type", "application/json")
   325  		w.WriteHeader(http.StatusNotFound)
   326  
   327  		fmt.Fprintf(w, nodeGroupDeleteNotFoundResponse)
   328  	})
   329  }
   330  
   331  func handleDeleteNodeGroupClusterNotFound(t *testing.T) {
   332  	th.Mux.HandleFunc("/v1/clusters/"+badClusterUUID+"/nodegroups/"+badNodeGroupUUID, func(w http.ResponseWriter, r *http.Request) {
   333  		th.TestMethod(t, r, http.MethodDelete)
   334  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   335  
   336  		w.Header().Add("Content-Type", "application/json")
   337  		w.WriteHeader(http.StatusNotFound)
   338  
   339  		fmt.Fprintf(w, nodeGroupDeleteClusterNotFoundResponse)
   340  	})
   341  }
   342  
   343  func handleDeleteNodeGroupDefault(t *testing.T) {
   344  	th.Mux.HandleFunc("/v1/clusters/"+clusterUUID+"/nodegroups/"+nodeGroup2UUID, func(w http.ResponseWriter, r *http.Request) {
   345  		th.TestMethod(t, r, http.MethodDelete)
   346  		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
   347  
   348  		w.Header().Add("Content-Type", "application/json")
   349  		w.WriteHeader(http.StatusBadRequest)
   350  
   351  		fmt.Fprintf(w, nodeGroupDeleteDefaultResponse)
   352  	})
   353  }
   354  
   355  var nodeGroupGetResponse = fmt.Sprintf(`
   356  {
   357    "links":[
   358      {
   359        "href":"http://123.456.789.0:9511/v1/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups/b2e581be-2eec-45b8-921a-c85fbc23aaa3",
   360        "rel":"self"
   361      },
   362      {
   363        "href":"http://123.456.789.0:9511/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups/b2e581be-2eec-45b8-921a-c85fbc23aaa3",
   364        "rel":"bookmark"
   365      }
   366    ],
   367    "labels":{
   368      "kube_tag":"v1.14.7"
   369    },
   370    "updated_at":"2019-10-18T14:18:35+00:00",
   371    "cluster_id":"%s",
   372    "min_node_count":1,
   373    "id":9,
   374    "uuid":"%s",
   375    "version":null,
   376    "role":"master",
   377    "node_count":1,
   378    "project_id":"e91d02d561374de6b49960a27b3f08d0",
   379    "status":"UPDATE_COMPLETE",
   380    "docker_volume_size":null,
   381    "max_node_count":null,
   382    "is_default":true,
   383    "image_id":"Fedora-AtomicHost-29-20190820.0.x86_64",
   384    "node_addresses":[
   385      "172.24.4.19"
   386    ],
   387    "status_reason":"Stack UPDATE completed successfully",
   388    "name":"default-master",
   389    "stack_id":"3cd55bb0-1115-4838-8eca-cefc13f7a21b",
   390    "created_at":"2019-10-18T14:03:37+00:00",
   391    "flavor_id":null
   392  }`, clusterUUID, nodeGroup1UUID)
   393  
   394  // nodeGroupGetNotFoundResponse is the returned error when there is a cluster with the requested ID but it does not have the requested node group.
   395  var nodeGroupGetNotFoundResponse = fmt.Sprintf(`
   396  {
   397    "errors":[
   398      {
   399        "status":404,
   400        "code":"client",
   401        "links":[
   402  
   403        ],
   404        "title":"Nodegroup %s could not be found",
   405        "request_id":""
   406      }
   407    ]
   408  }`, badNodeGroupUUID)
   409  
   410  // nodeGroupGetClusterNotFoundResponse is the returned error when there is no cluster with the requested ID.
   411  var nodeGroupGetClusterNotFoundResponse = fmt.Sprintf(`
   412  {
   413    "errors":[
   414      {
   415        "status":404,
   416        "code":"client",
   417        "links":[
   418  
   419        ],
   420        "title":"Cluster %s could not be found",
   421        "request_id":""
   422      }
   423    ]
   424  }`, badClusterUUID)
   425  
   426  var nodeGroupListResponse = fmt.Sprintf(`
   427  {
   428    "nodegroups":[
   429      {
   430        "status":"UPDATE_COMPLETE",
   431        "is_default":true,
   432        "uuid":"%s",
   433        "max_node_count":null,
   434        "stack_id":"3cd55bb0-1115-4838-8eca-cefc13f7a21b",
   435        "min_node_count":1,
   436        "image_id":"Fedora-AtomicHost-29-20190820.0.x86_64",
   437        "role":"master",
   438        "flavor_id":null,
   439        "node_count":1,
   440        "name":"default-master"
   441      },
   442      {
   443        "status":"UPDATE_COMPLETE",
   444        "is_default":true,
   445        "uuid":"%s",
   446        "max_node_count":null,
   447        "stack_id":"3cd55bb0-1115-4838-8eca-cefc13f7a21b",
   448        "min_node_count":1,
   449        "image_id":"Fedora-AtomicHost-29-20190820.0.x86_64",
   450        "role":"worker",
   451        "flavor_id":"m1.small",
   452        "node_count":1,
   453        "name":"default-worker"
   454      }
   455    ]
   456  }`, nodeGroup1UUID, nodeGroup2UUID)
   457  
   458  // nodeGroupListLimitResponse1 is the first response when requesting the list of node groups with a limit of 1.
   459  // It returns the URL for the next page with the marker of the first node group.
   460  var nodeGroupListLimitResponse1 = fmt.Sprintf(`
   461  {
   462    "nodegroups":[
   463      {
   464        "status":"UPDATE_COMPLETE",
   465        "is_default":true,
   466        "name":"default-master",
   467        "max_node_count":null,
   468        "stack_id":"3cd55bb0-1115-4838-8eca-cefc13f7a21b",
   469        "min_node_count":1,
   470        "image_id":"Fedora-AtomicHost-29-20190820.0.x86_64",
   471        "cluster_id":"bda75056-3a57-4ada-b943-658ac27beea0",
   472        "flavor_id":null,
   473        "role":"master",
   474        "node_count":1,
   475        "uuid":"%s"
   476      }
   477    ],
   478    "next":"%%s/v1/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups?sort_key=id&sort_dir=asc&limit=1&marker=%s"
   479  }`, nodeGroup1UUID, nodeGroup1UUID)
   480  
   481  // nodeGroupListLimitResponse2 is returned when making a request to the URL given by "next" in the first response.
   482  var nodeGroupListLimitResponse2 = fmt.Sprintf(`
   483  {
   484    "nodegroups":[
   485      {
   486        "status":"UPDATE_COMPLETE",
   487        "is_default":true,
   488        "name":"default-worker",
   489        "max_node_count":null,
   490        "stack_id":"3cd55bb0-1115-4838-8eca-cefc13f7a21b",
   491        "min_node_count":1,
   492        "image_id":"Fedora-AtomicHost-29-20190820.0.x86_64",
   493        "cluster_id":"bda75056-3a57-4ada-b943-658ac27beea0",
   494        "flavor_id":"m1.small",
   495        "role":"worker",
   496        "node_count":1,
   497        "uuid":"%s"
   498      }
   499    ],
   500    "next":"%%s/v1/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups?sort_key=id&sort_dir=asc&limit=1&marker=%s"
   501  }`, nodeGroup2UUID, nodeGroup2UUID)
   502  
   503  // nodeGroupListLimitResponse3 is the response when listing node groups using a marker and all node groups have already been returned.
   504  var nodeGroupListLimitResponse3 = `{"nodegroups": []}`
   505  
   506  // nodeGroupListClusterNotFoundResponse is the error returned when the list operation fails because there is no cluster with the requested ID.
   507  var nodeGroupListClusterNotFoundResponse = fmt.Sprintf(`
   508  {
   509    "errors":[
   510      {
   511        "status":404,
   512        "code":"client",
   513        "links":[
   514  
   515        ],
   516        "title":"Cluster %s could not be found",
   517        "request_id":""
   518      }
   519    ]
   520  }`, badClusterUUID)
   521  
   522  var nodeGroupCreateResponse = fmt.Sprintf(`
   523  {
   524    "uuid":"12542dd8-9588-42a7-a2ff-06f49049920c",
   525    "links":[
   526      {
   527        "href":"http://123.456.789.0:9511/v1/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups/12542dd8-9588-42a7-a2ff-06f49049920c",
   528        "rel":"self"
   529      },
   530      {
   531        "href":"http://123.456.789.0:9511/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups/12542dd8-9588-42a7-a2ff-06f49049920c",
   532        "rel":"bookmark"
   533      }
   534    ],
   535    "max_node_count":null,
   536    "labels":{
   537      "kube_tag":"v1.14.7"
   538    },
   539    "min_node_count":1,
   540    "image_id":"Fedora-AtomicHost-29-20190820.0.x86_64",
   541    "cluster_id":"%s",
   542    "flavor_id":"m1.small",
   543    "role":"worker",
   544    "node_count":1,
   545    "project_id":"e91d02d561374de6b49960a27b3f08d0",
   546    "name":"test-ng"
   547  }`, clusterUUID)
   548  
   549  var nodeGroupCreateDuplicateResponse = `
   550  {
   551    "errors":[
   552      {
   553        "status":409,
   554        "code":"client",
   555        "links":[
   556  
   557        ],
   558        "title":"A node group with name default-worker already exists in the cluster kube",
   559        "detail":"A node group with name default-worker already exists in the cluster kube.",
   560        "request_id":""
   561      }
   562    ]
   563  }`
   564  
   565  var nodeGroupCreateMasterResponse = `
   566  {
   567    "errors":[
   568      {
   569        "status":400,
   570        "code":"client",
   571        "links":[
   572  
   573        ],
   574        "title":"Creating master nodegroups is currently not supported",
   575        "detail":"Creating master nodegroups is currently not supported.",
   576        "request_id":""
   577      }
   578    ]
   579  }`
   580  
   581  var nodeGroupCreateBadSizesResponse = `
   582  {
   583    "errors":[
   584      {
   585        "status":409,
   586        "code":"client",
   587        "links":[
   588  
   589        ],
   590        "title":"max_node_count for new-ng is invalid (min_node_count (5) should be less or equal to max_node_count (3))",
   591        "detail":"max_node_count for new-ng is invalid (min_node_count (5) should be less or equal to max_node_count (3)).",
   592        "request_id":""
   593      }
   594    ]
   595  }`
   596  
   597  var nodeGroupUpdateResponse = fmt.Sprintf(`
   598  {
   599    "links":[
   600      {
   601        "href":"http://123.456.789.0:9511/v1/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups/2457febf-520f-4be3-abb9-96b892d7b5a0",
   602        "rel":"self"
   603      },
   604      {
   605        "href":"http://123.456.789.0:9511/clusters/bda75056-3a57-4ada-b943-658ac27beea0/nodegroups/2457febf-520f-4be3-abb9-96b892d7b5a0",
   606        "rel":"bookmark"
   607      }
   608    ],
   609    "labels":{
   610      "kube_tag":"v1.14.7"
   611    },
   612    "updated_at":"2019-10-18T14:18:36+00:00",
   613    "cluster_id":"%s",
   614    "min_node_count":1,
   615    "id":10,
   616    "uuid":"%s",
   617    "version":null,
   618    "role":"worker",
   619    "node_count":1,
   620    "project_id":"e91d02d561374de6b49960a27b3f08d0",
   621    "status":"UPDATE_COMPLETE",
   622    "docker_volume_size":null,
   623    "max_node_count":3,
   624    "is_default":true,
   625    "image_id":"Fedora-AtomicHost-29-20190820.0.x86_64",
   626    "node_addresses":[
   627      "172.24.4.17"
   628    ],
   629    "status_reason":"Stack UPDATE completed successfully",
   630    "name":"default-worker",
   631    "stack_id":"3cd55bb0-1115-4838-8eca-cefc13f7a21b",
   632    "created_at":"2019-10-18T14:03:37+00:00",
   633    "flavor_id":"m1.small"
   634  }`, clusterUUID, nodeGroup2UUID)
   635  
   636  var nodeGroupUpdateInternalResponse = `
   637  {
   638    "errors":[
   639      {
   640        "status":400,
   641        "code":"client",
   642        "links":[
   643  
   644        ],
   645        "title":"'/name' is an internal attribute and can not be updated",
   646        "detail":"'/name' is an internal attribute and can not be updated",
   647        "request_id":""
   648      }
   649    ]
   650  }`
   651  
   652  var nodeGroupUpdateBadFieldResponse = `
   653  {
   654    "errors":[
   655      {
   656        "status":400,
   657        "code":"client",
   658        "links":[
   659  
   660        ],
   661        "title":"Couldn't apply patch '[{'path': '/bad_field', 'value': u'abc123', 'op': u'replace'}]'",
   662        "detail":"Couldn't apply patch '[{'path': '/bad_field', 'value': u'abc123', 'op': u'replace'}]'. Reason: can't replace non-existent object 'bad_field'",
   663        "request_id":""
   664      }
   665    ]
   666  }`
   667  
   668  var nodeGroupUpdateBadMinResponse = `
   669  {
   670    "errors":[
   671      {
   672        "status":409,
   673        "code":"client",
   674        "links":[
   675  
   676        ],
   677        "title":"max_node_count for test-ng is invalid (min_node_count (5) should be less or equal to max_node_count (3))",
   678        "detail":"max_node_count for test-ng is invalid (min_node_count (5) should be less or equal to max_node_count (3)).",
   679        "request_id":""
   680      }
   681    ]
   682  }`
   683  
   684  var nodeGroupDeleteNotFoundResponse = fmt.Sprintf(`
   685  {
   686    "errors":[
   687      {
   688        "status":404,
   689        "code":"client",
   690        "links":[
   691  
   692        ],
   693        "title":"Nodegroup %s could not be found",
   694        "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",
   695        "request_id":""
   696      }
   697    ]
   698  }`, badNodeGroupUUID, badNodeGroupUUID, badNodeGroupUUID)
   699  
   700  var nodeGroupDeleteClusterNotFoundResponse = fmt.Sprintf(`
   701  {
   702    "errors":[
   703      {
   704        "status":404,
   705        "code":"client",
   706        "links":[
   707  
   708        ],
   709        "title":"Cluster %s could not be found",
   710        "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",
   711        "request_id":""
   712      }
   713    ]
   714  }`, badClusterUUID, badClusterUUID, badClusterUUID)
   715  
   716  var nodeGroupDeleteDefaultResponse = `
   717  {
   718    "errors":[
   719      {
   720        "status":400,
   721        "code":"client",
   722        "links":[
   723  
   724        ],
   725        "title":"Deleting a default nodegroup is not supported",
   726        "detail":"Deleting a default nodegroup is not supported.",
   727        "request_id":""
   728      }
   729    ]
   730  }`