2018-06-30 23:45:24 +00:00
// Package vegadns implements a DNS provider for solving the DNS-01
// challenge using VegaDNS.
package vegadns
import (
"fmt"
"net"
"net/http"
"net/http/httptest"
"os"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
2018-10-16 15:52:57 +00:00
"github.com/xenolf/lego/platform/tester"
2018-06-30 23:45:24 +00:00
)
2018-09-24 19:07:20 +00:00
const testDomain = "example.com"
2018-12-06 21:50:17 +00:00
const ipPort = "127.0.0.1:2112"
2018-06-30 23:45:24 +00:00
2018-10-16 15:52:57 +00:00
var envTest = tester . NewEnvTest ( "SECRET_VEGADNS_KEY" , "SECRET_VEGADNS_SECRET" , "VEGADNS_URL" )
2018-06-30 23:45:24 +00:00
type muxCallback func ( ) * http . ServeMux
2018-10-12 17:29:18 +00:00
func TestNewDNSProvider_Fail ( t * testing . T ) {
2018-10-16 15:52:57 +00:00
defer envTest . RestoreEnv ( )
envTest . ClearEnv ( )
2018-06-30 23:45:24 +00:00
_ , err := NewDNSProvider ( )
assert . Error ( t , err , "VEGADNS_URL env missing" )
}
2018-10-12 17:29:18 +00:00
func TestDNSProvider_TimeoutSuccess ( t * testing . T ) {
2018-10-16 15:52:57 +00:00
defer envTest . RestoreEnv ( )
envTest . ClearEnv ( )
2018-10-12 17:29:18 +00:00
ts , err := startTestServer ( muxSuccess )
2018-06-30 23:45:24 +00:00
require . NoError ( t , err )
defer ts . Close ( )
provider , err := NewDNSProvider ( )
require . NoError ( t , err )
timeout , interval := provider . Timeout ( )
assert . Equal ( t , timeout , time . Duration ( 720000000000 ) )
assert . Equal ( t , interval , time . Duration ( 60000000000 ) )
}
2018-09-24 19:07:20 +00:00
func TestDNSProvider_Present ( t * testing . T ) {
testCases := [ ] struct {
desc string
callback muxCallback
expectedError string
} {
{
desc : "Success" ,
2018-10-12 17:29:18 +00:00
callback : muxSuccess ,
2018-09-24 19:07:20 +00:00
} ,
{
desc : "FailToFindZone" ,
2018-10-12 17:29:18 +00:00
callback : muxFailToFindZone ,
2018-09-24 19:07:20 +00:00
expectedError : "vegadns: can't find Authoritative Zone for _acme-challenge.example.com. in Present: Unable to find auth zone for fqdn _acme-challenge.example.com" ,
} ,
{
desc : "FailToCreateTXT" ,
2018-10-12 17:29:18 +00:00
callback : muxFailToCreateTXT ,
2018-09-24 19:07:20 +00:00
expectedError : "vegadns: Got bad answer from VegaDNS on CreateTXT. Code: 400. Message: " ,
} ,
}
2018-06-30 23:45:24 +00:00
2018-09-24 19:07:20 +00:00
for _ , test := range testCases {
t . Run ( test . desc , func ( t * testing . T ) {
2018-10-16 15:52:57 +00:00
defer envTest . RestoreEnv ( )
envTest . ClearEnv ( )
2018-09-24 19:07:20 +00:00
ts , err := startTestServer ( test . callback )
require . NoError ( t , err )
2018-06-30 23:45:24 +00:00
2018-09-24 19:07:20 +00:00
defer ts . Close ( )
2018-06-30 23:45:24 +00:00
2018-09-24 19:07:20 +00:00
provider , err := NewDNSProvider ( )
require . NoError ( t , err )
2018-06-30 23:45:24 +00:00
2018-09-24 19:07:20 +00:00
err = provider . Present ( testDomain , "token" , "keyAuth" )
if len ( test . expectedError ) == 0 {
assert . NoError ( t , err )
} else {
assert . EqualError ( t , err , test . expectedError )
}
} )
}
2018-06-30 23:45:24 +00:00
}
2018-09-24 19:07:20 +00:00
func TestDNSProvider_CleanUp ( t * testing . T ) {
testCases := [ ] struct {
desc string
callback muxCallback
expectedError string
} {
{
desc : "Success" ,
2018-10-12 17:29:18 +00:00
callback : muxSuccess ,
2018-09-24 19:07:20 +00:00
} ,
{
desc : "FailToFindZone" ,
2018-10-12 17:29:18 +00:00
callback : muxFailToFindZone ,
2018-09-24 19:07:20 +00:00
expectedError : "vegadns: can't find Authoritative Zone for _acme-challenge.example.com. in CleanUp: Unable to find auth zone for fqdn _acme-challenge.example.com" ,
} ,
{
desc : "FailToGetRecordID" ,
2018-10-12 17:29:18 +00:00
callback : muxFailToGetRecordID ,
2018-09-24 19:07:20 +00:00
expectedError : "vegadns: couldn't get Record ID in CleanUp: Got bad answer from VegaDNS on GetRecordID. Code: 404. Message: " ,
} ,
}
2018-06-30 23:45:24 +00:00
2018-09-24 19:07:20 +00:00
for _ , test := range testCases {
t . Run ( test . desc , func ( t * testing . T ) {
2018-10-16 15:52:57 +00:00
defer envTest . RestoreEnv ( )
envTest . ClearEnv ( )
2018-09-24 19:07:20 +00:00
ts , err := startTestServer ( test . callback )
require . NoError ( t , err )
2018-06-30 23:45:24 +00:00
2018-09-24 19:07:20 +00:00
defer ts . Close ( )
2018-06-30 23:45:24 +00:00
2018-09-24 19:07:20 +00:00
provider , err := NewDNSProvider ( )
require . NoError ( t , err )
2018-06-30 23:45:24 +00:00
2018-09-24 19:07:20 +00:00
err = provider . CleanUp ( testDomain , "token" , "keyAuth" )
if len ( test . expectedError ) == 0 {
assert . NoError ( t , err )
} else {
assert . EqualError ( t , err , test . expectedError )
}
} )
}
2018-06-30 23:45:24 +00:00
}
2018-10-12 17:29:18 +00:00
func muxSuccess ( ) * http . ServeMux {
2018-06-30 23:45:24 +00:00
mux := http . NewServeMux ( )
mux . HandleFunc ( "/1.0/token" , func ( w http . ResponseWriter , r * http . Request ) {
2018-12-06 21:50:17 +00:00
if r . Method == http . MethodPost {
2018-06-30 23:45:24 +00:00
w . WriteHeader ( http . StatusOK )
2019-02-06 17:15:53 +00:00
fmt . Fprint ( w , tokenResponseMock )
2018-06-30 23:45:24 +00:00
return
}
w . WriteHeader ( http . StatusBadRequest )
} )
mux . HandleFunc ( "/1.0/domains" , func ( w http . ResponseWriter , r * http . Request ) {
if r . URL . Query ( ) . Get ( "search" ) == "example.com" {
w . WriteHeader ( http . StatusOK )
2019-02-06 17:15:53 +00:00
fmt . Fprint ( w , domainsResponseMock )
2018-06-30 23:45:24 +00:00
return
}
w . WriteHeader ( http . StatusNotFound )
} )
mux . HandleFunc ( "/1.0/records" , func ( w http . ResponseWriter , r * http . Request ) {
switch r . Method {
case http . MethodGet :
if r . URL . Query ( ) . Get ( "domain_id" ) == "1" {
w . WriteHeader ( http . StatusOK )
2019-02-06 17:15:53 +00:00
fmt . Fprint ( w , recordsResponseMock )
2018-06-30 23:45:24 +00:00
return
}
w . WriteHeader ( http . StatusNotFound )
return
case http . MethodPost :
w . WriteHeader ( http . StatusCreated )
2019-02-06 17:15:53 +00:00
fmt . Fprint ( w , recordCreatedResponseMock )
2018-06-30 23:45:24 +00:00
return
}
w . WriteHeader ( http . StatusBadRequest )
} )
mux . HandleFunc ( "/1.0/records/3" , func ( w http . ResponseWriter , r * http . Request ) {
2018-12-06 21:50:17 +00:00
if r . Method == http . MethodDelete {
2018-06-30 23:45:24 +00:00
w . WriteHeader ( http . StatusOK )
2019-02-06 17:15:53 +00:00
fmt . Fprint ( w , recordDeletedResponseMock )
2018-06-30 23:45:24 +00:00
return
}
w . WriteHeader ( http . StatusBadRequest )
} )
mux . HandleFunc ( "/" , func ( w http . ResponseWriter , r * http . Request ) {
w . WriteHeader ( http . StatusNotFound )
fmt . Printf ( "Not Found for Request: (%+v)\n\n" , r )
} )
return mux
}
2018-10-12 17:29:18 +00:00
func muxFailToFindZone ( ) * http . ServeMux {
2018-06-30 23:45:24 +00:00
mux := http . NewServeMux ( )
mux . HandleFunc ( "/1.0/token" , func ( w http . ResponseWriter , r * http . Request ) {
2018-12-06 21:50:17 +00:00
if r . Method == http . MethodPost {
2018-06-30 23:45:24 +00:00
w . WriteHeader ( http . StatusOK )
2019-02-06 17:15:53 +00:00
fmt . Fprint ( w , tokenResponseMock )
2018-06-30 23:45:24 +00:00
return
}
w . WriteHeader ( http . StatusBadRequest )
} )
2019-02-06 17:15:53 +00:00
mux . HandleFunc ( "/1.0/domains" , func ( w http . ResponseWriter , _ * http . Request ) {
2018-06-30 23:45:24 +00:00
w . WriteHeader ( http . StatusNotFound )
} )
return mux
}
2018-10-12 17:29:18 +00:00
func muxFailToCreateTXT ( ) * http . ServeMux {
2018-06-30 23:45:24 +00:00
mux := http . NewServeMux ( )
mux . HandleFunc ( "/1.0/token" , func ( w http . ResponseWriter , r * http . Request ) {
2018-12-06 21:50:17 +00:00
if r . Method == http . MethodPost {
2018-06-30 23:45:24 +00:00
w . WriteHeader ( http . StatusOK )
2019-02-06 17:15:53 +00:00
fmt . Fprint ( w , tokenResponseMock )
2018-06-30 23:45:24 +00:00
return
}
w . WriteHeader ( http . StatusBadRequest )
} )
mux . HandleFunc ( "/1.0/domains" , func ( w http . ResponseWriter , r * http . Request ) {
2018-09-24 19:07:20 +00:00
if r . URL . Query ( ) . Get ( "search" ) == testDomain {
2018-06-30 23:45:24 +00:00
w . WriteHeader ( http . StatusOK )
2019-02-06 17:15:53 +00:00
fmt . Fprint ( w , domainsResponseMock )
2018-06-30 23:45:24 +00:00
return
}
w . WriteHeader ( http . StatusNotFound )
} )
mux . HandleFunc ( "/1.0/records" , func ( w http . ResponseWriter , r * http . Request ) {
switch r . Method {
case http . MethodGet :
if r . URL . Query ( ) . Get ( "domain_id" ) == "1" {
w . WriteHeader ( http . StatusOK )
2019-02-06 17:15:53 +00:00
fmt . Fprint ( w , recordsResponseMock )
2018-06-30 23:45:24 +00:00
return
}
w . WriteHeader ( http . StatusNotFound )
return
case http . MethodPost :
w . WriteHeader ( http . StatusBadRequest )
return
}
w . WriteHeader ( http . StatusBadRequest )
} )
return mux
}
2018-10-12 17:29:18 +00:00
func muxFailToGetRecordID ( ) * http . ServeMux {
2018-06-30 23:45:24 +00:00
mux := http . NewServeMux ( )
mux . HandleFunc ( "/1.0/token" , func ( w http . ResponseWriter , r * http . Request ) {
2018-12-06 21:50:17 +00:00
if r . Method == http . MethodPost {
2018-06-30 23:45:24 +00:00
w . WriteHeader ( http . StatusOK )
2019-02-06 17:15:53 +00:00
fmt . Fprint ( w , tokenResponseMock )
2018-06-30 23:45:24 +00:00
return
}
w . WriteHeader ( http . StatusBadRequest )
} )
mux . HandleFunc ( "/1.0/domains" , func ( w http . ResponseWriter , r * http . Request ) {
2018-09-24 19:07:20 +00:00
if r . URL . Query ( ) . Get ( "search" ) == testDomain {
2018-06-30 23:45:24 +00:00
w . WriteHeader ( http . StatusOK )
2019-02-06 17:15:53 +00:00
fmt . Fprint ( w , domainsResponseMock )
2018-06-30 23:45:24 +00:00
return
}
w . WriteHeader ( http . StatusNotFound )
} )
mux . HandleFunc ( "/1.0/records" , func ( w http . ResponseWriter , r * http . Request ) {
2018-12-06 21:50:17 +00:00
if r . Method == http . MethodGet {
2018-06-30 23:45:24 +00:00
w . WriteHeader ( http . StatusNotFound )
return
}
w . WriteHeader ( http . StatusBadRequest )
} )
return mux
}
// Starts and returns a test server using a custom ip/port. Defer close() afterwards.
func startTestServer ( callback muxCallback ) ( * httptest . Server , error ) {
err := os . Setenv ( "SECRET_VEGADNS_KEY" , "key" )
if err != nil {
return nil , err
}
err = os . Setenv ( "SECRET_VEGADNS_SECRET" , "secret" )
if err != nil {
return nil , err
}
err = os . Setenv ( "VEGADNS_URL" , "http://" + ipPort )
if err != nil {
return nil , err
}
ts := httptest . NewUnstartedServer ( callback ( ) )
l , err := net . Listen ( "tcp" , ipPort )
if err != nil {
return nil , err
}
ts . Listener = l
ts . Start ( )
return ts , nil
}