1package cloudflare
2
3import (
4	"context"
5	"fmt"
6	"io/ioutil"
7	"net/http"
8	"testing"
9	"time"
10
11	"github.com/stretchr/testify/assert"
12)
13
14func TestCustomHostname_DeleteCustomHostname(t *testing.T) {
15	setup()
16	defer teardown()
17
18	mux.HandleFunc("/zones/foo/custom_hostnames/bar", func(w http.ResponseWriter, r *http.Request) {
19		assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method)
20
21		w.Header().Set("content-type", "application/json")
22		fmt.Fprintf(w, `
23{
24  "id": "bar"
25}`)
26	})
27
28	err := client.DeleteCustomHostname(context.Background(), "foo", "bar")
29
30	assert.NoError(t, err)
31}
32
33func TestCustomHostname_CreateCustomHostname(t *testing.T) {
34	setup()
35	defer teardown()
36
37	mux.HandleFunc("/zones/foo/custom_hostnames", func(w http.ResponseWriter, r *http.Request) {
38		assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method)
39
40		w.Header().Set("content-type", "application/json")
41		w.WriteHeader(http.StatusCreated)
42		fmt.Fprintf(w, `
43{
44	"success": true,
45	"errors": [],
46	"messages": [],
47	"result": {
48		"id": "0d89c70d-ad9f-4843-b99f-6cc0252067e9",
49		"hostname": "app.example.com",
50		"custom_origin_server": "example.app.com",
51		"ssl": {
52			"status": "pending_validation",
53			"method": "cname",
54			"type": "dv",
55			"cname_target": "dcv.digicert.com",
56			"cname": "810b7d5f01154524b961ba0cd578acc2.app.example.com",
57			"settings": {
58			"http2": "on"
59			}
60		},
61		"status": "pending",
62		"verification_errors": [
63		  "None of the A or AAAA records are owned by this account and the pre-generated ownership verification token was not found."
64		],
65		"ownership_verification": {
66		  "type": "txt",
67		  "name": "_cf-custom-hostname.app.example.com",
68		  "value": "38ddbedc-6cc3-4a4c-af67-9c5b02344ce0"
69		},
70		"ownership_verification_http": {
71		  "http_url": "http://app.example.com/.well-known/cf-custom-hostname-challenge/37c82d20-99fb-490e-ba0a-489fa483b776",
72		  "http_body": "38ddbedc-6cc3-4a4c-af67-9c5b02344ce0"
73		},
74		"created_at": "2020-02-06T18:11:23.531995Z"
75	}
76}`)
77	})
78
79	response, err := client.CreateCustomHostname(context.Background(), "foo", CustomHostname{Hostname: "app.example.com", SSL: &CustomHostnameSSL{Method: "cname", Type: "dv"}})
80
81	createdAt, _ := time.Parse(time.RFC3339, "2020-02-06T18:11:23.531995Z")
82
83	want := &CustomHostnameResponse{
84		Result: CustomHostname{
85			ID:                 "0d89c70d-ad9f-4843-b99f-6cc0252067e9",
86			Hostname:           "app.example.com",
87			CustomOriginServer: "example.app.com",
88			SSL: &CustomHostnameSSL{
89				Type:        "dv",
90				Method:      "cname",
91				Status:      "pending_validation",
92				CnameTarget: "dcv.digicert.com",
93				CnameName:   "810b7d5f01154524b961ba0cd578acc2.app.example.com",
94				Settings: CustomHostnameSSLSettings{
95					HTTP2: "on",
96				},
97			},
98			Status:             "pending",
99			VerificationErrors: []string{"None of the A or AAAA records are owned by this account and the pre-generated ownership verification token was not found."},
100			OwnershipVerification: CustomHostnameOwnershipVerification{
101				Type:  "txt",
102				Name:  "_cf-custom-hostname.app.example.com",
103				Value: "38ddbedc-6cc3-4a4c-af67-9c5b02344ce0",
104			},
105			OwnershipVerificationHTTP: CustomHostnameOwnershipVerificationHTTP{
106				HTTPUrl:  "http://app.example.com/.well-known/cf-custom-hostname-challenge/37c82d20-99fb-490e-ba0a-489fa483b776",
107				HTTPBody: "38ddbedc-6cc3-4a4c-af67-9c5b02344ce0",
108			},
109			CreatedAt: &createdAt,
110		},
111		Response: Response{Success: true, Errors: []ResponseInfo{}, Messages: []ResponseInfo{}},
112	}
113
114	if assert.NoError(t, err) {
115		assert.Equal(t, want, response)
116	}
117}
118
119func TestCustomHostname_CreateCustomHostname_MethodTxt(t *testing.T) {
120	setup()
121	defer teardown()
122
123	mux.HandleFunc("/zones/foo/custom_hostnames", func(w http.ResponseWriter, r *http.Request) {
124		assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method)
125
126		w.Header().Set("content-type", "application/json")
127		w.WriteHeader(http.StatusCreated)
128		fmt.Fprintf(w, `
129{
130	"success": true,
131	"errors": [],
132	"messages": [],
133	"result": {
134		"id": "0d89c70d-ad9f-4843-b99f-6cc0252067e9",
135		"hostname": "app.example.com",
136		"custom_origin_server": "example.app.com",
137		"ssl": {
138			"status": "pending_validation",
139			"method": "txt",
140			"type": "dv",
141			"txt_name": "app.example.com",
142			"txt_value": "ca3-f8db94da174g4c409b17fcaa5470deb2",
143			"settings": {
144			"http2": "on"
145			}
146		},
147		"status": "pending",
148		"verification_errors": [
149		  "None of the A or AAAA records are owned by this account and the pre-generated ownership verification token was not found."
150		],
151		"ownership_verification": {
152		  "type": "txt",
153		  "name": "_cf-custom-hostname.app.example.com",
154		  "value": "38ddbedc-6cc3-4a4c-af67-9c5b02344ce0"
155		},
156		"ownership_verification_http": {
157		  "http_url": "http://app.example.com/.well-known/cf-custom-hostname-challenge/37c82d20-99fb-490e-ba0a-489fa483b776",
158		  "http_body": "38ddbedc-6cc3-4a4c-af67-9c5b02344ce0"
159		},
160		"created_at": "2020-02-06T18:11:23.531995Z"
161	}
162}`)
163	})
164
165	response, err := client.CreateCustomHostname(context.Background(), "foo", CustomHostname{Hostname: "app.example.com", SSL: &CustomHostnameSSL{Method: "txt", Type: "dv"}})
166
167	createdAt, _ := time.Parse(time.RFC3339, "2020-02-06T18:11:23.531995Z")
168
169	want := &CustomHostnameResponse{
170		Result: CustomHostname{
171			ID:                 "0d89c70d-ad9f-4843-b99f-6cc0252067e9",
172			Hostname:           "app.example.com",
173			CustomOriginServer: "example.app.com",
174			SSL: &CustomHostnameSSL{
175				Type:     "dv",
176				Method:   "txt",
177				Status:   "pending_validation",
178				TxtName:  "app.example.com",
179				TxtValue: "ca3-f8db94da174g4c409b17fcaa5470deb2",
180				Settings: CustomHostnameSSLSettings{
181					HTTP2: "on",
182				},
183			},
184			Status:             "pending",
185			VerificationErrors: []string{"None of the A or AAAA records are owned by this account and the pre-generated ownership verification token was not found."},
186			OwnershipVerification: CustomHostnameOwnershipVerification{
187				Type:  "txt",
188				Name:  "_cf-custom-hostname.app.example.com",
189				Value: "38ddbedc-6cc3-4a4c-af67-9c5b02344ce0",
190			},
191			OwnershipVerificationHTTP: CustomHostnameOwnershipVerificationHTTP{
192				HTTPUrl:  "http://app.example.com/.well-known/cf-custom-hostname-challenge/37c82d20-99fb-490e-ba0a-489fa483b776",
193				HTTPBody: "38ddbedc-6cc3-4a4c-af67-9c5b02344ce0",
194			},
195			CreatedAt: &createdAt,
196		},
197		Response: Response{Success: true, Errors: []ResponseInfo{}, Messages: []ResponseInfo{}},
198	}
199
200	if assert.NoError(t, err) {
201		assert.Equal(t, want, response)
202	}
203}
204
205func TestCustomHostname_CreateCustomHostname_CustomOrigin(t *testing.T) {
206	setup()
207	defer teardown()
208
209	mux.HandleFunc("/zones/foo/custom_hostnames", func(w http.ResponseWriter, r *http.Request) {
210		assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method)
211
212		w.Header().Set("content-type", "application/json")
213		w.WriteHeader(http.StatusCreated)
214		fmt.Fprintf(w, `
215{
216	"success": true,
217	"errors": [],
218	"messages": [],
219	"result": {
220		"id": "0d89c70d-ad9f-4843-b99f-6cc0252067e9",
221		"hostname": "app.example.com",
222		"custom_origin_server": "example.app.com",
223		"ssl": {
224			"status": "pending_validation",
225			"method": "cname",
226			"type": "dv",
227			"cname_target": "dcv.digicert.com",
228			"cname": "810b7d5f01154524b961ba0cd578acc2.app.example.com",
229			"settings": {
230			"http2": "on"
231			}
232		}
233  	}
234}`)
235	})
236
237	response, err := client.CreateCustomHostname(context.Background(), "foo", CustomHostname{Hostname: "app.example.com", CustomOriginServer: "example.app.com", SSL: &CustomHostnameSSL{Method: "cname", Type: "dv"}})
238
239	want := &CustomHostnameResponse{
240		Result: CustomHostname{
241			ID:                 "0d89c70d-ad9f-4843-b99f-6cc0252067e9",
242			Hostname:           "app.example.com",
243			CustomOriginServer: "example.app.com",
244			SSL: &CustomHostnameSSL{
245				Type:        "dv",
246				Method:      "cname",
247				Status:      "pending_validation",
248				CnameTarget: "dcv.digicert.com",
249				CnameName:   "810b7d5f01154524b961ba0cd578acc2.app.example.com",
250				Settings: CustomHostnameSSLSettings{
251					HTTP2: "on",
252				},
253			},
254		},
255		Response: Response{Success: true, Errors: []ResponseInfo{}, Messages: []ResponseInfo{}},
256	}
257
258	if assert.NoError(t, err) {
259		assert.Equal(t, want, response)
260	}
261}
262
263func TestCustomHostname_CreateCustomHostname_No_SSL(t *testing.T) {
264	setup()
265	defer teardown()
266
267	mux.HandleFunc("/zones/foo/custom_hostnames", func(w http.ResponseWriter, r *http.Request) {
268		assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method)
269
270		w.Header().Set("content-type", "application/json")
271		w.WriteHeader(http.StatusCreated)
272		fmt.Fprintf(w, `
273{
274	"success": true,
275	"errors": [],
276	"messages": [],
277	"result": {
278		"id": "0d89c70d-ad9f-4843-b99f-6cc0252067e9",
279		"hostname": "app.example.com",
280		"custom_origin_server": "example.app.com",
281		"status": "pending",
282		"verification_errors": [
283		  "None of the A or AAAA records are owned by this account and the pre-generated ownership verification token was not found."
284		],
285		"ownership_verification": {
286		  "type": "txt",
287		  "name": "_cf-custom-hostname.app.example.com",
288		  "value": "38ddbedc-6cc3-4a4c-af67-9c5b02344ce0"
289		},
290		"ownership_verification_http": {
291		  "http_url": "http://app.example.com/.well-known/cf-custom-hostname-challenge/37c82d20-99fb-490e-ba0a-489fa483b776",
292		  "http_body": "38ddbedc-6cc3-4a4c-af67-9c5b02344ce0"
293		},
294		"created_at": "2020-02-06T18:11:23.531995Z"
295	}
296}`)
297	})
298
299	response, err := client.CreateCustomHostname(context.Background(), "foo", CustomHostname{Hostname: "app.example.com"})
300
301	createdAt, _ := time.Parse(time.RFC3339, "2020-02-06T18:11:23.531995Z")
302
303	want := &CustomHostnameResponse{
304		Result: CustomHostname{
305			ID:                 "0d89c70d-ad9f-4843-b99f-6cc0252067e9",
306			Hostname:           "app.example.com",
307			CustomOriginServer: "example.app.com",
308			Status:             "pending",
309			VerificationErrors: []string{"None of the A or AAAA records are owned by this account and the pre-generated ownership verification token was not found."},
310			OwnershipVerification: CustomHostnameOwnershipVerification{
311				Type:  "txt",
312				Name:  "_cf-custom-hostname.app.example.com",
313				Value: "38ddbedc-6cc3-4a4c-af67-9c5b02344ce0",
314			},
315			OwnershipVerificationHTTP: CustomHostnameOwnershipVerificationHTTP{
316				HTTPUrl:  "http://app.example.com/.well-known/cf-custom-hostname-challenge/37c82d20-99fb-490e-ba0a-489fa483b776",
317				HTTPBody: "38ddbedc-6cc3-4a4c-af67-9c5b02344ce0",
318			},
319			CreatedAt: &createdAt,
320		},
321		Response: Response{Success: true, Errors: []ResponseInfo{}, Messages: []ResponseInfo{}},
322	}
323
324	if assert.NoError(t, err) {
325		assert.Equal(t, want, response)
326	}
327}
328
329func TestCustomHostname_CustomHostnames(t *testing.T) {
330	setup()
331	defer teardown()
332
333	mux.HandleFunc("/zones/foo/custom_hostnames", func(w http.ResponseWriter, r *http.Request) {
334		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
335
336		w.Header().Set("content-type", "application/json")
337		fmt.Fprintf(w, `{
338	"success": true,
339	"result": [
340		{
341			"id": "custom_host_1",
342			"hostname": "custom.host.one",
343			"ssl": {
344				"id": "0d89c70d-ad9f-4843-b99f-6cc0252067e9",
345				"type": "dv",
346				"method": "cname",
347				"status": "pending_validation",
348				"cname_target": "dcv.digicert.com",
349				"cname": "810b7d5f01154524b961ba0cd578acc2.app.example.com",
350				"issuer": "DigiCertInc",
351				"serial_number": "6743787633689793699141714808227354901",
352				"http_url": "http://app.example.com/.well-known/pki-validation/ca3-da12a1c25e7b48cf80408c6c1763b8a2.txt",
353      			"http_body": "ca3-574923932a82475cb8592200f1a2a23d"
354			},
355			"custom_metadata": {
356				"a_random_field": "random field value"
357			},
358			"status": "pending",
359			"verification_errors": [
360				"None of the A or AAAA records are owned by this account and the pre-generated ownership verification token was not found."
361    		],
362			"ownership_verification": {
363				"type": "txt",
364      			"name": "_cf-custom-hostname.app.example.com",
365      			"value": "5cc07c04-ea62-4a5a-95f0-419334a875a4"
366    		}
367		}
368	],
369	"result_info": {
370		"page": 1,
371		"per_page": 20,
372		"count": 5,
373		"total_count": 5
374	}
375}`)
376	})
377
378	customHostnames, _, err := client.CustomHostnames(context.Background(), "foo", 1, CustomHostname{})
379
380	want := []CustomHostname{
381		{
382			ID:       "custom_host_1",
383			Hostname: "custom.host.one",
384			SSL: &CustomHostnameSSL{
385				ID:           "0d89c70d-ad9f-4843-b99f-6cc0252067e9",
386				Type:         "dv",
387				Method:       "cname",
388				Status:       "pending_validation",
389				CnameTarget:  "dcv.digicert.com",
390				CnameName:    "810b7d5f01154524b961ba0cd578acc2.app.example.com",
391				Issuer:       "DigiCertInc",
392				SerialNumber: "6743787633689793699141714808227354901",
393				HTTPUrl:      "http://app.example.com/.well-known/pki-validation/ca3-da12a1c25e7b48cf80408c6c1763b8a2.txt",
394				HTTPBody:     "ca3-574923932a82475cb8592200f1a2a23d",
395			},
396			CustomMetadata: CustomMetadata{"a_random_field": "random field value"},
397			Status:         PENDING,
398			VerificationErrors: []string{"None of the A or AAAA records are owned " +
399				"by this account and the pre-generated ownership verification token was not found."},
400			OwnershipVerification: CustomHostnameOwnershipVerification{
401				Type:  "txt",
402				Name:  "_cf-custom-hostname.app.example.com",
403				Value: "5cc07c04-ea62-4a5a-95f0-419334a875a4",
404			},
405		},
406	}
407
408	if assert.NoError(t, err) {
409		assert.Equal(t, want, customHostnames)
410	}
411}
412
413func TestCustomHostname_CustomHostname(t *testing.T) {
414	setup()
415	defer teardown()
416
417	mux.HandleFunc("/zones/foo/custom_hostnames/bar", func(w http.ResponseWriter, r *http.Request) {
418		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
419
420		w.Header().Set("content-type", "application/json")
421		fmt.Fprintf(w, `{
422"success": true,
423"result": {
424    "id": "bar",
425    "hostname": "foo.bar.com",
426    "ssl": {
427      "id": "0d89c70d-ad9f-4843-b99f-6cc0252067e9",
428      "type": "dv",
429      "method": "http",
430      "status": "active",
431      "issuer": "DigiCertInc",
432      "serial_number": "6743787633689793699141714808227354901",
433      "settings": {
434        "ciphers": ["ECDHE-RSA-AES128-GCM-SHA256","AES128-SHA"],
435        "http2": "on",
436        "min_tls_version": "1.2"
437      }
438    },
439    "custom_metadata": {
440      "origin": "a.custom.origin"
441    },
442	"status": "pending",
443	"verification_errors": [
444		"None of the A or AAAA records are owned by this account and the pre-generated ownership verification token was not found."
445    ],
446	"ownership_verification": {
447		"type": "txt",
448     	"name": "_cf-custom-hostname.app.example.com",
449    	"value": "5cc07c04-ea62-4a5a-95f0-419334a875a4"
450    }
451  }
452}`)
453	})
454
455	customHostname, err := client.CustomHostname(context.Background(), "foo", "bar")
456
457	want := CustomHostname{
458		ID:       "bar",
459		Hostname: "foo.bar.com",
460		SSL: &CustomHostnameSSL{
461			ID:           "0d89c70d-ad9f-4843-b99f-6cc0252067e9",
462			Status:       "active",
463			Method:       "http",
464			Type:         "dv",
465			Issuer:       "DigiCertInc",
466			SerialNumber: "6743787633689793699141714808227354901",
467			Settings: CustomHostnameSSLSettings{
468				HTTP2:         "on",
469				MinTLSVersion: "1.2",
470				Ciphers:       []string{"ECDHE-RSA-AES128-GCM-SHA256", "AES128-SHA"},
471			},
472		},
473		CustomMetadata: CustomMetadata{"origin": "a.custom.origin"},
474		Status:         PENDING,
475		VerificationErrors: []string{"None of the A or AAAA records are owned " +
476			"by this account and the pre-generated ownership verification token was not found."},
477		OwnershipVerification: CustomHostnameOwnershipVerification{
478			Type:  "txt",
479			Name:  "_cf-custom-hostname.app.example.com",
480			Value: "5cc07c04-ea62-4a5a-95f0-419334a875a4",
481		},
482	}
483
484	if assert.NoError(t, err) {
485		assert.Equal(t, want, customHostname)
486	}
487}
488
489func TestCustomHostname_CustomHostname_WithSSLError(t *testing.T) {
490	setup()
491	defer teardown()
492
493	mux.HandleFunc("/zones/foo/custom_hostnames/bar", func(w http.ResponseWriter, r *http.Request) {
494		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
495
496		w.Header().Set("content-type", "application/json")
497		fmt.Fprintf(w, `{
498"success": true,
499"result": {
500	"id": "bar",
501	"hostname": "example.com",
502	"ssl": {
503		"type": "dv",
504		"method": "cname",
505		"status": "pending_validation",
506		"cname_target": "dcv.digicert.com",
507		"cname": "810b7d5f01154524b961ba0cd578acc2.example.com",
508		"validation_errors": [{
509			"message": "SERVFAIL looking up CAA for example.com"
510		}]
511	},
512	"status": "pending",
513	"verification_errors": [
514		"None of the A or AAAA records are owned by this account and the pre-generated ownership verification token was not found."
515	],
516	"ownership_verification_http": {
517		"http_url": "http://example.com/.well-known/cf-custom-hostname-challenge/0d89c70d-ad9f-4843-b99f-6cc0252067e9",
518		"http_body": "5cc07c04-ea62-4a5a-95f0-419334a875a4"
519	}
520}
521}`)
522	})
523
524	customHostname, err := client.CustomHostname(context.Background(), "foo", "bar")
525
526	want := CustomHostname{
527		ID:       "bar",
528		Hostname: "example.com",
529		SSL: &CustomHostnameSSL{
530			Type:        "dv",
531			Method:      "cname",
532			Status:      "pending_validation",
533			CnameName:   "810b7d5f01154524b961ba0cd578acc2.example.com",
534			CnameTarget: "dcv.digicert.com",
535			ValidationErrors: []CustomHostnameSSLValidationErrors{
536				{
537					Message: "SERVFAIL looking up CAA for example.com",
538				},
539			},
540		},
541		Status: PENDING,
542		VerificationErrors: []string{"None of the A or AAAA records are owned " +
543			"by this account and the pre-generated ownership verification token was not found."},
544		OwnershipVerificationHTTP: CustomHostnameOwnershipVerificationHTTP{
545			HTTPBody: "5cc07c04-ea62-4a5a-95f0-419334a875a4",
546			HTTPUrl:  "http://example.com/.well-known/cf-custom-hostname-challenge/0d89c70d-ad9f-4843-b99f-6cc0252067e9",
547		},
548	}
549
550	if assert.NoError(t, err) {
551		assert.Equal(t, want, customHostname)
552	}
553}
554
555func TestCustomHostname_UpdateCustomHostnameSSL(t *testing.T) {
556	setup()
557	defer teardown()
558
559	mux.HandleFunc("/zones/foo/custom_hostnames/0d89c70d-ad9f-4843-b99f-6cc0252067e9", func(w http.ResponseWriter, r *http.Request) {
560		assert.Equal(t, http.MethodPatch, r.Method, "Expected method 'PATCH', got %s", r.Method)
561
562		w.Header().Set("content-type", "application/json")
563		w.WriteHeader(http.StatusCreated)
564		fmt.Fprintf(w, `
565{
566	"success": true,
567	"errors": [],
568	"messages": [],
569	"result": {
570		"id": "0d89c70d-ad9f-4843-b99f-6cc0252067e9",
571		"hostname": "app.example.com",
572		"custom_origin_server": "example.app.com",
573		"ssl": {
574			"status": "pending_validation",
575			"method": "cname",
576			"type": "dv",
577			"cname_target": "dcv.digicert.com",
578			"cname": "810b7d5f01154524b961ba0cd578acc2.app.example.com",
579			"settings": {
580			"http2": "off",
581			"tls_1_3": "on"
582			}
583		}
584  	}
585}`)
586	})
587
588	response, err := client.UpdateCustomHostnameSSL(context.Background(), "foo", "0d89c70d-ad9f-4843-b99f-6cc0252067e9", &CustomHostnameSSL{Method: "cname", Type: "dv", Settings: CustomHostnameSSLSettings{HTTP2: "off", TLS13: "on"}})
589
590	want := &CustomHostnameResponse{
591		Result: CustomHostname{
592			ID:                 "0d89c70d-ad9f-4843-b99f-6cc0252067e9",
593			Hostname:           "app.example.com",
594			CustomOriginServer: "example.app.com",
595			SSL: &CustomHostnameSSL{
596				Type:        "dv",
597				Method:      "cname",
598				Status:      "pending_validation",
599				CnameTarget: "dcv.digicert.com",
600				CnameName:   "810b7d5f01154524b961ba0cd578acc2.app.example.com",
601				Settings: CustomHostnameSSLSettings{
602					HTTP2: "off",
603					TLS13: "on",
604				},
605			},
606		},
607		Response: Response{Success: true, Errors: []ResponseInfo{}, Messages: []ResponseInfo{}},
608	}
609
610	if assert.NoError(t, err) {
611		assert.Equal(t, want, response)
612	}
613}
614
615func TestCustomHostname_UpdateCustomHostname(t *testing.T) {
616	setup()
617	defer teardown()
618
619	mux.HandleFunc("/zones/foo/custom_hostnames/0d89c70d-ad9f-4843-b99f-6cc0252067e9", func(w http.ResponseWriter, r *http.Request) {
620		assert.Equal(t, http.MethodPatch, r.Method, "Expected method 'PATCH', got %s", r.Method)
621
622		defer r.Body.Close()
623		reqBody, err := ioutil.ReadAll(r.Body)
624		assert.NoError(t, err, "Reading request body")
625		assert.JSONEq(t, `
626{
627	"hostname": "app.example.com",
628	"custom_origin_server": "example.app.com",
629	"ssl": {
630		"method": "cname",
631		"type": "dv",
632		"wildcard": false,
633		"settings": {}
634	},
635	"ownership_verification": {},
636	"ownership_verification_http": {}
637}`, string(reqBody), "Unexpected request body")
638
639		w.Header().Set("content-type", "application/json")
640		w.WriteHeader(http.StatusCreated)
641		fmt.Fprintf(w, `
642{
643	"success": true,
644	"errors": [],
645	"messages": [],
646	"result": {
647		"id": "0d89c70d-ad9f-4843-b99f-6cc0252067e9",
648		"hostname": "app.example.com",
649		"custom_origin_server": "example.app.com",
650		"ssl": {
651			"status": "pending_validation",
652			"method": "cname",
653			"type": "dv",
654			"cname_target": "dcv.digicert.com",
655			"cname": "810b7d5f01154524b961ba0cd578acc2.app.example.com",
656			"settings": {
657			"http2": "off",
658			"tls_1_3": "on"
659			}
660		}
661  	}
662}`)
663	})
664
665	wildcard := false
666	response, err := client.UpdateCustomHostname(context.Background(), "foo", "0d89c70d-ad9f-4843-b99f-6cc0252067e9", CustomHostname{Hostname: "app.example.com", CustomOriginServer: "example.app.com", SSL: &CustomHostnameSSL{Method: "cname", Type: "dv", Wildcard: &wildcard}})
667
668	want := &CustomHostnameResponse{
669		Result: CustomHostname{
670			ID:                 "0d89c70d-ad9f-4843-b99f-6cc0252067e9",
671			Hostname:           "app.example.com",
672			CustomOriginServer: "example.app.com",
673			SSL: &CustomHostnameSSL{
674				Type:        "dv",
675				Method:      "cname",
676				Status:      "pending_validation",
677				CnameTarget: "dcv.digicert.com",
678				CnameName:   "810b7d5f01154524b961ba0cd578acc2.app.example.com",
679				Settings: CustomHostnameSSLSettings{
680					HTTP2: "off",
681					TLS13: "on",
682				},
683			},
684		},
685		Response: Response{Success: true, Errors: []ResponseInfo{}, Messages: []ResponseInfo{}},
686	}
687
688	if assert.NoError(t, err) {
689		assert.Equal(t, want, response)
690	}
691}
692
693func TestCustomHostname_CustomHostnameFallbackOrigin(t *testing.T) {
694	setup()
695	defer teardown()
696
697	mux.HandleFunc("/zones/foo/custom_hostnames/fallback_origin", func(w http.ResponseWriter, r *http.Request) {
698		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
699
700		w.Header().Set("content-type", "application/json")
701		fmt.Fprintf(w, `{
702  "success": true,
703  "errors": [],
704  "messages": [],
705  "result": {
706    "origin": "fallback.example.com",
707    "status": "pending_deployment",
708    "errors": [
709      "DNS records are not setup correctly. Origin should be a proxied A/AAAA/CNAME dns record"
710    ],
711    "created_at": "2019-10-28T18:11:23.37411Z",
712    "updated_at": "2020-03-16T18:11:23.531995Z"
713  }
714}`)
715	})
716
717	customHostnameFallbackOrigin, err := client.CustomHostnameFallbackOrigin(context.Background(), "foo")
718
719	want := CustomHostnameFallbackOrigin{
720		Origin: "fallback.example.com",
721		Status: "pending_deployment",
722		Errors: []string{"DNS records are not setup correctly. Origin should be a proxied A/AAAA/CNAME dns record"},
723	}
724
725	if assert.NoError(t, err) {
726		assert.Equal(t, want, customHostnameFallbackOrigin)
727	}
728}
729
730func TestCustomHostname_DeleteCustomHostnameFallbackOrigin(t *testing.T) {
731	setup()
732	defer teardown()
733
734	mux.HandleFunc("/zones/foo/custom_hostnames/fallback_origin", func(w http.ResponseWriter, r *http.Request) {
735		assert.Equal(t, http.MethodDelete, r.Method, "Expected method 'DELETE', got %s", r.Method)
736
737		w.Header().Set("content-type", "application/json")
738		fmt.Fprintf(w, `
739{
740  "id": "bar"
741}`)
742	})
743
744	err := client.DeleteCustomHostnameFallbackOrigin(context.Background(), "foo")
745
746	assert.NoError(t, err)
747}
748
749func TestCustomHostname_UpdateCustomHostnameFallbackOrigin(t *testing.T) {
750	setup()
751	defer teardown()
752
753	mux.HandleFunc("/zones/foo/custom_hostnames/fallback_origin", func(w http.ResponseWriter, r *http.Request) {
754		assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method)
755
756		w.Header().Set("content-type", "application/json")
757		w.WriteHeader(http.StatusCreated)
758		fmt.Fprintf(w, `
759{
760  "success": true,
761  "errors": [],
762  "messages": [],
763  "result": {
764    "origin": "fallback.example.com",
765    "status": "pending_deployment",
766    "errors": [
767      "DNS records are not setup correctly. Origin should be a proxied A/AAAA/CNAME dns record"
768    ],
769    "created_at": "2019-10-28T18:11:23.37411Z",
770    "updated_at": "2020-03-16T18:11:23.531995Z"
771  }
772}`)
773	})
774
775	response, err := client.UpdateCustomHostnameFallbackOrigin(context.Background(), "foo", CustomHostnameFallbackOrigin{Origin: "fallback.example.com"})
776
777	want := &CustomHostnameFallbackOriginResponse{
778		Result: CustomHostnameFallbackOrigin{
779			Origin: "fallback.example.com",
780			Status: "pending_deployment",
781			Errors: []string{"DNS records are not setup correctly. Origin should be a proxied A/AAAA/CNAME dns record"},
782		},
783		Response: Response{Success: true, Errors: []ResponseInfo{}, Messages: []ResponseInfo{}},
784	}
785
786	if assert.NoError(t, err) {
787		assert.Equal(t, want, response)
788	}
789}
790
791func TestCustomHostname_CreateCustomHostnameCustomCertificateAuthority(t *testing.T) {
792	setup()
793	defer teardown()
794
795	mux.HandleFunc("/zones/foo/custom_hostnames", func(w http.ResponseWriter, r *http.Request) {
796		assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method)
797
798		w.Header().Set("content-type", "application/json")
799		w.WriteHeader(http.StatusCreated)
800		fmt.Fprintf(w, `
801{
802  "result": {
803    "id": "614b3124-cd57-42f0-8307-000000000000",
804    "hostname": "app.example.com",
805    "ssl": {
806      "id": "d9ae4881-34d2-4820-8e28-000000000000",
807      "type": "dv",
808      "method": "http",
809      "status": "initializing",
810      "settings": {
811        "min_tls_version": "1.2"
812      },
813      "wildcard": false,
814      "certificate_authority": "lets_encrypt"
815    },
816    "custom_origin_server": "origin.example.com",
817    "created_at": "2020-06-30T21:37:36.563495Z"
818  },
819  "success": true,
820  "errors": [],
821  "messages": []
822}`)
823	})
824
825	response, err := client.CreateCustomHostname(context.Background(), "foo", CustomHostname{Hostname: "app.example.com", SSL: &CustomHostnameSSL{Method: "cname", Type: "dv", CertificateAuthority: "lets_encrypt"}})
826
827	createdAt, _ := time.Parse(time.RFC3339, "2020-06-30T21:37:36.563495Z")
828
829	wildcard := false
830	want := &CustomHostnameResponse{
831		Result: CustomHostname{
832			ID:                 "614b3124-cd57-42f0-8307-000000000000",
833			Hostname:           "app.example.com",
834			CustomOriginServer: "origin.example.com",
835			SSL: &CustomHostnameSSL{
836				ID:     "d9ae4881-34d2-4820-8e28-000000000000",
837				Type:   "dv",
838				Method: "http",
839				Status: "initializing",
840				Settings: CustomHostnameSSLSettings{
841					MinTLSVersion: "1.2",
842				},
843				Wildcard:             &wildcard,
844				CertificateAuthority: "lets_encrypt",
845			},
846			CreatedAt: &createdAt,
847		},
848		Response: Response{Success: true, Errors: []ResponseInfo{}, Messages: []ResponseInfo{}},
849	}
850
851	if assert.NoError(t, err) {
852		assert.Equal(t, want, response)
853	}
854}
855