1package vps
2
3import (
4	"fmt"
5	"github.com/stretchr/testify/assert"
6	"github.com/stretchr/testify/require"
7	"github.com/transip/gotransip/v6"
8	"github.com/transip/gotransip/v6/ipaddress"
9	"github.com/transip/gotransip/v6/repository"
10	"io/ioutil"
11	"net"
12	"net/http"
13	"net/http/httptest"
14	"net/url"
15	"testing"
16	"time"
17)
18
19// mockServer struct is used to test the how the client sends a request
20// and responds to a servers response
21type mockServer struct {
22	t               *testing.T
23	expectedURL     string
24	expectedMethod  string
25	statusCode      int
26	expectedRequest string
27	response        string
28	skipRequestBody bool
29}
30
31func (m *mockServer) getHTTPServer() *httptest.Server {
32	return httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
33		assert.Equal(m.t, m.expectedURL, req.URL.String()) // check if right expectedURL is called
34
35		if m.skipRequestBody == false && req.ContentLength != 0 {
36			// get the request body
37			// and check if the body matches the expected request body
38			body, err := ioutil.ReadAll(req.Body)
39			require.NoError(m.t, err)
40			assert.Equal(m.t, m.expectedRequest, string(body))
41		}
42
43		assert.Equal(m.t, m.expectedMethod, req.Method) // check if the right expectedRequest expectedMethod is used
44		rw.WriteHeader(m.statusCode)                    // respond with given status code
45
46		if m.response != "" {
47			_, err := rw.Write([]byte(m.response))
48			require.NoError(m.t, err, "error when writing mock response")
49		}
50	}))
51}
52
53func (m *mockServer) getClient() (*repository.Client, func()) {
54	httpServer := m.getHTTPServer()
55	config := gotransip.DemoClientConfiguration
56	config.URL = httpServer.URL
57	client, err := gotransip.NewClient(config)
58	require.NoError(m.t, err)
59
60	// return tearDown method with which will close the test server after the test
61	tearDown := func() {
62		httpServer.Close()
63	}
64
65	return &client, tearDown
66}
67
68func TestRepository_GetAll(t *testing.T) {
69	const apiResponse = `{ "vpss": [ { "name": "example-vps", "description": "example VPS", "productName": "vps-bladevps-x1", "operatingSystem": "ubuntu-18.04", "diskSize": 157286400, "memorySize": 4194304, "cpus": 2, "status": "running", "ipAddress": "37.97.254.6", "macAddress": "52:54:00:3b:52:65", "currentSnapshots": 1, "maxSnapshots": 10, "isLocked": false, "isBlocked": false, "isCustomerLocked": false, "availabilityZone": "ams0", "tags": [ "customTag", "anotherTag" ] } ] }`
70
71	server := mockServer{t: t, expectedURL: "/vps", expectedMethod: "GET", statusCode: 200, response: apiResponse}
72	client, tearDown := server.getClient()
73	defer tearDown()
74	repo := Repository{Client: *client}
75
76	all, err := repo.GetAll()
77	require.NoError(t, err)
78	require.Equal(t, 1, len(all))
79
80	assert.Equal(t, "example-vps", all[0].Name)
81	assert.Equal(t, "example VPS", all[0].Description)
82	assert.Equal(t, "vps-bladevps-x1", all[0].ProductName)
83	assert.Equal(t, "ubuntu-18.04", all[0].OperatingSystem)
84	assert.EqualValues(t, 157286400, all[0].DiskSize)
85	assert.EqualValues(t, 4194304, all[0].MemorySize)
86	assert.EqualValues(t, 2, all[0].CPUs)
87	assert.EqualValues(t, "running", all[0].Status)
88	assert.Equal(t, "37.97.254.6", all[0].IPAddress)
89	assert.Equal(t, "52:54:00:3b:52:65", all[0].MacAddress)
90	assert.EqualValues(t, 1, all[0].CurrentSnapshots)
91	assert.EqualValues(t, 10, all[0].MaxSnapshots)
92	assert.Equal(t, false, all[0].IsLocked)
93	assert.Equal(t, false, all[0].IsBlocked)
94	assert.Equal(t, false, all[0].IsCustomerLocked)
95	assert.Equal(t, "ams0", all[0].AvailabilityZone)
96	assert.Equal(t, []string{"customTag", "anotherTag"}, all[0].Tags)
97}
98
99func TestRepository_GetAllByTags(t *testing.T) {
100	const apiResponse = `{ "vpss": [ { "name": "example-vps", "uuid": "bfa08ad9-6c12-4e03-95dd-a888b97ffe49", "description": "example VPS", "productName": "vps-bladevps-x1", "operatingSystem": "ubuntu-18.04", "diskSize": 157286400, "memorySize": 4194304, "cpus": 2, "status": "running", "ipAddress": "37.97.254.6", "macAddress": "52:54:00:3b:52:65", "currentSnapshots": 1, "maxSnapshots": 10, "isLocked": false, "isBlocked": false, "isCustomerLocked": false, "availabilityZone": "ams0", "tags": [ "customTag", "anotherTag" ] } ] }`
101
102	server := mockServer{t: t, expectedURL: "/vps?tags=customTag", expectedMethod: "GET", statusCode: 200, response: apiResponse}
103	client, tearDown := server.getClient()
104	defer tearDown()
105	repo := Repository{Client: *client}
106
107	all, err := repo.GetAllByTags([]string{"customTag"})
108	require.NoError(t, err)
109	require.Equal(t, 1, len(all))
110
111	assert.Equal(t, "example-vps", all[0].Name)
112	assert.Equal(t, "example VPS", all[0].Description)
113	assert.Equal(t, "bfa08ad9-6c12-4e03-95dd-a888b97ffe49", all[0].UUID)
114	assert.Equal(t, "vps-bladevps-x1", all[0].ProductName)
115	assert.Equal(t, "ubuntu-18.04", all[0].OperatingSystem)
116	assert.EqualValues(t, 157286400, all[0].DiskSize)
117	assert.EqualValues(t, 4194304, all[0].MemorySize)
118	assert.EqualValues(t, 2, all[0].CPUs)
119	assert.EqualValues(t, "running", all[0].Status)
120	assert.Equal(t, "37.97.254.6", all[0].IPAddress)
121	assert.Equal(t, "52:54:00:3b:52:65", all[0].MacAddress)
122	assert.EqualValues(t, 1, all[0].CurrentSnapshots)
123	assert.EqualValues(t, 10, all[0].MaxSnapshots)
124	assert.Equal(t, false, all[0].IsLocked)
125	assert.Equal(t, false, all[0].IsBlocked)
126	assert.Equal(t, false, all[0].IsCustomerLocked)
127	assert.Equal(t, "ams0", all[0].AvailabilityZone)
128	assert.Equal(t, []string{"customTag", "anotherTag"}, all[0].Tags)
129}
130
131func TestRepository_GetSelection(t *testing.T) {
132	const apiResponse = `{ "vpss": [ { "name": "example-vps", "uuid": "bfa08ad9-6c12-4e03-95dd-a888b97ffe49", "description": "example VPS", "productName": "vps-bladevps-x1", "operatingSystem": "ubuntu-18.04", "diskSize": 157286400, "memorySize": 4194304, "cpus": 2, "status": "running", "ipAddress": "37.97.254.6", "macAddress": "52:54:00:3b:52:65", "currentSnapshots": 1, "maxSnapshots": 10, "isLocked": false, "isBlocked": false, "isCustomerLocked": false, "availabilityZone": "ams0", "tags": [ "customTag", "anotherTag" ] } ] }`
133
134	server := mockServer{t: t, expectedURL: "/vps?page=1&pageSize=25", expectedMethod: "GET", statusCode: 200, response: apiResponse}
135	client, tearDown := server.getClient()
136	defer tearDown()
137	repo := Repository{Client: *client}
138
139	all, err := repo.GetSelection(1, 25)
140	require.NoError(t, err)
141	require.Equal(t, 1, len(all))
142
143	assert.Equal(t, "example-vps", all[0].Name)
144	assert.Equal(t, "bfa08ad9-6c12-4e03-95dd-a888b97ffe49", all[0].UUID)
145	assert.Equal(t, "example VPS", all[0].Description)
146	assert.Equal(t, "vps-bladevps-x1", all[0].ProductName)
147	assert.Equal(t, "ubuntu-18.04", all[0].OperatingSystem)
148	assert.EqualValues(t, 157286400, all[0].DiskSize)
149	assert.EqualValues(t, 4194304, all[0].MemorySize)
150	assert.EqualValues(t, 2, all[0].CPUs)
151	assert.EqualValues(t, "running", all[0].Status)
152	assert.Equal(t, "37.97.254.6", all[0].IPAddress)
153	assert.Equal(t, "52:54:00:3b:52:65", all[0].MacAddress)
154	assert.EqualValues(t, 1, all[0].CurrentSnapshots)
155	assert.EqualValues(t, 10, all[0].MaxSnapshots)
156	assert.Equal(t, false, all[0].IsLocked)
157	assert.Equal(t, false, all[0].IsBlocked)
158	assert.Equal(t, false, all[0].IsCustomerLocked)
159	assert.Equal(t, "ams0", all[0].AvailabilityZone)
160	assert.Equal(t, []string{"customTag", "anotherTag"}, all[0].Tags)
161}
162
163func TestRepository_GetByName(t *testing.T) {
164	const apiResponse = `{ "vps": { "name": "example-vps", "uuid": "bfa08ad9-6c12-4e03-95dd-a888b97ffe49", "description": "example VPS", "productName": "vps-bladevps-x1", "operatingSystem": "ubuntu-18.04", "diskSize": 157286400, "memorySize": 4194304, "cpus": 2, "status": "running", "ipAddress": "37.97.254.6", "macAddress": "52:54:00:3b:52:65", "currentSnapshots": 1, "maxSnapshots": 10, "isLocked": false, "isBlocked": false, "isCustomerLocked": false, "availabilityZone": "ams0", "tags": [ "customTag", "anotherTag" ] } }`
165	server := mockServer{t: t, expectedURL: "/vps/example-vps", expectedMethod: "GET", statusCode: 200, response: apiResponse}
166	client, tearDown := server.getClient()
167	defer tearDown()
168	repo := Repository{Client: *client}
169
170	vps, err := repo.GetByName("example-vps")
171	require.NoError(t, err)
172
173	assert.Equal(t, "example-vps", vps.Name)
174	assert.Equal(t, "bfa08ad9-6c12-4e03-95dd-a888b97ffe49", vps.UUID)
175	assert.Equal(t, "example VPS", vps.Description)
176	assert.Equal(t, "vps-bladevps-x1", vps.ProductName)
177	assert.Equal(t, "ubuntu-18.04", vps.OperatingSystem)
178	assert.EqualValues(t, 157286400, vps.DiskSize)
179	assert.EqualValues(t, 4194304, vps.MemorySize)
180	assert.EqualValues(t, 2, vps.CPUs)
181	assert.EqualValues(t, "running", vps.Status)
182	assert.Equal(t, "37.97.254.6", vps.IPAddress)
183	assert.Equal(t, "52:54:00:3b:52:65", vps.MacAddress)
184	assert.EqualValues(t, 1, vps.CurrentSnapshots)
185	assert.EqualValues(t, 10, vps.MaxSnapshots)
186	assert.Equal(t, false, vps.IsLocked)
187	assert.Equal(t, false, vps.IsBlocked)
188	assert.Equal(t, false, vps.IsCustomerLocked)
189	assert.Equal(t, "ams0", vps.AvailabilityZone)
190	assert.Equal(t, []string{"customTag", "anotherTag"}, vps.Tags)
191}
192
193func TestRepository_Order(t *testing.T) {
194	const expectedRequestBody = `{"productName":"vps-bladevps-x8","operatingSystem":"ubuntu-18.04","availabilityZone":"ams0","description":"example vps description","addons":["vpsAddon-1-extra-cpu-core"],"installFlavour":"cloudinit","hostname":"server01.example.com","username":"bob","sshKeys":["ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDf2pxWX/yhUBDyk2LPhvRtI0LnVO8PyR5Zt6AHrnhtLGqK+8YG9EMlWbCCWrASR+Q1hFQG example"],"base64InstallText":"testtext123"}`
195	server := mockServer{t: t, expectedURL: "/vps", expectedMethod: "POST", statusCode: 201, expectedRequest: expectedRequestBody}
196	client, tearDown := server.getClient()
197	defer tearDown()
198	repo := Repository{Client: *client}
199
200	order := Order{
201		ProductName:       "vps-bladevps-x8",
202		OperatingSystem:   "ubuntu-18.04",
203		AvailabilityZone:  "ams0",
204		Addons:            []string{"vpsAddon-1-extra-cpu-core"},
205		InstallFlavour:    InstallFlavourCloudInit,
206		Hostname:          "server01.example.com",
207		Username:          "bob",
208		SSHKeys:           []string{"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDf2pxWX/yhUBDyk2LPhvRtI0LnVO8PyR5Zt6AHrnhtLGqK+8YG9EMlWbCCWrASR+Q1hFQG example"},
209		Description:       "example vps description",
210		Base64InstallText: "testtext123",
211	}
212
213	err := repo.Order(order)
214	require.NoError(t, err)
215}
216
217func TestRepository_OrderMultiple(t *testing.T) {
218	const expectedRequestBody = `{"vpss":[{"productName":"vps-bladevps-x8","operatingSystem":"ubuntu-18.04","availabilityZone":"ams0","description":"webserver01","addons":["vpsAddon-1-extra-cpu-core"],"hostname":"server01.example.com","base64InstallText":"testtext123"},{"productName":"vps-bladevps-x8","operatingSystem":"ubuntu-18.04","availabilityZone":"ams0","description":"backupserver01","hostname":"server01.example.com"}]}`
219	server := mockServer{t: t, expectedURL: "/vps", expectedMethod: "POST", statusCode: 201, expectedRequest: expectedRequestBody}
220	client, tearDown := server.getClient()
221	defer tearDown()
222	repo := Repository{Client: *client}
223
224	orders := []Order{{
225		ProductName:       "vps-bladevps-x8",
226		OperatingSystem:   "ubuntu-18.04",
227		AvailabilityZone:  "ams0",
228		Addons:            []string{"vpsAddon-1-extra-cpu-core"},
229		Hostname:          "server01.example.com",
230		Description:       "webserver01",
231		Base64InstallText: "testtext123",
232	}, {
233		ProductName:      "vps-bladevps-x8",
234		OperatingSystem:  "ubuntu-18.04",
235		AvailabilityZone: "ams0",
236		Hostname:         "server01.example.com",
237		Description:      "backupserver01",
238	}}
239
240	err := repo.OrderMultiple(orders)
241	require.NoError(t, err)
242}
243
244func TestRepository_Clone(t *testing.T) {
245	const expectedRequest = `{"vpsName":"example-vps"}`
246	server := mockServer{t: t, expectedURL: "/vps", expectedMethod: "POST", statusCode: 201, expectedRequest: expectedRequest}
247	client, tearDown := server.getClient()
248	defer tearDown()
249	repo := Repository{Client: *client}
250
251	err := repo.Clone("example-vps")
252	require.NoError(t, err)
253}
254
255func TestRepository_CloneToAvailabilityZone(t *testing.T) {
256	const expectedRequest = `{"vpsName":"example-vps","availabilityZone":"ams0"}`
257	server := mockServer{t: t, expectedURL: "/vps", expectedMethod: "POST", statusCode: 201, expectedRequest: expectedRequest}
258	client, tearDown := server.getClient()
259	defer tearDown()
260	repo := Repository{Client: *client}
261
262	err := repo.CloneToAvailabilityZone("example-vps", "ams0")
263	require.NoError(t, err)
264}
265
266func TestRepository_Update(t *testing.T) {
267	const expectedRequest = `{"vps":{"name":"example-vps","uuid":"bfa08ad9-6c12-4e03-95dd-a888b97ffe49","description":"example VPS","productName":"vps-bladevps-x1","operatingSystem":"ubuntu-18.04","diskSize":157286400,"memorySize":4194304,"cpus":2,"status":"running","ipAddress":"37.97.254.6","macAddress":"52:54:00:3b:52:65","currentSnapshots":1,"maxSnapshots":10,"isCustomerLocked":false,"availabilityZone":"ams0","tags":["customTag","anotherTag"]}}`
268	server := mockServer{t: t, expectedURL: "/vps/example-vps", expectedMethod: "PUT", statusCode: 204, expectedRequest: expectedRequest}
269	client, tearDown := server.getClient()
270	defer tearDown()
271	repo := Repository{Client: *client}
272
273	vpsToUpdate := Vps{
274		Name:             "example-vps",
275		UUID:             "bfa08ad9-6c12-4e03-95dd-a888b97ffe49",
276		Description:      "example VPS",
277		ProductName:      "vps-bladevps-x1",
278		OperatingSystem:  "ubuntu-18.04",
279		DiskSize:         157286400,
280		MemorySize:       4194304,
281		CPUs:             2,
282		Status:           "running",
283		IPAddress:        "37.97.254.6",
284		MacAddress:       "52:54:00:3b:52:65",
285		CurrentSnapshots: 1,
286		MaxSnapshots:     10,
287		IsLocked:         false,
288		IsBlocked:        false,
289		IsCustomerLocked: false,
290		AvailabilityZone: "ams0",
291		Tags:             []string{"customTag", "anotherTag"},
292	}
293
294	err := repo.Update(vpsToUpdate)
295
296	require.NoError(t, err)
297}
298
299func TestRepository_Start(t *testing.T) {
300	const expectedRequest = `{"action":"start"}`
301	server := mockServer{t: t, expectedURL: "/vps/example-vps", expectedMethod: "PATCH", statusCode: 204, expectedRequest: expectedRequest}
302	client, tearDown := server.getClient()
303	defer tearDown()
304	repo := Repository{Client: *client}
305
306	err := repo.Start("example-vps")
307	require.NoError(t, err)
308}
309
310func TestRepository_Stop(t *testing.T) {
311	const expectedRequest = `{"action":"stop"}`
312	server := mockServer{t: t, expectedURL: "/vps/example-vps", expectedMethod: "PATCH", statusCode: 204, expectedRequest: expectedRequest}
313	client, tearDown := server.getClient()
314	defer tearDown()
315	repo := Repository{Client: *client}
316
317	err := repo.Stop("example-vps")
318	require.NoError(t, err)
319}
320
321func TestRepository_Reset(t *testing.T) {
322	const expectedRequest = `{"action":"reset"}`
323	server := mockServer{t: t, expectedURL: "/vps/example-vps", expectedMethod: "PATCH", statusCode: 204, expectedRequest: expectedRequest}
324	client, tearDown := server.getClient()
325	defer tearDown()
326	repo := Repository{Client: *client}
327
328	err := repo.Reset("example-vps")
329	require.NoError(t, err)
330}
331
332func TestRepository_Handover(t *testing.T) {
333	const expectedRequest = `{"action":"handover","targetCustomerName":"bobexample"}`
334	server := mockServer{t: t, expectedURL: "/vps/example-vps", expectedMethod: "PATCH", statusCode: 204, expectedRequest: expectedRequest}
335	client, tearDown := server.getClient()
336	defer tearDown()
337	repo := Repository{Client: *client}
338
339	err := repo.Handover("example-vps", "bobexample")
340	require.NoError(t, err)
341}
342
343func TestRepository_Cancel(t *testing.T) {
344	const expectedRequest = `{"endTime":"end"}`
345	server := mockServer{t: t, expectedURL: "/vps/example-vps", expectedMethod: "DELETE", statusCode: 204, expectedRequest: expectedRequest}
346	client, tearDown := server.getClient()
347	defer tearDown()
348	repo := Repository{Client: *client}
349
350	err := repo.Cancel("example-vps", gotransip.CancellationTimeEnd)
351	require.NoError(t, err)
352}
353
354func TestRepository_GetUsageData(t *testing.T) {
355	const apiResponse = `{"usage":{"cpu":[{"percentage":3.11,"date":1574783109}]}} `
356
357	values := url.Values{
358		"dateTimeStart": []string{"1500538995"},
359		"dateTimeEnd":   []string{"1500542619"},
360		"types":         []string{"cpu"},
361	}
362
363	expectedURL := "/vps/example-vps/usage?" + values.Encode()
364	server := mockServer{t: t, expectedURL: expectedURL, expectedMethod: "GET", statusCode: 200, response: apiResponse}
365	client, tearDown := server.getClient()
366	defer tearDown()
367	repo := Repository{Client: *client}
368
369	usageData, err := repo.GetUsage("example-vps", []UsageType{UsageTypeCPU}, UsagePeriod{TimeStart: 1500538995, TimeEnd: 1500542619})
370	require.NoError(t, err)
371
372	require.Equal(t, 1, len(usageData.CPU))
373	assert.EqualValues(t, 3.11, usageData.CPU[0].Percentage)
374	assert.EqualValues(t, 1574783109, usageData.CPU[0].Date)
375}
376
377func TestRepository_GetAllUsageDataByVps(t *testing.T) {
378	const apiResponse = `{ "usage": { "cpu": [ { "percentage": 3.11, "date": 1574783109 } ], "disk": [ { "iopsRead": 0.27, "iopsWrite": 0.13, "date": 1574783109 } ], "network": [ { "mbitOut": 100.2, "mbitIn": 249.93, "date": 1574783109 } ] } } `
379
380	values := url.Values{
381		"dateTimeStart": []string{"1500538995"},
382		"dateTimeEnd":   []string{"1500542619"},
383		"types":         []string{"cpu,disk,network"},
384	}
385
386	expectedURL := "/vps/example-vps/usage?" + values.Encode()
387	server := mockServer{t: t, expectedURL: expectedURL, expectedMethod: "GET", statusCode: 200, response: apiResponse}
388	client, tearDown := server.getClient()
389	defer tearDown()
390	repo := Repository{Client: *client}
391
392	usageData, err := repo.GetAllUsage("example-vps", UsagePeriod{TimeStart: 1500538995, TimeEnd: 1500542619})
393	require.NoError(t, err)
394
395	require.Equal(t, 1, len(usageData.CPU))
396	require.Equal(t, 1, len(usageData.Disk))
397	require.Equal(t, 1, len(usageData.Network))
398
399	assert.EqualValues(t, 3.11, usageData.CPU[0].Percentage)
400	assert.EqualValues(t, 1574783109, usageData.CPU[0].Date)
401
402	assert.EqualValues(t, 0.27, usageData.Disk[0].IopsRead)
403	assert.EqualValues(t, 0.13, usageData.Disk[0].IopsWrite)
404	assert.EqualValues(t, 1574783109, usageData.Disk[0].Date)
405
406	assert.EqualValues(t, 100.2, usageData.Network[0].MbitOut)
407	assert.EqualValues(t, 249.93, usageData.Network[0].MbitIn)
408	assert.EqualValues(t, 1574783109, usageData.Network[0].Date)
409}
410
411func TestRepository_GetAllUsageDataByVps24Hours(t *testing.T) {
412	const apiResponse = `{ "usage": { "cpu": [ { "percentage": 3.11, "date": 1574783109 } ], "disk": [ { "iopsRead": 0.27, "iopsWrite": 0.13, "date": 1574783109 } ], "network": [ { "mbitOut": 100.2, "mbitIn": 249.93, "date": 1574783109 } ] } } `
413
414	values := url.Values{
415		"dateTimeStart": []string{fmt.Sprintf("%d", time.Now().Add(-24*time.Hour).Unix())},
416		"dateTimeEnd":   []string{fmt.Sprintf("%d", time.Now().Unix())},
417		"types":         []string{"cpu,disk,network"},
418	}
419
420	expectedURL := "/vps/example-vps/usage?" + values.Encode()
421	server := mockServer{t: t, expectedURL: expectedURL, expectedMethod: "GET", statusCode: 200, response: apiResponse}
422	client, tearDown := server.getClient()
423	defer tearDown()
424	repo := Repository{Client: *client}
425
426	usageData, err := repo.GetAllUsage24Hours("example-vps")
427	require.NoError(t, err)
428
429	require.Equal(t, 1, len(usageData.CPU))
430	require.Equal(t, 1, len(usageData.Disk))
431	require.Equal(t, 1, len(usageData.Network))
432
433	assert.EqualValues(t, 3.11, usageData.CPU[0].Percentage)
434	assert.EqualValues(t, 1574783109, usageData.CPU[0].Date)
435
436	assert.EqualValues(t, 0.27, usageData.Disk[0].IopsRead)
437	assert.EqualValues(t, 0.13, usageData.Disk[0].IopsWrite)
438	assert.EqualValues(t, 1574783109, usageData.Disk[0].Date)
439
440	assert.EqualValues(t, 100.2, usageData.Network[0].MbitOut)
441	assert.EqualValues(t, 249.93, usageData.Network[0].MbitIn)
442	assert.EqualValues(t, 1574783109, usageData.Network[0].Date)
443}
444
445func TestRepository_GetVNCData(t *testing.T) {
446	const apiResponse = `{ "vncData": { "host": "vncproxy.transip.nl", "path": "websockify?token=testtokentje", "url": "https://vncproxy.transip.nl/websockify?token=testtokentje", "token": "testtokentje", "password": "esisteinpassw0rd" } }`
447	server := mockServer{t: t, expectedURL: "/vps/example-vps/vnc-data", expectedMethod: "GET", statusCode: 200, response: apiResponse}
448	client, tearDown := server.getClient()
449	defer tearDown()
450	repo := Repository{Client: *client}
451
452	vncData, err := repo.GetVNCData("example-vps")
453	require.NoError(t, err)
454	assert.Equal(t, "vncproxy.transip.nl", vncData.Host)
455	assert.Equal(t, "websockify?token=testtokentje", vncData.Path)
456	assert.Equal(t, "https://vncproxy.transip.nl/websockify?token=testtokentje", vncData.URL)
457	assert.Equal(t, "esisteinpassw0rd", vncData.Password)
458	assert.Equal(t, "testtokentje", vncData.Token)
459
460}
461
462func TestRepository_RegenerateVNCToken(t *testing.T) {
463	server := mockServer{t: t, expectedURL: "/vps/example-vps/vnc-data", expectedMethod: "PATCH", statusCode: 204}
464	client, tearDown := server.getClient()
465	defer tearDown()
466	repo := Repository{Client: *client}
467
468	err := repo.RegenerateVNCToken("example-vps")
469	require.NoError(t, err)
470}
471
472func TestRepository_GetAddons(t *testing.T) {
473	const apiResponse = `{ "addons": { "active": [ { "name": "example-product-name", "description": "This is an example product", "price": 499, "recurringPrice": 799 } ], "cancellable": [ { "name": "example-product-name", "description": "This is an example product", "price": 499, "recurringPrice": 799 } ], "available": [ { "name": "example-product-name", "description": "This is an example product", "price": 499, "recurringPrice": 799 } ] } }`
474	server := mockServer{t: t, expectedURL: "/vps/example-vps/addons", expectedMethod: "GET", statusCode: 200, response: apiResponse}
475	client, tearDown := server.getClient()
476	defer tearDown()
477	repo := Repository{Client: *client}
478
479	allAddons, err := repo.GetAddons("example-vps")
480	require.NoError(t, err)
481	require.Equal(t, 1, len(allAddons.Active))
482	require.Equal(t, 1, len(allAddons.Cancellable))
483	require.Equal(t, 1, len(allAddons.Available))
484
485	assert.Equal(t, "example-product-name", allAddons.Active[0].Name)
486	assert.Equal(t, "This is an example product", allAddons.Active[0].Description)
487	assert.Equal(t, 499, allAddons.Active[0].Price)
488	assert.Equal(t, 799, allAddons.Active[0].RecurringPrice)
489
490	assert.Equal(t, "example-product-name", allAddons.Cancellable[0].Name)
491	assert.Equal(t, "This is an example product", allAddons.Cancellable[0].Description)
492	assert.Equal(t, 499, allAddons.Cancellable[0].Price)
493	assert.Equal(t, 799, allAddons.Cancellable[0].RecurringPrice)
494
495	assert.Equal(t, "example-product-name", allAddons.Available[0].Name)
496	assert.Equal(t, "This is an example product", allAddons.Available[0].Description)
497	assert.Equal(t, 499, allAddons.Available[0].Price)
498	assert.Equal(t, 799, allAddons.Available[0].RecurringPrice)
499}
500
501func TestRepository_OrderAddons(t *testing.T) {
502	const expectedRequest = `{"addons":["vps-addon-1-extra-ip-address"]}`
503	server := mockServer{t: t, expectedURL: "/vps/example-vps/addons", expectedMethod: "POST", statusCode: 201, expectedRequest: expectedRequest}
504	client, tearDown := server.getClient()
505	defer tearDown()
506	repo := Repository{Client: *client}
507
508	err := repo.OrderAddons("example-vps", []string{"vps-addon-1-extra-ip-address"})
509	require.NoError(t, err)
510}
511
512func TestRepository_CancelAddon(t *testing.T) {
513	server := mockServer{t: t, expectedURL: "/vps/example-vps/addons/einaddon", expectedMethod: "DELETE", statusCode: 204}
514	client, tearDown := server.getClient()
515	defer tearDown()
516	repo := Repository{Client: *client}
517
518	err := repo.CancelAddon("example-vps", "einaddon")
519	require.NoError(t, err)
520}
521
522func TestRepository_GetUpgrades(t *testing.T) {
523	const apiResponse = `{ "upgrades": [ { "name": "example-product-name", "description": "This is an example product", "price": 499, "recurringPrice": 799 } ] } `
524	server := mockServer{t: t, expectedURL: "/vps/example-vps/upgrades", expectedMethod: "GET", statusCode: 200, response: apiResponse}
525	client, tearDown := server.getClient()
526	defer tearDown()
527	repo := Repository{Client: *client}
528
529	allUpgrades, err := repo.GetUpgrades("example-vps")
530	require.NoError(t, err)
531	require.Equal(t, 1, len(allUpgrades))
532
533	assert.Equal(t, "example-product-name", allUpgrades[0].Name)
534	assert.Equal(t, "This is an example product", allUpgrades[0].Description)
535	assert.Equal(t, 499, allUpgrades[0].Price)
536	assert.Equal(t, 799, allUpgrades[0].RecurringPrice)
537}
538
539func TestRepository_Upgrade(t *testing.T) {
540	const expectedRequest = `{"productName":"vps-bladevps-pro-x16"}`
541	server := mockServer{t: t, expectedURL: "/vps/example-vps/upgrades", expectedMethod: "POST", statusCode: 201, expectedRequest: expectedRequest}
542	client, tearDown := server.getClient()
543	defer tearDown()
544	repo := Repository{Client: *client}
545
546	err := repo.Upgrade("example-vps", "vps-bladevps-pro-x16")
547	require.NoError(t, err)
548}
549
550func TestRepository_GetOperatingSystems(t *testing.T) {
551	const apiResponse = `{
552  "operatingSystems": [
553    {
554      "name": "ubuntu-18.04",
555      "description": "Ubuntu 18.04 LTS",
556      "version": "18.04 LTS",
557      "price": 1250,
558      "installFlavours": [
559        "installer",
560        "preinstallable",
561        "cloudinit"
562      ]
563    }
564  ]
565}`
566	server := mockServer{t: t, expectedURL: "/vps/example-vps/operating-systems", expectedMethod: "GET", statusCode: 200, response: apiResponse}
567	client, tearDown := server.getClient()
568	defer tearDown()
569	repo := Repository{Client: *client}
570
571	oses, err := repo.GetOperatingSystems("example-vps")
572	require.NoError(t, err)
573	require.Equal(t, 1, len(oses))
574
575	assert.Equal(t, "ubuntu-18.04", oses[0].Name)
576	assert.Equal(t, "Ubuntu 18.04 LTS", oses[0].Description)
577	assert.Equal(t, false, oses[0].IsPreinstallableImage)
578	assert.Contains(t, oses[0].InstallFlavours, InstallFlavourInstaller)
579	assert.Contains(t, oses[0].InstallFlavours, InstallFlavourPreinstallable)
580	assert.Contains(t, oses[0].InstallFlavours, InstallFlavourCloudInit)
581	assert.Equal(t, "18.04 LTS", oses[0].Version)
582	assert.Equal(t, 1250, oses[0].Price)
583}
584
585func TestRepository_InstallOperatingSystemOptionalFields(t *testing.T) {
586	const expectedRequest = `{"operatingSystemName":"ubuntu-18.04"}`
587	server := mockServer{t: t, expectedURL: "/vps/example-vps/operating-systems", expectedMethod: "POST", statusCode: 201, expectedRequest: expectedRequest}
588	client, tearDown := server.getClient()
589	defer tearDown()
590	repo := Repository{Client: *client}
591
592	err := repo.InstallOperatingSystem("example-vps", "ubuntu-18.04", "", "")
593	require.NoError(t, err)
594}
595
596func TestRepository_InstallOperatingSystem(t *testing.T) {
597	const expectedRequest = `{"operatingSystemName":"ubuntu-18.04","hostname":"test","base64InstallText":"ZGFzaXN0YmFzZTY0"}`
598	server := mockServer{t: t, expectedURL: "/vps/example-vps/operating-systems", expectedMethod: "POST", statusCode: 201, expectedRequest: expectedRequest}
599	client, tearDown := server.getClient()
600	defer tearDown()
601	repo := Repository{Client: *client}
602
603	err := repo.InstallOperatingSystem("example-vps", "ubuntu-18.04", "test", "ZGFzaXN0YmFzZTY0")
604	require.NoError(t, err)
605}
606
607func TestRepository_InstallOperatingSystemWithOptions(t *testing.T) {
608	const expectedRequest = `{"operatingSystemName":"ubuntu-20.04","installFlavour":"cloudinit","username":"bob","sshKeys":["ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDf2pxWX/yhUBDyk2LPhvRtI0LnVO8PyR5Zt6AHrnhtLGqK+8YG9EMlWbCCWrASR+Q1hFQG example"]}`
609	server := mockServer{t: t, expectedURL: "/vps/example-vps/operating-systems", expectedMethod: "POST", statusCode: 201, expectedRequest: expectedRequest}
610	client, tearDown := server.getClient()
611	defer tearDown()
612	repo := Repository{Client: *client}
613
614	options := InstallOptions{
615		OperatingSystemName: "ubuntu-20.04",
616		InstallFlavour:      "cloudinit",
617		Hostname:            "",
618		Username:            "bob",
619		SSHKeys:             []string{"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDf2pxWX/yhUBDyk2LPhvRtI0LnVO8PyR5Zt6AHrnhtLGqK+8YG9EMlWbCCWrASR+Q1hFQG example"},
620		Base64InstallText:   "",
621	}
622
623	err := repo.InstallOperatingSystemWithOptions("example-vps", options)
624	require.NoError(t, err)
625}
626
627func TestRepository_GetIPAddresses(t *testing.T) {
628	const apiResponse = `{ "ipAddresses" : [ { "dnsResolvers" : [ "195.8.195.8", "195.135.195.135" ], "subnetMask" : "255.255.255.0", "reverseDns" : "example.com", "address" : "149.210.192.184", "gateway" : "149.210.192.1" }, { "address" : "2a01:7c8:aab5:5d5::1", "gateway" : "2a01:7c8:aab5::1", "dnsResolvers" : [ "2a01:7c8:7000:195::8:195:8", "2a01:7c8:7000:195::135:195:135" ], "subnetMask" : "/48", "reverseDns" : "example.com" } ] }`
629	server := mockServer{t: t, expectedURL: "/vps/example-vps/ip-addresses", expectedMethod: "GET", statusCode: 200, response: apiResponse}
630	client, tearDown := server.getClient()
631	defer tearDown()
632	repo := Repository{Client: *client}
633
634	ips, err := repo.GetIPAddresses("example-vps")
635	require.NoError(t, err)
636	require.Equal(t, 2, len(ips))
637
638	assert.EqualValues(t, "149.210.192.184", ips[0].Address.String())
639	assert.EqualValues(t, "00000000000000000000ffffffffff00", ips[0].SubnetMask.String())
640	assert.EqualValues(t, "149.210.192.1", ips[0].Gateway.String())
641	assert.EqualValues(t, "195.8.195.8", ips[0].DNSResolvers[0].String())
642	assert.EqualValues(t, "195.135.195.135", ips[0].DNSResolvers[1].String())
643	assert.EqualValues(t, "example.com", ips[0].ReverseDNS)
644
645	assert.EqualValues(t, "2a01:7c8:aab5:5d5::1", ips[1].Address.String())
646	assert.EqualValues(t, "ffffffffffff00000000000000000000", ips[1].SubnetMask.String())
647	assert.EqualValues(t, "2a01:7c8:aab5::1", ips[1].Gateway.String())
648	assert.EqualValues(t, "2a01:7c8:7000:195:0:8:195:8", ips[1].DNSResolvers[0].String())
649	assert.EqualValues(t, "2a01:7c8:7000:195:0:135:195:135", ips[1].DNSResolvers[1].String())
650	assert.EqualValues(t, "example.com", ips[1].ReverseDNS)
651}
652
653func TestRepository_GetIPAddressByAddress(t *testing.T) {
654	const apiResponse = `{ "ipAddress": { "address": "37.97.254.6", "subnetMask": "255.255.255.0", "gateway": "37.97.254.1", "dnsResolvers": [ "195.8.195.8", "195.135.195.135" ], "reverseDns": "example.com" } } `
655	server := mockServer{t: t, expectedURL: "/vps/example-vps/ip-addresses/37.97.254.6", expectedMethod: "GET", statusCode: 200, response: apiResponse}
656	client, tearDown := server.getClient()
657	defer tearDown()
658	repo := Repository{Client: *client}
659
660	address := net.ParseIP("37.97.254.6")
661	ip, err := repo.GetIPAddressByAddress("example-vps", address)
662	require.NoError(t, err)
663
664	assert.EqualValues(t, "37.97.254.6", ip.Address.String())
665	assert.EqualValues(t, "00000000000000000000ffffffffff00", ip.SubnetMask.String())
666	assert.EqualValues(t, "37.97.254.1", ip.Gateway.String())
667	assert.EqualValues(t, "195.8.195.8", ip.DNSResolvers[0].String())
668	assert.EqualValues(t, "195.135.195.135", ip.DNSResolvers[1].String())
669	assert.EqualValues(t, "example.com", ip.ReverseDNS)
670}
671
672func TestRepository_AddIPv6Address(t *testing.T) {
673	const expectedRequest = `{"ipAddress":"2a01:7c8:3:1337::6"}`
674	server := mockServer{t: t, expectedURL: "/vps/example-vps/ip-addresses", expectedMethod: "POST", statusCode: 201, expectedRequest: expectedRequest}
675	client, tearDown := server.getClient()
676	defer tearDown()
677	repo := Repository{Client: *client}
678
679	address := net.ParseIP("2a01:7c8:3:1337::6")
680	err := repo.AddIPv6Address("example-vps", address)
681	require.NoError(t, err)
682}
683
684func TestRepository_UpdateReverseDNS(t *testing.T) {
685	const expectedRequest = `{"ipAddress":{"address":"37.97.254.6","gateway":"37.97.254.1","reverseDns":"example.com","subnetMask":"255.0.0.0"}}`
686	server := mockServer{t: t, expectedURL: "/vps/example-vps/ip-addresses/37.97.254.6", expectedMethod: "PUT", statusCode: 204, expectedRequest: expectedRequest}
687	client, tearDown := server.getClient()
688	defer tearDown()
689	repo := Repository{Client: *client}
690
691	ip := net.ParseIP("37.97.254.6")
692	address := ipaddress.IPAddress{
693		Address:    ip,
694		Gateway:    net.ParseIP("37.97.254.1"),
695		ReverseDNS: "example.com",
696		SubnetMask: ipaddress.SubnetMask{IPMask: ip.DefaultMask()},
697	}
698	err := repo.UpdateReverseDNS("example-vps", address)
699	require.NoError(t, err)
700}
701
702func TestRepository_RemoveIPv6Address(t *testing.T) {
703	server := mockServer{t: t, expectedURL: "/vps/example-vps/ip-addresses/2a01::1", expectedMethod: "DELETE", statusCode: 204}
704	client, tearDown := server.getClient()
705	defer tearDown()
706	repo := Repository{Client: *client}
707
708	address := net.ParseIP("2a01::1")
709	err := repo.RemoveIPv6Address("example-vps", address)
710	require.NoError(t, err)
711}
712
713func TestRepository_GetSnapshots(t *testing.T) {
714	const apiResponse = `{ "snapshots": [ { "name": "1572607577", "description": "before upgrade", "diskSize": 314572800, "status": "creating", "dateTimeCreate": "2019-07-14 12:21:11", "operatingSystem": "ubuntu-18.04" } ] } `
715	server := mockServer{t: t, expectedURL: "/vps/example-vps/snapshots", expectedMethod: "GET", statusCode: 200, response: apiResponse}
716	client, tearDown := server.getClient()
717	defer tearDown()
718	repo := Repository{Client: *client}
719
720	all, err := repo.GetSnapshots("example-vps")
721	require.NoError(t, err)
722	require.Equal(t, 1, len(all))
723
724	assert.Equal(t, "1572607577", all[0].Name)
725	assert.Equal(t, "before upgrade", all[0].Description)
726	assert.EqualValues(t, 314572800, all[0].DiskSize)
727	assert.EqualValues(t, "creating", all[0].Status)
728	assert.Equal(t, "2019-07-14 12:21:11", all[0].DateTimeCreate)
729	assert.Equal(t, "ubuntu-18.04", all[0].OperatingSystem)
730
731}
732
733func TestRepository_GetSnapshotByName(t *testing.T) {
734	const apiResponse = `{ "snapshot": { "name": "1572607577", "description": "before upgrade", "diskSize": 314572800, "status": "creating", "dateTimeCreate": "2019-07-14 12:21:11", "operatingSystem": "ubuntu-18.04" } }`
735	server := mockServer{t: t, expectedURL: "/vps/example-vps/snapshots/1572607577", expectedMethod: "GET", statusCode: 200, response: apiResponse}
736	client, tearDown := server.getClient()
737	defer tearDown()
738	repo := Repository{Client: *client}
739
740	snap, err := repo.GetSnapshotByName("example-vps", "1572607577")
741	require.NoError(t, err)
742
743	assert.Equal(t, "1572607577", snap.Name)
744	assert.Equal(t, "before upgrade", snap.Description)
745	assert.EqualValues(t, 314572800, snap.DiskSize)
746	assert.EqualValues(t, "creating", snap.Status)
747	assert.Equal(t, "2019-07-14 12:21:11", snap.DateTimeCreate)
748	assert.Equal(t, "ubuntu-18.04", snap.OperatingSystem)
749}
750
751func TestRepository_CreateSnapshot(t *testing.T) {
752	const expectedRequest = `{"description":"BeforeItsAllBroken","shouldStartVps":true}`
753	server := mockServer{t: t, expectedURL: "/vps/example-vps/snapshots", expectedMethod: "POST", statusCode: 201, expectedRequest: expectedRequest}
754	client, tearDown := server.getClient()
755	defer tearDown()
756	repo := Repository{Client: *client}
757
758	err := repo.CreateSnapshot("example-vps", "BeforeItsAllBroken", true)
759	require.NoError(t, err)
760}
761
762func TestRepository_RevertSnapshot(t *testing.T) {
763	server := mockServer{t: t, expectedURL: "/vps/example-vps/snapshots/1337", expectedMethod: "PATCH", statusCode: 204}
764	client, tearDown := server.getClient()
765	defer tearDown()
766	repo := Repository{Client: *client}
767
768	err := repo.RevertSnapshot("example-vps", "1337")
769	require.NoError(t, err)
770}
771
772func TestRepository_RevertSnapshotToOtherVps(t *testing.T) {
773	const expectedRequest = `{"destinationVpsName":"example-vps2"}`
774	server := mockServer{t: t, expectedURL: "/vps/example-vps/snapshots/1337", expectedMethod: "PATCH", statusCode: 204, expectedRequest: expectedRequest}
775	client, tearDown := server.getClient()
776	defer tearDown()
777	repo := Repository{Client: *client}
778
779	err := repo.RevertSnapshotToOtherVps("example-vps", "1337", "example-vps2")
780	require.NoError(t, err)
781}
782
783func TestRepository_RemoveSnapshot(t *testing.T) {
784	server := mockServer{t: t, expectedURL: "/vps/example-vps/snapshots/1337", expectedMethod: "DELETE", statusCode: 204}
785	client, tearDown := server.getClient()
786	defer tearDown()
787	repo := Repository{Client: *client}
788
789	err := repo.RemoveSnapshot("example-vps", "1337")
790	require.NoError(t, err)
791}
792
793func TestRepository_GetBackups(t *testing.T) {
794	const apiResponse = `{ "backups": [ { "id": 712332, "status": "active", "dateTimeCreate": "2019-11-29 22:11:20", "diskSize": 157286400, "operatingSystem": "Ubuntu 19.10", "availabilityZone": "ams0" } ] }`
795	server := mockServer{t: t, expectedURL: "/vps/example-vps/backups", expectedMethod: "GET", statusCode: 200, response: apiResponse}
796	client, tearDown := server.getClient()
797	defer tearDown()
798	repo := Repository{Client: *client}
799
800	all, err := repo.GetBackups("example-vps")
801	require.NoError(t, err)
802	require.Equal(t, 1, len(all))
803
804	assert.EqualValues(t, 712332, all[0].ID)
805	assert.EqualValues(t, "active", all[0].Status)
806	assert.Equal(t, "2019-11-29 22:11:20", all[0].DateTimeCreate.Format("2006-01-02 15:04:05"))
807	assert.EqualValues(t, 157286400, all[0].DiskSize)
808	assert.Equal(t, "Ubuntu 19.10", all[0].OperatingSystem)
809	assert.Equal(t, "ams0", all[0].AvailabilityZone)
810}
811
812func TestRepository_RevertBackup(t *testing.T) {
813	const expectedRequest = `{"action":"revert"}`
814	server := mockServer{t: t, expectedURL: "/vps/example-vps/backups/1337", expectedMethod: "PATCH", statusCode: 204, expectedRequest: expectedRequest}
815	client, tearDown := server.getClient()
816	defer tearDown()
817	repo := Repository{Client: *client}
818
819	err := repo.RevertBackup("example-vps", 1337)
820	require.NoError(t, err)
821}
822
823func TestRepository_ConvertBackupToSnapshot(t *testing.T) {
824	const expectedRequest = `{"action":"convert","description":"BeforeItsAllBroken"}`
825	server := mockServer{t: t, expectedURL: "/vps/example-vps/backups/1337", expectedMethod: "PATCH", statusCode: 204, expectedRequest: expectedRequest}
826	client, tearDown := server.getClient()
827	defer tearDown()
828	repo := Repository{Client: *client}
829
830	err := repo.ConvertBackupToSnapshot("example-vps", 1337, "BeforeItsAllBroken")
831	require.NoError(t, err)
832}
833