github.com/vnpaycloud-console/gophercloud/v2@v2.0.5/openstack/compute/v2/servers/testing/requests_test.go (about)

     1  package testing
     2  
     3  import (
     4  	"context"
     5  	"encoding/base64"
     6  	"encoding/json"
     7  	"net/http"
     8  	"testing"
     9  
    10  	"github.com/vnpaycloud-console/gophercloud/v2/openstack/compute/v2/servers"
    11  	"github.com/vnpaycloud-console/gophercloud/v2/pagination"
    12  	th "github.com/vnpaycloud-console/gophercloud/v2/testhelper"
    13  	"github.com/vnpaycloud-console/gophercloud/v2/testhelper/client"
    14  )
    15  
    16  func TestListServers(t *testing.T) {
    17  	th.SetupHTTP()
    18  	defer th.TeardownHTTP()
    19  	HandleServerListSuccessfully(t)
    20  
    21  	pages := 0
    22  	err := servers.List(client.ServiceClient(), servers.ListOpts{}).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) {
    23  		pages++
    24  
    25  		actual, err := servers.ExtractServers(page)
    26  		if err != nil {
    27  			return false, err
    28  		}
    29  
    30  		if len(actual) != 3 {
    31  			t.Fatalf("Expected 3 servers, got %d", len(actual))
    32  		}
    33  		th.CheckDeepEquals(t, ServerHerp, actual[0])
    34  		th.CheckDeepEquals(t, ServerDerp, actual[1])
    35  		th.CheckDeepEquals(t, ServerMerp, actual[2])
    36  
    37  		return true, nil
    38  	})
    39  
    40  	th.AssertNoErr(t, err)
    41  
    42  	if pages != 1 {
    43  		t.Errorf("Expected 1 page, saw %d", pages)
    44  	}
    45  }
    46  
    47  func TestListAllServers(t *testing.T) {
    48  	th.SetupHTTP()
    49  	defer th.TeardownHTTP()
    50  	HandleServerListSimpleSuccessfully(t)
    51  
    52  	allPages, err := servers.ListSimple(client.ServiceClient(), servers.ListOpts{}).AllPages(context.TODO())
    53  	th.AssertNoErr(t, err)
    54  	actual, err := servers.ExtractServers(allPages)
    55  	th.AssertNoErr(t, err)
    56  	th.CheckDeepEquals(t, ServerHerp, actual[0])
    57  	th.CheckDeepEquals(t, ServerDerp, actual[1])
    58  }
    59  
    60  func TestListAllServersWithExtensions(t *testing.T) {
    61  	th.SetupHTTP()
    62  	defer th.TeardownHTTP()
    63  	HandleServerListSuccessfully(t)
    64  
    65  	allPages, err := servers.List(client.ServiceClient(), servers.ListOpts{}).AllPages(context.TODO())
    66  	th.AssertNoErr(t, err)
    67  
    68  	var actual []servers.Server
    69  	err = servers.ExtractServersInto(allPages, &actual)
    70  	th.AssertNoErr(t, err)
    71  	th.AssertEquals(t, 3, len(actual))
    72  	th.AssertEquals(t, "nova", actual[0].AvailabilityZone)
    73  	th.AssertEquals(t, "RUNNING", actual[0].PowerState.String())
    74  	th.AssertEquals(t, "", actual[0].TaskState)
    75  	th.AssertEquals(t, "active", actual[0].VmState)
    76  	th.AssertEquals(t, servers.Manual, actual[0].DiskConfig)
    77  }
    78  
    79  func TestCreateServer(t *testing.T) {
    80  	th.SetupHTTP()
    81  	defer th.TeardownHTTP()
    82  	HandleServerCreationSuccessfully(t, SingleServerBody)
    83  
    84  	actual, err := servers.Create(context.TODO(), client.ServiceClient(), servers.CreateOpts{
    85  		Name:      "derp",
    86  		ImageRef:  "f90f6034-2570-4974-8351-6b49732ef2eb",
    87  		FlavorRef: "1",
    88  	}, nil).Extract()
    89  	th.AssertNoErr(t, err)
    90  
    91  	th.CheckDeepEquals(t, ServerDerp, *actual)
    92  }
    93  
    94  func TestCreateServerNoNetwork(t *testing.T) {
    95  	th.SetupHTTP()
    96  	defer th.TeardownHTTP()
    97  	HandleServerNoNetworkCreationSuccessfully(t, SingleServerBody)
    98  
    99  	actual, err := servers.Create(context.TODO(), client.ServiceClient(), servers.CreateOpts{
   100  		Name:      "derp",
   101  		ImageRef:  "f90f6034-2570-4974-8351-6b49732ef2eb",
   102  		FlavorRef: "1",
   103  		Networks:  "none",
   104  	}, nil).Extract()
   105  	th.AssertNoErr(t, err)
   106  
   107  	th.CheckDeepEquals(t, ServerDerp, *actual)
   108  }
   109  
   110  func TestCreateServers(t *testing.T) {
   111  	th.SetupHTTP()
   112  	defer th.TeardownHTTP()
   113  	HandleServersCreationSuccessfully(t, SingleServerBody)
   114  
   115  	actual, err := servers.Create(context.TODO(), client.ServiceClient(), servers.CreateOpts{
   116  		Name:      "derp",
   117  		ImageRef:  "f90f6034-2570-4974-8351-6b49732ef2eb",
   118  		FlavorRef: "1",
   119  		Min:       3,
   120  		Max:       3,
   121  	}, nil).Extract()
   122  	th.AssertNoErr(t, err)
   123  
   124  	th.CheckDeepEquals(t, ServerDerp, *actual)
   125  }
   126  
   127  func TestCreateServerWithCustomField(t *testing.T) {
   128  	th.SetupHTTP()
   129  	defer th.TeardownHTTP()
   130  	HandleServerCreationWithCustomFieldSuccessfully(t, SingleServerBody)
   131  
   132  	actual, err := servers.Create(context.TODO(), client.ServiceClient(), CreateOptsWithCustomField{
   133  		CreateOpts: servers.CreateOpts{
   134  			Name:      "derp",
   135  			ImageRef:  "f90f6034-2570-4974-8351-6b49732ef2eb",
   136  			FlavorRef: "1",
   137  		},
   138  		Foo: "bar",
   139  	}, nil).Extract()
   140  	th.AssertNoErr(t, err)
   141  
   142  	th.CheckDeepEquals(t, ServerDerp, *actual)
   143  }
   144  
   145  func TestCreateServerWithMetadata(t *testing.T) {
   146  	th.SetupHTTP()
   147  	defer th.TeardownHTTP()
   148  	HandleServerCreationWithMetadata(t, SingleServerBody)
   149  
   150  	actual, err := servers.Create(context.TODO(), client.ServiceClient(), servers.CreateOpts{
   151  		Name:      "derp",
   152  		ImageRef:  "f90f6034-2570-4974-8351-6b49732ef2eb",
   153  		FlavorRef: "1",
   154  		Metadata: map[string]string{
   155  			"abc": "def",
   156  		},
   157  	}, nil).Extract()
   158  	th.AssertNoErr(t, err)
   159  
   160  	th.CheckDeepEquals(t, ServerDerp, *actual)
   161  }
   162  
   163  func TestCreateServerWithUserdataString(t *testing.T) {
   164  	th.SetupHTTP()
   165  	defer th.TeardownHTTP()
   166  	HandleServerCreationWithUserdata(t, SingleServerBody)
   167  
   168  	actual, err := servers.Create(context.TODO(), client.ServiceClient(), servers.CreateOpts{
   169  		Name:      "derp",
   170  		ImageRef:  "f90f6034-2570-4974-8351-6b49732ef2eb",
   171  		FlavorRef: "1",
   172  		UserData:  []byte("userdata string"),
   173  	}, nil).Extract()
   174  	th.AssertNoErr(t, err)
   175  
   176  	th.CheckDeepEquals(t, ServerDerp, *actual)
   177  }
   178  
   179  func TestCreateServerWithUserdataEncoded(t *testing.T) {
   180  	th.SetupHTTP()
   181  	defer th.TeardownHTTP()
   182  	HandleServerCreationWithUserdata(t, SingleServerBody)
   183  
   184  	encoded := base64.StdEncoding.EncodeToString([]byte("userdata string"))
   185  
   186  	actual, err := servers.Create(context.TODO(), client.ServiceClient(), servers.CreateOpts{
   187  		Name:      "derp",
   188  		ImageRef:  "f90f6034-2570-4974-8351-6b49732ef2eb",
   189  		FlavorRef: "1",
   190  		UserData:  []byte(encoded),
   191  	}, nil).Extract()
   192  	th.AssertNoErr(t, err)
   193  
   194  	th.CheckDeepEquals(t, ServerDerp, *actual)
   195  }
   196  
   197  func TestCreateServerWithHostname(t *testing.T) {
   198  	th.SetupHTTP()
   199  	defer th.TeardownHTTP()
   200  	HandleServerCreationWithHostname(t, SingleServerBody)
   201  
   202  	actual, err := servers.Create(context.TODO(), client.ServiceClient(), servers.CreateOpts{
   203  		Name:      "derp",
   204  		ImageRef:  "f90f6034-2570-4974-8351-6b49732ef2eb",
   205  		FlavorRef: "1",
   206  		Hostname:  "derp.local",
   207  	}, nil).Extract()
   208  	th.AssertNoErr(t, err)
   209  
   210  	th.CheckDeepEquals(t, ServerDerp, *actual)
   211  }
   212  
   213  func TestCreateServerWithDiskConfig(t *testing.T) {
   214  	opts := servers.CreateOpts{
   215  		Name:       "createdserver",
   216  		ImageRef:   "asdfasdfasdf",
   217  		FlavorRef:  "performance1-1",
   218  		DiskConfig: servers.Manual,
   219  	}
   220  	expected := `
   221  		{
   222  			"server": {
   223  				"name": "createdserver",
   224  				"imageRef": "asdfasdfasdf",
   225  				"flavorRef": "performance1-1",
   226  				"OS-DCF:diskConfig": "MANUAL"
   227  			}
   228  		}
   229  	`
   230  
   231  	actual, err := opts.ToServerCreateMap()
   232  	th.AssertNoErr(t, err)
   233  	th.CheckJSONEquals(t, expected, actual)
   234  }
   235  
   236  func TestCreateServerWithBFVBootFromNewVolume(t *testing.T) {
   237  	opts := servers.CreateOpts{
   238  		Name:      "createdserver",
   239  		FlavorRef: "performance1-1",
   240  		BlockDevice: []servers.BlockDevice{
   241  			{
   242  				UUID:                "123456",
   243  				SourceType:          servers.SourceImage,
   244  				DestinationType:     servers.DestinationVolume,
   245  				VolumeSize:          10,
   246  				DeleteOnTermination: true,
   247  			},
   248  		},
   249  	}
   250  	expected := `
   251  	{
   252  		"server": {
   253  			"name":"createdserver",
   254  			"flavorRef":"performance1-1",
   255  			"imageRef":"",
   256  			"block_device_mapping_v2":[
   257  				{
   258  					"uuid":"123456",
   259  					"source_type":"image",
   260  					"destination_type":"volume",
   261  					"boot_index": 0,
   262  					"delete_on_termination": true,
   263  					"volume_size": 10
   264  				}
   265  			]
   266  		}
   267  	}
   268  	`
   269  
   270  	actual, err := opts.ToServerCreateMap()
   271  	th.AssertNoErr(t, err)
   272  	th.CheckJSONEquals(t, expected, actual)
   273  }
   274  
   275  func TestCreateServerWithBFVBootFromExistingVolume(t *testing.T) {
   276  	opts := servers.CreateOpts{
   277  		Name:      "createdserver",
   278  		FlavorRef: "performance1-1",
   279  		BlockDevice: []servers.BlockDevice{
   280  			{
   281  				UUID:                "123456",
   282  				SourceType:          servers.SourceVolume,
   283  				DestinationType:     servers.DestinationVolume,
   284  				DeleteOnTermination: true,
   285  			},
   286  		},
   287  	}
   288  	expected := `
   289  	{
   290  		"server": {
   291  			"name":"createdserver",
   292  			"flavorRef":"performance1-1",
   293  			"imageRef":"",
   294  			"block_device_mapping_v2":[
   295  				{
   296  					"uuid":"123456",
   297  					"source_type":"volume",
   298  					"destination_type":"volume",
   299  					"boot_index": 0,
   300  					"delete_on_termination": true
   301  				}
   302  			]
   303  		}
   304  	}
   305  	`
   306  
   307  	actual, err := opts.ToServerCreateMap()
   308  	th.AssertNoErr(t, err)
   309  	th.CheckJSONEquals(t, expected, actual)
   310  }
   311  
   312  func TestCreateServerWithBFVBootFromImage(t *testing.T) {
   313  	var ImageRequest = servers.CreateOpts{
   314  		Name:      "createdserver",
   315  		FlavorRef: "performance1-1",
   316  		ImageRef:  "asdfasdfasdf",
   317  		BlockDevice: []servers.BlockDevice{
   318  			{
   319  				BootIndex:           0,
   320  				DeleteOnTermination: true,
   321  				DestinationType:     servers.DestinationLocal,
   322  				SourceType:          servers.SourceImage,
   323  				UUID:                "asdfasdfasdf",
   324  			},
   325  		},
   326  	}
   327  	const ExpectedImageRequest = `
   328  	{
   329  		"server": {
   330  			"name": "createdserver",
   331  			"imageRef": "asdfasdfasdf",
   332  			"flavorRef": "performance1-1",
   333  			"block_device_mapping_v2":[
   334  				{
   335  					"boot_index": 0,
   336  					"delete_on_termination": true,
   337  					"destination_type":"local",
   338  					"source_type":"image",
   339  					"uuid":"asdfasdfasdf"
   340  				}
   341  			]
   342  		}
   343  	}
   344  	`
   345  
   346  	actual, err := ImageRequest.ToServerCreateMap()
   347  	th.AssertNoErr(t, err)
   348  	th.CheckJSONEquals(t, ExpectedImageRequest, actual)
   349  }
   350  
   351  func TestCreateServerWithBFVCreateMultiEphemeralOpts(t *testing.T) {
   352  	var MultiEphemeralRequest = servers.CreateOpts{
   353  		Name:      "createdserver",
   354  		FlavorRef: "performance1-1",
   355  		ImageRef:  "asdfasdfasdf",
   356  		BlockDevice: []servers.BlockDevice{
   357  			{
   358  				BootIndex:           0,
   359  				DeleteOnTermination: true,
   360  				DestinationType:     servers.DestinationLocal,
   361  				SourceType:          servers.SourceImage,
   362  				UUID:                "asdfasdfasdf",
   363  			},
   364  			{
   365  				BootIndex:           -1,
   366  				DeleteOnTermination: true,
   367  				DestinationType:     servers.DestinationLocal,
   368  				GuestFormat:         "ext4",
   369  				SourceType:          servers.SourceBlank,
   370  				VolumeSize:          1,
   371  			},
   372  			{
   373  				BootIndex:           -1,
   374  				DeleteOnTermination: true,
   375  				DestinationType:     servers.DestinationLocal,
   376  				GuestFormat:         "ext4",
   377  				SourceType:          servers.SourceBlank,
   378  				VolumeSize:          1,
   379  			},
   380  		},
   381  	}
   382  	const ExpectedMultiEphemeralRequest = `
   383  	{
   384  		"server": {
   385  			"name": "createdserver",
   386  			"imageRef": "asdfasdfasdf",
   387  			"flavorRef": "performance1-1",
   388  			"block_device_mapping_v2":[
   389  				{
   390  					"boot_index": 0,
   391  					"delete_on_termination": true,
   392  					"destination_type":"local",
   393  					"source_type":"image",
   394  					"uuid":"asdfasdfasdf"
   395  				},
   396  				{
   397  					"boot_index": -1,
   398  					"delete_on_termination": true,
   399  					"destination_type":"local",
   400  					"guest_format":"ext4",
   401  					"source_type":"blank",
   402  					"volume_size": 1
   403  				},
   404  				{
   405  					"boot_index": -1,
   406  					"delete_on_termination": true,
   407  					"destination_type":"local",
   408  					"guest_format":"ext4",
   409  					"source_type":"blank",
   410  					"volume_size": 1
   411  				}
   412  			]
   413  		}
   414  	}
   415  	`
   416  
   417  	actual, err := MultiEphemeralRequest.ToServerCreateMap()
   418  	th.AssertNoErr(t, err)
   419  	th.CheckJSONEquals(t, ExpectedMultiEphemeralRequest, actual)
   420  }
   421  
   422  func TestCreateServerWithBFVAttachNewVolume(t *testing.T) {
   423  	opts := servers.CreateOpts{
   424  		Name:      "createdserver",
   425  		FlavorRef: "performance1-1",
   426  		ImageRef:  "asdfasdfasdf",
   427  		BlockDevice: []servers.BlockDevice{
   428  			{
   429  				BootIndex:           0,
   430  				DeleteOnTermination: true,
   431  				DestinationType:     servers.DestinationLocal,
   432  				SourceType:          servers.SourceImage,
   433  				UUID:                "asdfasdfasdf",
   434  			},
   435  			{
   436  				BootIndex:           1,
   437  				DeleteOnTermination: true,
   438  				DestinationType:     servers.DestinationVolume,
   439  				SourceType:          servers.SourceBlank,
   440  				VolumeSize:          1,
   441  				DeviceType:          "disk",
   442  				DiskBus:             "scsi",
   443  			},
   444  		},
   445  	}
   446  	expected := `
   447  	{
   448  		"server": {
   449  			"name": "createdserver",
   450  			"imageRef": "asdfasdfasdf",
   451  			"flavorRef": "performance1-1",
   452  			"block_device_mapping_v2":[
   453  				{
   454  					"boot_index": 0,
   455  					"delete_on_termination": true,
   456  					"destination_type":"local",
   457  					"source_type":"image",
   458  					"uuid":"asdfasdfasdf"
   459  				},
   460  				{
   461  					"boot_index": 1,
   462  					"delete_on_termination": true,
   463  					"destination_type":"volume",
   464  					"source_type":"blank",
   465  					"volume_size": 1,
   466  					"device_type": "disk",
   467  					"disk_bus": "scsi"
   468  				}
   469  			]
   470  		}
   471  	}
   472  	`
   473  
   474  	actual, err := opts.ToServerCreateMap()
   475  	th.AssertNoErr(t, err)
   476  	th.CheckJSONEquals(t, expected, actual)
   477  }
   478  
   479  func TestCreateServerWithBFVAttachExistingVolume(t *testing.T) {
   480  	opts := servers.CreateOpts{
   481  		Name:      "createdserver",
   482  		FlavorRef: "performance1-1",
   483  		ImageRef:  "asdfasdfasdf",
   484  		BlockDevice: []servers.BlockDevice{
   485  			{
   486  				BootIndex:           0,
   487  				DeleteOnTermination: true,
   488  				DestinationType:     servers.DestinationLocal,
   489  				SourceType:          servers.SourceImage,
   490  				UUID:                "asdfasdfasdf",
   491  			},
   492  			{
   493  				BootIndex:           1,
   494  				DeleteOnTermination: true,
   495  				DestinationType:     servers.DestinationVolume,
   496  				SourceType:          servers.SourceVolume,
   497  				UUID:                "123456",
   498  				VolumeSize:          1,
   499  			},
   500  		},
   501  	}
   502  	expected := `
   503  	{
   504  		"server": {
   505  			"name": "createdserver",
   506  			"imageRef": "asdfasdfasdf",
   507  			"flavorRef": "performance1-1",
   508  			"block_device_mapping_v2":[
   509  				{
   510  					"boot_index": 0,
   511  					"delete_on_termination": true,
   512  					"destination_type":"local",
   513  					"source_type":"image",
   514  					"uuid":"asdfasdfasdf"
   515  				},
   516  				{
   517  					"boot_index": 1,
   518  					"delete_on_termination": true,
   519  					"destination_type":"volume",
   520  					"source_type":"volume",
   521  					"uuid":"123456",
   522  					"volume_size": 1
   523  				}
   524  			]
   525  		}
   526  	}
   527  	`
   528  
   529  	actual, err := opts.ToServerCreateMap()
   530  	th.AssertNoErr(t, err)
   531  	th.CheckJSONEquals(t, expected, actual)
   532  }
   533  
   534  func TestCreateServerWithBFVBootFromNewVolumeType(t *testing.T) {
   535  	var NewVolumeTypeRequest = servers.CreateOpts{
   536  		Name:      "createdserver",
   537  		FlavorRef: "performance1-1",
   538  		BlockDevice: []servers.BlockDevice{
   539  			{
   540  				UUID:                "123456",
   541  				SourceType:          servers.SourceImage,
   542  				DestinationType:     servers.DestinationVolume,
   543  				VolumeSize:          10,
   544  				DeleteOnTermination: true,
   545  				VolumeType:          "ssd",
   546  			},
   547  		},
   548  	}
   549  	const ExpectedNewVolumeTypeRequest = `
   550  	{
   551  		"server": {
   552  			"name":"createdserver",
   553  			"flavorRef":"performance1-1",
   554  			"imageRef":"",
   555  			"block_device_mapping_v2":[
   556  				{
   557  					"uuid":"123456",
   558  					"source_type":"image",
   559  					"destination_type":"volume",
   560  					"boot_index": 0,
   561  					"delete_on_termination": true,
   562  					"volume_size": 10,
   563  					"volume_type": "ssd"
   564  				}
   565  			]
   566  		}
   567  	}
   568  	`
   569  
   570  	actual, err := NewVolumeTypeRequest.ToServerCreateMap()
   571  	th.AssertNoErr(t, err)
   572  	th.CheckJSONEquals(t, ExpectedNewVolumeTypeRequest, actual)
   573  }
   574  
   575  func TestCreateServerWithBFVAttachExistingVolumeWithTag(t *testing.T) {
   576  	var ImageAndExistingVolumeWithTagRequest = servers.CreateOpts{
   577  		Name:      "createdserver",
   578  		FlavorRef: "performance1-1",
   579  		ImageRef:  "asdfasdfasdf",
   580  		BlockDevice: []servers.BlockDevice{
   581  			{
   582  				BootIndex:           0,
   583  				DeleteOnTermination: true,
   584  				DestinationType:     servers.DestinationLocal,
   585  				SourceType:          servers.SourceImage,
   586  				UUID:                "asdfasdfasdf",
   587  			},
   588  			{
   589  				BootIndex:           -1,
   590  				DeleteOnTermination: true,
   591  				DestinationType:     servers.DestinationVolume,
   592  				SourceType:          servers.SourceVolume,
   593  				Tag:                 "volume-tag",
   594  				UUID:                "123456",
   595  				VolumeSize:          1,
   596  			},
   597  		},
   598  	}
   599  	const ExpectedImageAndExistingVolumeWithTagRequest = `
   600  	{
   601  		"server": {
   602  			"name": "createdserver",
   603  			"imageRef": "asdfasdfasdf",
   604  			"flavorRef": "performance1-1",
   605  			"block_device_mapping_v2":[
   606  				{
   607  					"boot_index": 0,
   608  					"delete_on_termination": true,
   609  					"destination_type":"local",
   610  					"source_type":"image",
   611  					"uuid":"asdfasdfasdf"
   612  				},
   613  				{
   614  					"boot_index": -1,
   615  					"delete_on_termination": true,
   616  					"destination_type":"volume",
   617  					"source_type":"volume",
   618  					"tag": "volume-tag",
   619  					"uuid":"123456",
   620  					"volume_size": 1
   621  				}
   622  			]
   623  		}
   624  	}
   625  	`
   626  
   627  	actual, err := ImageAndExistingVolumeWithTagRequest.ToServerCreateMap()
   628  	th.AssertNoErr(t, err)
   629  	th.CheckJSONEquals(t, ExpectedImageAndExistingVolumeWithTagRequest, actual)
   630  }
   631  
   632  func TestCreateSchedulerHints(t *testing.T) {
   633  	opts := servers.SchedulerHintOpts{
   634  		Group: "101aed42-22d9-4a3e-9ba1-21103b0d1aba",
   635  		DifferentHost: []string{
   636  			"a0cf03a5-d921-4877-bb5c-86d26cf818e1",
   637  			"8c19174f-4220-44f0-824a-cd1eeef10287",
   638  		},
   639  		SameHost: []string{
   640  			"a0cf03a5-d921-4877-bb5c-86d26cf818e1",
   641  			"8c19174f-4220-44f0-824a-cd1eeef10287",
   642  		},
   643  		Query:      []any{"=", "$free_ram_mb", "1024"},
   644  		TargetCell: "foobar",
   645  		DifferentCell: []string{
   646  			"bazbar",
   647  			"barbaz",
   648  		},
   649  		BuildNearHostIP:      "192.168.1.1/24",
   650  		AdditionalProperties: map[string]any{"reservation": "a0cf03a5-d921-4877-bb5c-86d26cf818e1"},
   651  	}
   652  
   653  	expected := `
   654  		{
   655  			"os:scheduler_hints": {
   656  				"group": "101aed42-22d9-4a3e-9ba1-21103b0d1aba",
   657  				"different_host": [
   658  					"a0cf03a5-d921-4877-bb5c-86d26cf818e1",
   659  					"8c19174f-4220-44f0-824a-cd1eeef10287"
   660  				],
   661  				"same_host": [
   662  					"a0cf03a5-d921-4877-bb5c-86d26cf818e1",
   663  					"8c19174f-4220-44f0-824a-cd1eeef10287"
   664  				],
   665  				"query": "[\"=\",\"$free_ram_mb\",\"1024\"]",
   666  				"target_cell": "foobar",
   667  				"different_cell": [
   668  					"bazbar",
   669  					"barbaz"
   670  				],
   671  				"build_near_host_ip": "192.168.1.1",
   672  				"cidr": "/24",
   673  				"reservation": "a0cf03a5-d921-4877-bb5c-86d26cf818e1"
   674  			}
   675  		}
   676  	`
   677  	actual, err := opts.ToSchedulerHintsMap()
   678  	th.AssertNoErr(t, err)
   679  	th.CheckJSONEquals(t, expected, actual)
   680  }
   681  
   682  func TestCreateComplexSchedulerHints(t *testing.T) {
   683  	opts := servers.SchedulerHintOpts{
   684  		Group: "101aed42-22d9-4a3e-9ba1-21103b0d1aba",
   685  		DifferentHost: []string{
   686  			"a0cf03a5-d921-4877-bb5c-86d26cf818e1",
   687  			"8c19174f-4220-44f0-824a-cd1eeef10287",
   688  		},
   689  		SameHost: []string{
   690  			"a0cf03a5-d921-4877-bb5c-86d26cf818e1",
   691  			"8c19174f-4220-44f0-824a-cd1eeef10287",
   692  		},
   693  		Query:      []any{"and", []string{"=", "$free_ram_mb", "1024"}, []string{"=", "$free_disk_mb", "204800"}},
   694  		TargetCell: "foobar",
   695  		DifferentCell: []string{
   696  			"bazbar",
   697  			"barbaz",
   698  		},
   699  		BuildNearHostIP:      "192.168.1.1/24",
   700  		AdditionalProperties: map[string]any{"reservation": "a0cf03a5-d921-4877-bb5c-86d26cf818e1"},
   701  	}
   702  
   703  	expected := `
   704  		{
   705  			"os:scheduler_hints": {
   706  				"group": "101aed42-22d9-4a3e-9ba1-21103b0d1aba",
   707  				"different_host": [
   708  					"a0cf03a5-d921-4877-bb5c-86d26cf818e1",
   709  					"8c19174f-4220-44f0-824a-cd1eeef10287"
   710  				],
   711  				"same_host": [
   712  					"a0cf03a5-d921-4877-bb5c-86d26cf818e1",
   713  					"8c19174f-4220-44f0-824a-cd1eeef10287"
   714  				],
   715  				"query": "[\"and\",[\"=\",\"$free_ram_mb\",\"1024\"],[\"=\",\"$free_disk_mb\",\"204800\"]]",
   716  				"target_cell": "foobar",
   717  				"different_cell": [
   718  					"bazbar",
   719  					"barbaz"
   720  				],
   721  				"build_near_host_ip": "192.168.1.1",
   722  				"cidr": "/24",
   723  				"reservation": "a0cf03a5-d921-4877-bb5c-86d26cf818e1"
   724  			}
   725  		}
   726  	`
   727  	actual, err := opts.ToSchedulerHintsMap()
   728  	th.AssertNoErr(t, err)
   729  	th.CheckJSONEquals(t, expected, actual)
   730  }
   731  
   732  func TestDeleteServer(t *testing.T) {
   733  	th.SetupHTTP()
   734  	defer th.TeardownHTTP()
   735  	HandleServerDeletionSuccessfully(t)
   736  
   737  	res := servers.Delete(context.TODO(), client.ServiceClient(), "asdfasdfasdf")
   738  	th.AssertNoErr(t, res.Err)
   739  }
   740  
   741  func TestForceDeleteServer(t *testing.T) {
   742  	th.SetupHTTP()
   743  	defer th.TeardownHTTP()
   744  	HandleServerForceDeletionSuccessfully(t)
   745  
   746  	res := servers.ForceDelete(context.TODO(), client.ServiceClient(), "asdfasdfasdf")
   747  	th.AssertNoErr(t, res.Err)
   748  }
   749  
   750  func TestGetServer(t *testing.T) {
   751  	th.SetupHTTP()
   752  	defer th.TeardownHTTP()
   753  	HandleServerGetSuccessfully(t)
   754  
   755  	client := client.ServiceClient()
   756  	actual, err := servers.Get(context.TODO(), client, "1234asdf").Extract()
   757  	if err != nil {
   758  		t.Fatalf("Unexpected Get error: %v", err)
   759  	}
   760  
   761  	th.CheckDeepEquals(t, ServerDerp, *actual)
   762  }
   763  
   764  func TestGetFaultyServer(t *testing.T) {
   765  	th.SetupHTTP()
   766  	defer th.TeardownHTTP()
   767  	HandleServerGetFaultSuccessfully(t)
   768  
   769  	client := client.ServiceClient()
   770  	actual, err := servers.Get(context.TODO(), client, "1234asdf").Extract()
   771  	if err != nil {
   772  		t.Fatalf("Unexpected Get error: %v", err)
   773  	}
   774  
   775  	FaultyServer := ServerDerp
   776  	FaultyServer.Fault = DerpFault
   777  	FaultyServer.Locked = nil
   778  	th.CheckDeepEquals(t, FaultyServer, *actual)
   779  }
   780  
   781  func TestGetServerWithExtensions(t *testing.T) {
   782  	th.SetupHTTP()
   783  	defer th.TeardownHTTP()
   784  	HandleServerGetSuccessfully(t)
   785  
   786  	var s struct {
   787  		servers.Server
   788  	}
   789  
   790  	client := client.ServiceClient()
   791  	err := servers.Get(context.TODO(), client, "1234asdf").ExtractInto(&s)
   792  	th.AssertNoErr(t, err)
   793  	th.AssertEquals(t, "nova", s.AvailabilityZone)
   794  	th.AssertEquals(t, "RUNNING", s.PowerState.String())
   795  	th.AssertEquals(t, "", s.TaskState)
   796  	th.AssertEquals(t, "active", s.VmState)
   797  	th.AssertEquals(t, servers.Manual, s.DiskConfig)
   798  
   799  	err = servers.Get(context.TODO(), client, "1234asdf").ExtractInto(s)
   800  	if err == nil {
   801  		t.Errorf("Expected error when providing non-pointer struct")
   802  	}
   803  }
   804  
   805  func TestUpdateServer(t *testing.T) {
   806  	th.SetupHTTP()
   807  	defer th.TeardownHTTP()
   808  	HandleServerUpdateSuccessfully(t)
   809  
   810  	client := client.ServiceClient()
   811  	actual, err := servers.Update(context.TODO(), client, "1234asdf", servers.UpdateOpts{Name: "new-name"}).Extract()
   812  	if err != nil {
   813  		t.Fatalf("Unexpected Update error: %v", err)
   814  	}
   815  
   816  	th.CheckDeepEquals(t, ServerDerp, *actual)
   817  }
   818  
   819  func TestChangeServerAdminPassword(t *testing.T) {
   820  	th.SetupHTTP()
   821  	defer th.TeardownHTTP()
   822  	HandleAdminPasswordChangeSuccessfully(t)
   823  
   824  	res := servers.ChangeAdminPassword(context.TODO(), client.ServiceClient(), "1234asdf", "new-password")
   825  	th.AssertNoErr(t, res.Err)
   826  }
   827  
   828  func TestShowConsoleOutput(t *testing.T) {
   829  	th.SetupHTTP()
   830  	defer th.TeardownHTTP()
   831  	HandleShowConsoleOutputSuccessfully(t, ConsoleOutputBody)
   832  
   833  	outputOpts := &servers.ShowConsoleOutputOpts{
   834  		Length: 50,
   835  	}
   836  	actual, err := servers.ShowConsoleOutput(context.TODO(), client.ServiceClient(), "1234asdf", outputOpts).Extract()
   837  
   838  	th.AssertNoErr(t, err)
   839  	th.AssertByteArrayEquals(t, []byte(ConsoleOutput), []byte(actual))
   840  }
   841  
   842  func TestGetPassword(t *testing.T) {
   843  	th.SetupHTTP()
   844  	defer th.TeardownHTTP()
   845  	HandlePasswordGetSuccessfully(t)
   846  
   847  	res := servers.GetPassword(context.TODO(), client.ServiceClient(), "1234asdf")
   848  	th.AssertNoErr(t, res.Err)
   849  }
   850  
   851  func TestRebootServer(t *testing.T) {
   852  	th.SetupHTTP()
   853  	defer th.TeardownHTTP()
   854  	HandleRebootSuccessfully(t)
   855  
   856  	res := servers.Reboot(context.TODO(), client.ServiceClient(), "1234asdf", servers.RebootOpts{
   857  		Type: servers.SoftReboot,
   858  	})
   859  	th.AssertNoErr(t, res.Err)
   860  }
   861  
   862  func TestRebuildServer(t *testing.T) {
   863  	th.SetupHTTP()
   864  	defer th.TeardownHTTP()
   865  	HandleRebuildSuccessfully(t, SingleServerBody)
   866  
   867  	opts := servers.RebuildOpts{
   868  		Name:       "new-name",
   869  		AdminPass:  "swordfish",
   870  		ImageRef:   "f90f6034-2570-4974-8351-6b49732ef2eb",
   871  		AccessIPv4: "1.2.3.4",
   872  	}
   873  
   874  	actual, err := servers.Rebuild(context.TODO(), client.ServiceClient(), "1234asdf", opts).Extract()
   875  	th.AssertNoErr(t, err)
   876  
   877  	th.CheckDeepEquals(t, ServerDerp, *actual)
   878  }
   879  
   880  func TestRebuildServerWithDiskConfig(t *testing.T) {
   881  	opts := servers.RebuildOpts{
   882  		Name:       "rebuiltserver",
   883  		AdminPass:  "swordfish",
   884  		ImageRef:   "asdfasdfasdf",
   885  		DiskConfig: servers.Auto,
   886  	}
   887  	expected := `
   888  		{
   889  			"rebuild": {
   890  				"name": "rebuiltserver",
   891  				"imageRef": "asdfasdfasdf",
   892  				"adminPass": "swordfish",
   893  				"OS-DCF:diskConfig": "AUTO"
   894  			}
   895  		}
   896  	`
   897  
   898  	actual, err := opts.ToServerRebuildMap()
   899  	th.AssertNoErr(t, err)
   900  	th.CheckJSONEquals(t, expected, actual)
   901  }
   902  
   903  func TestResizeServer(t *testing.T) {
   904  	th.SetupHTTP()
   905  	defer th.TeardownHTTP()
   906  
   907  	th.Mux.HandleFunc("/servers/1234asdf/action", func(w http.ResponseWriter, r *http.Request) {
   908  		th.TestMethod(t, r, "POST")
   909  		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
   910  		th.TestJSONRequest(t, r, `{ "resize": { "flavorRef": "2" } }`)
   911  
   912  		w.WriteHeader(http.StatusAccepted)
   913  	})
   914  
   915  	res := servers.Resize(context.TODO(), client.ServiceClient(), "1234asdf", servers.ResizeOpts{FlavorRef: "2"})
   916  	th.AssertNoErr(t, res.Err)
   917  }
   918  
   919  func TestResizeServerWithDiskConfig(t *testing.T) {
   920  	opts := servers.ResizeOpts{
   921  		FlavorRef:  "performance1-8",
   922  		DiskConfig: servers.Auto,
   923  	}
   924  	expected := `
   925  		{
   926  			"resize": {
   927  				"flavorRef": "performance1-8",
   928  				"OS-DCF:diskConfig": "AUTO"
   929  			}
   930  		}
   931  	`
   932  
   933  	actual, err := opts.ToServerResizeMap()
   934  	th.AssertNoErr(t, err)
   935  	th.CheckJSONEquals(t, expected, actual)
   936  }
   937  
   938  func TestConfirmResize(t *testing.T) {
   939  	th.SetupHTTP()
   940  	defer th.TeardownHTTP()
   941  
   942  	th.Mux.HandleFunc("/servers/1234asdf/action", func(w http.ResponseWriter, r *http.Request) {
   943  		th.TestMethod(t, r, "POST")
   944  		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
   945  		th.TestJSONRequest(t, r, `{ "confirmResize": null }`)
   946  
   947  		w.WriteHeader(http.StatusNoContent)
   948  	})
   949  
   950  	res := servers.ConfirmResize(context.TODO(), client.ServiceClient(), "1234asdf")
   951  	th.AssertNoErr(t, res.Err)
   952  }
   953  
   954  func TestRevertResize(t *testing.T) {
   955  	th.SetupHTTP()
   956  	defer th.TeardownHTTP()
   957  
   958  	th.Mux.HandleFunc("/servers/1234asdf/action", func(w http.ResponseWriter, r *http.Request) {
   959  		th.TestMethod(t, r, "POST")
   960  		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
   961  		th.TestJSONRequest(t, r, `{ "revertResize": null }`)
   962  
   963  		w.WriteHeader(http.StatusAccepted)
   964  	})
   965  
   966  	res := servers.RevertResize(context.TODO(), client.ServiceClient(), "1234asdf")
   967  	th.AssertNoErr(t, res.Err)
   968  }
   969  
   970  func TestGetMetadatum(t *testing.T) {
   971  	th.SetupHTTP()
   972  	defer th.TeardownHTTP()
   973  
   974  	HandleMetadatumGetSuccessfully(t)
   975  
   976  	expected := map[string]string{"foo": "bar"}
   977  	actual, err := servers.Metadatum(context.TODO(), client.ServiceClient(), "1234asdf", "foo").Extract()
   978  	th.AssertNoErr(t, err)
   979  	th.AssertDeepEquals(t, expected, actual)
   980  }
   981  
   982  func TestCreateMetadatum(t *testing.T) {
   983  	th.SetupHTTP()
   984  	defer th.TeardownHTTP()
   985  
   986  	HandleMetadatumCreateSuccessfully(t)
   987  
   988  	expected := map[string]string{"foo": "bar"}
   989  	actual, err := servers.CreateMetadatum(context.TODO(), client.ServiceClient(), "1234asdf", servers.MetadatumOpts{"foo": "bar"}).Extract()
   990  	th.AssertNoErr(t, err)
   991  	th.AssertDeepEquals(t, expected, actual)
   992  }
   993  
   994  func TestDeleteMetadatum(t *testing.T) {
   995  	th.SetupHTTP()
   996  	defer th.TeardownHTTP()
   997  
   998  	HandleMetadatumDeleteSuccessfully(t)
   999  
  1000  	err := servers.DeleteMetadatum(context.TODO(), client.ServiceClient(), "1234asdf", "foo").ExtractErr()
  1001  	th.AssertNoErr(t, err)
  1002  }
  1003  
  1004  func TestGetMetadata(t *testing.T) {
  1005  	th.SetupHTTP()
  1006  	defer th.TeardownHTTP()
  1007  
  1008  	HandleMetadataGetSuccessfully(t)
  1009  
  1010  	expected := map[string]string{"foo": "bar", "this": "that"}
  1011  	actual, err := servers.Metadata(context.TODO(), client.ServiceClient(), "1234asdf").Extract()
  1012  	th.AssertNoErr(t, err)
  1013  	th.AssertDeepEquals(t, expected, actual)
  1014  }
  1015  
  1016  func TestResetMetadata(t *testing.T) {
  1017  	th.SetupHTTP()
  1018  	defer th.TeardownHTTP()
  1019  
  1020  	HandleMetadataResetSuccessfully(t)
  1021  
  1022  	expected := map[string]string{"foo": "bar", "this": "that"}
  1023  	actual, err := servers.ResetMetadata(context.TODO(), client.ServiceClient(), "1234asdf", servers.MetadataOpts{
  1024  		"foo":  "bar",
  1025  		"this": "that",
  1026  	}).Extract()
  1027  	th.AssertNoErr(t, err)
  1028  	th.AssertDeepEquals(t, expected, actual)
  1029  }
  1030  
  1031  func TestUpdateMetadata(t *testing.T) {
  1032  	th.SetupHTTP()
  1033  	defer th.TeardownHTTP()
  1034  
  1035  	HandleMetadataUpdateSuccessfully(t)
  1036  
  1037  	expected := map[string]string{"foo": "baz", "this": "those"}
  1038  	actual, err := servers.UpdateMetadata(context.TODO(), client.ServiceClient(), "1234asdf", servers.MetadataOpts{
  1039  		"foo":  "baz",
  1040  		"this": "those",
  1041  	}).Extract()
  1042  	th.AssertNoErr(t, err)
  1043  	th.AssertDeepEquals(t, expected, actual)
  1044  }
  1045  
  1046  func TestListAddresses(t *testing.T) {
  1047  	th.SetupHTTP()
  1048  	defer th.TeardownHTTP()
  1049  	HandleAddressListSuccessfully(t)
  1050  
  1051  	expected := ListAddressesExpected
  1052  	pages := 0
  1053  	err := servers.ListAddresses(client.ServiceClient(), "asdfasdfasdf").EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) {
  1054  		pages++
  1055  
  1056  		actual, err := servers.ExtractAddresses(page)
  1057  		th.AssertNoErr(t, err)
  1058  
  1059  		if len(actual) != 2 {
  1060  			t.Fatalf("Expected 2 networks, got %d", len(actual))
  1061  		}
  1062  		th.CheckDeepEquals(t, expected, actual)
  1063  
  1064  		return true, nil
  1065  	})
  1066  	th.AssertNoErr(t, err)
  1067  	th.CheckEquals(t, 1, pages)
  1068  }
  1069  
  1070  func TestListAddressesByNetwork(t *testing.T) {
  1071  	th.SetupHTTP()
  1072  	defer th.TeardownHTTP()
  1073  	HandleNetworkAddressListSuccessfully(t)
  1074  
  1075  	expected := ListNetworkAddressesExpected
  1076  	pages := 0
  1077  	err := servers.ListAddressesByNetwork(client.ServiceClient(), "asdfasdfasdf", "public").EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) {
  1078  		pages++
  1079  
  1080  		actual, err := servers.ExtractNetworkAddresses(page)
  1081  		th.AssertNoErr(t, err)
  1082  
  1083  		if len(actual) != 2 {
  1084  			t.Fatalf("Expected 2 addresses, got %d", len(actual))
  1085  		}
  1086  		th.CheckDeepEquals(t, expected, actual)
  1087  
  1088  		return true, nil
  1089  	})
  1090  	th.AssertNoErr(t, err)
  1091  	th.CheckEquals(t, 1, pages)
  1092  }
  1093  
  1094  func TestCreateServerImage(t *testing.T) {
  1095  	th.SetupHTTP()
  1096  	defer th.TeardownHTTP()
  1097  	HandleCreateServerImageSuccessfully(t)
  1098  
  1099  	_, err := servers.CreateImage(context.TODO(), client.ServiceClient(), "serverimage", servers.CreateImageOpts{Name: "test"}).ExtractImageID()
  1100  	th.AssertNoErr(t, err)
  1101  }
  1102  
  1103  func TestMarshalPersonality(t *testing.T) {
  1104  	name := "/etc/test"
  1105  	contents := []byte("asdfasdf")
  1106  
  1107  	personality := servers.Personality{
  1108  		&servers.File{
  1109  			Path:     name,
  1110  			Contents: contents,
  1111  		},
  1112  	}
  1113  
  1114  	data, err := json.Marshal(personality)
  1115  	if err != nil {
  1116  		t.Fatal(err)
  1117  	}
  1118  
  1119  	var actual []map[string]string
  1120  	err = json.Unmarshal(data, &actual)
  1121  	if err != nil {
  1122  		t.Fatal(err)
  1123  	}
  1124  
  1125  	if len(actual) != 1 {
  1126  		t.Fatal("expected personality length 1")
  1127  	}
  1128  
  1129  	if actual[0]["path"] != name {
  1130  		t.Fatal("file path incorrect")
  1131  	}
  1132  
  1133  	if actual[0]["contents"] != base64.StdEncoding.EncodeToString(contents) {
  1134  		t.Fatal("file contents incorrect")
  1135  	}
  1136  }
  1137  
  1138  func TestCreateServerWithTags(t *testing.T) {
  1139  	th.SetupHTTP()
  1140  	defer th.TeardownHTTP()
  1141  	HandleServerWithTagsCreationSuccessfully(t)
  1142  
  1143  	c := client.ServiceClient()
  1144  	c.Microversion = "2.52"
  1145  
  1146  	tags := []string{"foo", "bar"}
  1147  	ServerDerpTags := ServerDerp
  1148  	ServerDerpTags.Tags = &tags
  1149  	ServerDerpTags.Locked = nil
  1150  
  1151  	createOpts := servers.CreateOpts{
  1152  		Name:      "derp",
  1153  		ImageRef:  "f90f6034-2570-4974-8351-6b49732ef2eb",
  1154  		FlavorRef: "1",
  1155  		Tags:      tags,
  1156  	}
  1157  	res := servers.Create(context.TODO(), c, createOpts, nil)
  1158  	th.AssertNoErr(t, res.Err)
  1159  	actualServer, err := res.Extract()
  1160  	th.AssertNoErr(t, err)
  1161  	th.CheckDeepEquals(t, ServerDerpTags, *actualServer)
  1162  }
  1163  
  1164  func TestCreateServerWithHypervisorHostname(t *testing.T) {
  1165  	opts := servers.CreateOpts{
  1166  		Name:               "createdserver",
  1167  		FlavorRef:          "performance1-1",
  1168  		ImageRef:           "asdfasdfasdf",
  1169  		HypervisorHostname: "test-hypervisor",
  1170  	}
  1171  	expected := `
  1172      {
  1173          "server": {
  1174              "name":"createdserver",
  1175              "flavorRef":"performance1-1",
  1176              "imageRef":"asdfasdfasdf",
  1177              "hypervisor_hostname":"test-hypervisor"
  1178          }
  1179      }
  1180      `
  1181  	actual, err := opts.ToServerCreateMap()
  1182  	th.AssertNoErr(t, err)
  1183  	th.CheckJSONEquals(t, expected, actual)
  1184  }