Repository: xenolf/lego
Pull request #644 (2018-09-21 23:22:01)

Migrate to golangci-lint
Replace [gometalinter](https://github.com/alecthomas/gometalinter) by [golangci-lint](https://github.com/golangci/golangci-lint/).

Before (with gometalinter):
- gotypex
- varcheck
- gotype
- interfacer
- misspell
- ineffassign
- golint
- vet
- gosimple

After (with golangci-lint):
- deadcode
- depguard
- errcheck
- goconst
- gocyclo
- gofmt
- goimports
- golint
- gosec
- gosimple
- govet
- ineffassign
- interfacer
- megacheck
- misspell
- nakedret
- staticcheck
- structcheck
- typecheck
- unconvert
- unparam
- unused
- varcheck



Patch:
diff --git a/.golangci.toml b/.golangci.toml
new file mode 100644
index 00000000..9bfee405
--- /dev/null
+++ b/.golangci.toml
@@ -0,0 +1,42 @@
+[run]
+  deadline = "2m"
+
+[linters-settings]
+
+  [linters-settings.govet]
+    check-shadowing = true
+
+  [linters-settings.gocyclo]
+    min-complexity = 16.0
+
+  [linters-settings.maligned]
+    suggest-new = true
+
+  [linters-settings.goconst]
+    min-len = 2.0
+    min-occurrences = 3.0
+
+  [linters-settings.misspell]
+    locale = "US"
+
+[linters]
+  enable-all = true
+  disable = [
+    "maligned",
+    "lll",
+    "gas",
+    "dupl",
+    "prealloc",
+  ]
+
+[issues]
+  max-per-linter = 0
+  max-same = 0
+  exclude = [
+    "session.New is deprecated:", # providers/dns/route53/route53_integration_test.go | providers/dns/route53/route53_test.go
+    "func (.+)disableAuthz(.) is unused", # acme/client.go#disableAuthz
+    "type (.+)deactivateAuthMessage(.) is unused", # acme/messages.go#deactivateAuthMessage
+    "(.)limitReader(.) - (.)numBytes(.) always receives (.)1048576(.)", # acme/crypto.go#limitReader
+    "cyclomatic complexity (\\d+) of func (.)NewDNSChallengeProviderByName(.) is high", # providers/dns/dns_providers.go#NewDNSChallengeProviderByName
+    "cyclomatic complexity (\\d+) of func (.)setup(.) is high", # cli_handler.go#setup
+  ]
diff --git a/.travis.yml b/.travis.yml
index d3642a5a..e5da5f03 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -18,9 +18,8 @@ before_install:
   - chmod +x $GOPATH/bin/dep
 
   # Install linters and misspell
-  - go get -u github.com/alecthomas/gometalinter
-  - gometalinter --install
-
+  - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.10.2
+  - golangci-lint --version
 
 install:
   - dep status -v
diff --git a/Makefile b/Makefile
index d1379732..9ec2590f 100644
--- a/Makefile
+++ b/Makefile
@@ -17,8 +17,8 @@ dependencies:
 test: clean
 	go test -v -cover ./...
 
-checks: check-fmt
-	gometalinter ./...
+checks:
+	golangci-lint run
 
 check-fmt: SHELL := /bin/bash
 check-fmt:
diff --git a/acme/client.go b/acme/client.go
index 12fd5b37..7af45033 100644
--- a/acme/client.go
+++ b/acme/client.go
@@ -26,6 +26,9 @@ const (
 	// “new-reg”, “new-authz” and “new-cert” endpoints. From the documentation the
 	// limitation is 20 requests per second, but using 20 as value doesn't work but 18 do
 	overallRequestLimit = 18
+
+	statusValid   = "valid"
+	statusInvalid = "invalid"
 )
 
 // User interface is to be implemented by users of this library.
@@ -43,7 +46,7 @@ type solver interface {
 
 // Interface for challenges like dns, where we can set a record in advance for ALL challenges.
 // This saves quite a bit of time vs creating the records and solving them serially.
-type presolver interface {
+type preSolver interface {
 	PreSolve(challenge challenge, domain string) error
 }
 
@@ -502,9 +505,9 @@ func (c *Client) RenewCertificate(cert CertificateResource, bundle, mustStaple b
 	// Start by checking to see if the certificate was based off a CSR, and
 	// use that if it's defined.
 	if len(cert.CSR) > 0 {
-		csr, err := pemDecodeTox509CSR(cert.CSR)
-		if err != nil {
-			return nil, err
+		csr, errP := pemDecodeTox509CSR(cert.CSR)
+		if errP != nil {
+			return nil, errP
 		}
 		newCert, failures := c.ObtainCertificateForCSR(*csr, bundle)
 		return newCert, failures
@@ -537,7 +540,6 @@ func (c *Client) RenewCertificate(cert CertificateResource, bundle, mustStaple b
 }
 
 func (c *Client) createOrderForIdentifiers(domains []string) (orderResource, error) {
-
 	var identifiers []identifier
 	for _, domain := range domains {
 		identifiers = append(identifiers, identifier{Type: "dns", Value: domain})
@@ -577,16 +579,16 @@ func (c *Client) solveChallengeForAuthz(authorizations []authorization) error {
 
 	// loop through the resources, basically through the domains. First pass just selects a solver for each authz.
 	for _, authz := range authorizations {
-		if authz.Status == "valid" {
+		if authz.Status == statusValid {
 			// Boulder might recycle recent validated authz (see issue #267)
 			log.Infof("[%s] acme: Authorization already valid; skipping challenge", authz.Identifier.Value)
 			continue
 		}
-		if i, solver := c.chooseSolver(authz, authz.Identifier.Value); solver != nil {
+		if i, solvr := c.chooseSolver(authz, authz.Identifier.Value); solvr != nil {
 			authSolvers = append(authSolvers, &selectedAuthSolver{
 				authz:          authz,
 				challengeIndex: i,
-				solver:         solver,
+				solver:         solvr,
 			})
 		} else {
 			failures[authz.Identifier.Value] = fmt.Errorf("[%s] acme: Could not determine solvers", authz.Identifier.Value)
@@ -597,7 +599,7 @@ func (c *Client) solveChallengeForAuthz(authorizations []authorization) error {
 	for _, item := range authSolvers {
 		authz := item.authz
 		i := item.challengeIndex
-		if presolver, ok := item.solver.(presolver); ok {
+		if presolver, ok := item.solver.(preSolver); ok {
 			if err := presolver.PreSolve(authz.Challenges[i], authz.Identifier.Value); err != nil {
 				failures[authz.Identifier.Value] = err
 			}
@@ -607,12 +609,12 @@ func (c *Client) solveChallengeForAuthz(authorizations []authorization) error {
 	defer func() {
 		// clean all created TXT records
 		for _, item := range authSolvers {
-			if cleanup, ok := item.solver.(cleanup); ok {
+			if clean, ok := item.solver.(cleanup); ok {
 				if failures[item.authz.Identifier.Value] != nil {
 					// already failed in previous loop
 					continue
 				}
-				err := cleanup.CleanUp(item.authz.Challenges[item.challengeIndex], item.authz.Identifier.Value)
+				err := clean.CleanUp(item.authz.Challenges[item.challengeIndex], item.authz.Identifier.Value)
 				if err != nil {
 					log.Warnf("Error cleaning up %s: %v ", item.authz.Identifier.Value, err)
 				}
@@ -755,7 +757,7 @@ func (c *Client) requestCertificateForCsr(order orderResource, bundle bool, csr
 		return nil, err
 	}
 
-	if retOrder.Status == "invalid" {
+	if retOrder.Status == statusInvalid {
 		return nil, err
 	}
 
@@ -765,7 +767,7 @@ func (c *Client) requestCertificateForCsr(order orderResource, bundle bool, csr
 		PrivateKey: privateKeyPem,
 	}
 
-	if retOrder.Status == "valid" {
+	if retOrder.Status == statusValid {
 		// if the certificate is available right away, short cut!
 		ok, err := c.checkCertResponse(retOrder, &certRes, bundle)
 		if err != nil {
@@ -809,9 +811,8 @@ func (c *Client) requestCertificateForCsr(order orderResource, bundle bool, csr
 // should already have the Domain (common name) field populated. If bundle is
 // true, the certificate will be bundled with the issuer's cert.
 func (c *Client) checkCertResponse(order orderMessage, certRes *CertificateResource, bundle bool) (bool, error) {
-
 	switch order.Status {
-	case "valid":
+	case statusValid:
 		resp, err := httpGet(order.Certificate)
 		if err != nil {
 			return false, err
@@ -860,7 +861,7 @@ func (c *Client) checkCertResponse(order orderMessage, certRes *CertificateResou
 
 	case "processing":
 		return false, nil
-	case "invalid":
+	case statusInvalid:
 		return false, errors.New("order has invalid state: invalid")
 	default:
 		return false, nil
@@ -922,12 +923,12 @@ func validate(j *jws, domain, uri string, c challenge) error {
 	// Repeatedly check the server for an updated status on our request.
 	for {
 		switch chlng.Status {
-		case "valid":
+		case statusValid:
 			log.Infof("[%s] The server validated our request", domain)
 			return nil
 		case "pending":
 		case "processing":
-		case "invalid":
+		case statusInvalid:
 			return handleChallengeError(chlng)
 		default:
 			return errors.New("the server returned an unexpected state")
diff --git a/acme/crypto.go b/acme/crypto.go
index f5ebbf08..5ddeeaec 100644
--- a/acme/crypto.go
+++ b/acme/crypto.go
@@ -81,20 +81,20 @@ func GetOCSPForCert(bundle []byte) ([]byte, *ocsp.Response, error) {
 			return nil, nil, errors.New("no issuing certificate URL")
 		}
 
-		resp, err := httpGet(issuedCert.IssuingCertificateURL[0])
-		if err != nil {
-			return nil, nil, err
+		resp, errC := httpGet(issuedCert.IssuingCertificateURL[0])
+		if errC != nil {
+			return nil, nil, errC
 		}
 		defer resp.Body.Close()
 
-		issuerBytes, err := ioutil.ReadAll(limitReader(resp.Body, 1024*1024))
-		if err != nil {
-			return nil, nil, err
+		issuerBytes, errC := ioutil.ReadAll(limitReader(resp.Body, 1024*1024))
+		if errC != nil {
+			return nil, nil, errC
 		}
 
-		issuerCert, err := x509.ParseCertificate(issuerBytes)
-		if err != nil {
-			return nil, nil, err
+		issuerCert, errC := x509.ParseCertificate(issuerBytes)
+		if errC != nil {
+			return nil, nil, errC
 		}
 
 		// Insert it into the slice on position 0
@@ -258,15 +258,6 @@ func pemDecode(data []byte) (*pem.Block, error) {
 	return pemBlock, nil
 }
 
-func pemDecodeTox509(pem []byte) (*x509.Certificate, error) {
-	pemBlock, err := pemDecode(pem)
-	if pemBlock == nil {
-		return nil, err
-	}
-
-	return x509.ParseCertificate(pemBlock.Bytes)
-}
-
 func pemDecodeTox509CSR(pem []byte) (*x509.CertificateRequest, error) {
 	pemBlock, err := pemDecode(pem)
 	if pemBlock == nil {
diff --git a/acme/http.go b/acme/http.go
index 8d7ee51e..2ddbc0f1 100644
--- a/acme/http.go
+++ b/acme/http.go
@@ -148,29 +148,25 @@ func getJSON(uri string, respBody interface{}) (http.Header, error) {
 func postJSON(j *jws, uri string, reqBody, respBody interface{}) (http.Header, error) {
 	jsonBytes, err := json.Marshal(reqBody)
 	if err != nil {
-		return nil, errors.New("Failed to marshal network message")
+		return nil, errors.New("failed to marshal network message")
 	}
 
 	resp, err := j.post(uri, jsonBytes)
 	if err != nil {
-		return nil, fmt.Errorf("Failed to post JWS message. -> %v", err)
+		return nil, fmt.Errorf("failed to post JWS message. -> %v", err)
 	}
 
 	defer resp.Body.Close()
 
 	if resp.StatusCode >= http.StatusBadRequest {
-
-		err := handleHTTPError(resp)
-
+		err = handleHTTPError(resp)
 		switch err.(type) {
-
 		case NonceError:
-
 			// Retry once if the nonce was invalidated
 
-			retryResp, err := j.post(uri, jsonBytes)
-			if err != nil {
-				return nil, fmt.Errorf("Failed to post JWS message. -> %v", err)
+			retryResp, errP := j.post(uri, jsonBytes)
+			if errP != nil {
+				return nil, fmt.Errorf("failed to post JWS message. -> %v", errP)
 			}
 
 			defer retryResp.Body.Close()
diff --git a/acme/http_challenge_server.go b/acme/http_challenge_server.go
index 319e2618..9c595d7f 100644
--- a/acme/http_challenge_server.go
+++ b/acme/http_challenge_server.go
@@ -35,7 +35,7 @@ func (s *HTTPProviderServer) Present(domain, token, keyAuth string) error {
 	var err error
 	s.listener, err = net.Listen("tcp", net.JoinHostPort(s.iface, s.port))
 	if err != nil {
-		return fmt.Errorf("Could not start HTTP server for challenge -> %v", err)
+		return fmt.Errorf("could not start HTTP server for challenge -> %v", err)
 	}
 
 	s.done = make(chan bool)
@@ -62,20 +62,31 @@ func (s *HTTPProviderServer) serve(domain, token, keyAuth string) {
 	mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
 		if strings.HasPrefix(r.Host, domain) && r.Method == http.MethodGet {
 			w.Header().Add("Content-Type", "text/plain")
-			w.Write([]byte(keyAuth))
+			_, err := w.Write([]byte(keyAuth))
+			if err != nil {
+				http.Error(w, err.Error(), http.StatusInternalServerError)
+				return
+			}
 			log.Infof("[%s] Served key authentication", domain)
 		} else {
 			log.Warnf("Received request for domain %s with method %s but the domain did not match any challenge. Please ensure your are passing the HOST header properly.", r.Host, r.Method)
-			w.Write([]byte("TEST"))
+			_, err := w.Write([]byte("TEST"))
+			if err != nil {
+				http.Error(w, err.Error(), http.StatusInternalServerError)
+				return
+			}
 		}
 	})
 
-	httpServer := &http.Server{
-		Handler: mux,
-	}
+	httpServer := &http.Server{Handler: mux}
+
 	// Once httpServer is shut down we don't want any lingering
 	// connections, so disable KeepAlives.
 	httpServer.SetKeepAlivesEnabled(false)
-	httpServer.Serve(s.listener)
+
+	err := httpServer.Serve(s.listener)
+	if err != nil {
+		log.Println(err)
+	}
 	s.done <- true
 }
diff --git a/acme/tls_alpn_challenge_server.go b/acme/tls_alpn_challenge_server.go
index 8d33668e..ee06a16d 100644
--- a/acme/tls_alpn_challenge_server.go
+++ b/acme/tls_alpn_challenge_server.go
@@ -3,6 +3,7 @@ package acme
 import (
 	"crypto/tls"
 	"fmt"
+	"log"
 	"net"
 	"net/http"
 )
@@ -65,7 +66,10 @@ func (t *TLSALPNProviderServer) Present(domain, token, keyAuth string) error {
 
 	// Shut the server down when we're finished.
 	go func() {
-		http.Serve(t.listener, nil)
+		err := http.Serve(t.listener, nil)
+		if err != nil {
+			log.Println(err)
+		}
 	}()
 
 	return nil
diff --git a/acme/utils.go b/acme/utils.go
index 2fa0db30..2c68c4a3 100644
--- a/acme/utils.go
+++ b/acme/utils.go
@@ -3,16 +3,20 @@ package acme
 import (
 	"fmt"
 	"time"
+
+	"github.com/xenolf/lego/log"
 )
 
 // WaitFor polls the given function 'f', once every 'interval', up to 'timeout'.
 func WaitFor(timeout, interval time.Duration, f func() (bool, error)) error {
+	log.Infof("Wait [timeout: %s, interval: %s]", timeout, interval)
+
 	var lastErr string
 	timeup := time.After(timeout)
 	for {
 		select {
 		case <-timeup:
-			return fmt.Errorf("Time limit exceeded. Last error: %s", lastErr)
+			return fmt.Errorf("time limit exceeded: last error: %s", lastErr)
 		default:
 		}
 
diff --git a/cli.go b/cli.go
index 8a7fbfa6..77dc7c47 100644
--- a/cli.go
+++ b/cli.go
@@ -177,7 +177,7 @@ func main() {
 		},
 		cli.BoolFlag{
 			Name:  "pem",
-			Usage: "Generate a .pem file by concatanating the .key and .crt files together.",
+			Usage: "Generate a .pem file by concatenating the .key and .crt files together.",
 		},
 	}
 
diff --git a/cli_handlers.go b/cli_handlers.go
index 16c9c0a1..768c62e7 100644
--- a/cli_handlers.go
+++ b/cli_handlers.go
@@ -30,7 +30,6 @@ func checkFolder(path string) error {
 }
 
 func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {
-
 	if c.GlobalIsSet("http-timeout") {
 		acme.HTTPClient = http.Client{Timeout: time.Duration(c.GlobalInt("http-timeout")) * time.Second}
 	}
@@ -60,7 +59,7 @@ func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {
 		log.Fatal("You have to pass an account (email address) to the program using --email or -m")
 	}
 
-	//TODO: move to account struct? Currently MUST pass email.
+	// TODO: move to account struct? Currently MUST pass email.
 	acc := NewAccount(c.GlobalString("email"), conf)
 
 	keyType, err := conf.KeyType()
@@ -80,35 +79,37 @@ func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {
 	}
 
 	if c.GlobalIsSet("webroot") {
-		provider, err := webroot.NewHTTPProvider(c.GlobalString("webroot"))
-		if err != nil {
-			log.Fatal(err)
+		provider, errO := webroot.NewHTTPProvider(c.GlobalString("webroot"))
+		if errO != nil {
+			log.Fatal(errO)
 		}
 
-		err = client.SetChallengeProvider(acme.HTTP01, provider)
-		if err != nil {
-			log.Fatal(err)
+		errO = client.SetChallengeProvider(acme.HTTP01, provider)
+		if errO != nil {
+			log.Fatal(errO)
 		}
 
 		// --webroot=foo indicates that the user specifically want to do a HTTP challenge
 		// infer that the user also wants to exclude all other challenges
 		client.ExcludeChallenges([]acme.Challenge{acme.DNS01, acme.TLSALPN01})
 	}
+
 	if c.GlobalIsSet("memcached-host") {
-		provider, err := memcached.NewMemcachedProvider(c.GlobalStringSlice("memcached-host"))
-		if err != nil {
-			log.Fatal(err)
+		provider, errO := memcached.NewMemcachedProvider(c.GlobalStringSlice("memcached-host"))
+		if errO != nil {
+			log.Fatal(errO)
 		}
 
-		err = client.SetChallengeProvider(acme.HTTP01, provider)
-		if err != nil {
-			log.Fatal(err)
+		errO = client.SetChallengeProvider(acme.HTTP01, provider)
+		if errO != nil {
+			log.Fatal(errO)
 		}
 
 		// --memcached-host=foo:11211 indicates that the user specifically want to do a HTTP challenge
 		// infer that the user also wants to exclude all other challenges
 		client.ExcludeChallenges([]acme.Challenge{acme.DNS01, acme.TLSALPN01})
 	}
+
 	if c.GlobalIsSet("http") {
 		if !strings.Contains(c.GlobalString("http"), ":") {
 			log.Fatalf("The --http switch only accepts interface:port or :port for its argument.")
@@ -124,18 +125,22 @@ func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) {
 		if !strings.Contains(c.GlobalString("tls"), ":") {
 			log.Fatalf("The --tls switch only accepts interface:port or :port for its argument.")
 		}
-		client.SetTLSAddress(c.GlobalString("tls"))
-	}
 
-	if c.GlobalIsSet("dns") {
-		provider, err := dns.NewDNSChallengeProviderByName(c.GlobalString("dns"))
+		err = client.SetTLSAddress(c.GlobalString("tls"))
 		if err != nil {
 			log.Fatal(err)
 		}
+	}
 
-		err = client.SetChallengeProvider(acme.DNS01, provider)
-		if err != nil {
-			log.Fatal(err)
+	if c.GlobalIsSet("dns") {
+		provider, errO := dns.NewDNSChallengeProviderByName(c.GlobalString("dns"))
+		if errO != nil {
+			log.Fatal(errO)
+		}
+
+		errO = client.SetChallengeProvider(acme.DNS01, provider)
+		if errO != nil {
+			log.Fatal(errO)
 		}
 
 		// --dns=foo indicates that the user specifically want to do a DNS challenge
@@ -311,7 +316,10 @@ func run(c *cli.Context) error {
 		}
 
 		acc.Registration = reg
-		acc.Save()
+		err = acc.Save()
+		if err != nil {
+			log.Fatal(err)
+		}
 
 		log.Print("!!!! HEADS UP !!!!")
 		log.Printf(`
@@ -421,8 +429,8 @@ func renew(c *cli.Context) error {
 	}
 
 	if c.IsSet("days") {
-		expTime, err := acme.GetPEMCertExpiration(certBytes)
-		if err != nil {
+		expTime, errE := acme.GetPEMCertExpiration(certBytes)
+		if errE != nil {
 			log.Printf("Could not get Certification expiration for domain %s", domain)
 		}
 
@@ -437,14 +445,14 @@ func renew(c *cli.Context) error {
 	}
 
 	var certRes acme.CertificateResource
-	if err := json.Unmarshal(metaBytes, &certRes); err != nil {
-		log.Fatalf("Error while marshalling the meta data for domain %s\n\t%v", domain, err)
+	if err = json.Unmarshal(metaBytes, &certRes); err != nil {
+		log.Fatalf("Error while marshaling the meta data for domain %s\n\t%v", domain, err)
 	}
 
 	if c.Bool("reuse-key") {
-		keyBytes, err := ioutil.ReadFile(privPath)
-		if err != nil {
-			log.Fatalf("Error while loading the private key for domain %s\n\t%v", domain, err)
+		keyBytes, errR := ioutil.ReadFile(privPath)
+		if errR != nil {
+			log.Fatalf("Error while loading the private key for domain %s\n\t%v", domain, errR)
 		}
 		certRes.PrivateKey = keyBytes
 	}
diff --git a/crypto.go b/crypto.go
index 0d42b173..27cbf494 100644
--- a/crypto.go
+++ b/crypto.go
@@ -13,7 +13,6 @@ import (
 )
 
 func generatePrivateKey(file string) (crypto.PrivateKey, error) {
-
 	privateKey, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
 	if err != nil {
 		return nil, err
@@ -30,9 +29,12 @@ func generatePrivateKey(file string) (crypto.PrivateKey, error) {
 	if err != nil {
 		return nil, err
 	}
+	defer certOut.Close()
 
-	pem.Encode(certOut, &pemKey)
-	certOut.Close()
+	err = pem.Encode(certOut, &pemKey)
+	if err != nil {
+		return nil, err
+	}
 
 	return privateKey, nil
 }
diff --git a/providers/dns/acmedns/acmedns.go b/providers/dns/acmedns/acmedns.go
index cce0d8d8..7e650755 100644
--- a/providers/dns/acmedns/acmedns.go
+++ b/providers/dns/acmedns/acmedns.go
@@ -101,7 +101,7 @@ func (e ErrCNAMERequired) Error() string {
 		e.Domain, e.Domain, e.FQDN, e.Target)
 }
 
-// Present creates a TXT record to fulfil the DNS-01 challenge. If there is an
+// Present creates a TXT record to fulfill the DNS-01 challenge. If there is an
 // existing account for the domain in the provider's storage then it will be
 // used to set the challenge response TXT record with the ACME-DNS server and
 // issuance will continue. If there is not an account for the given domain
diff --git a/providers/dns/alidns/alidns.go b/providers/dns/alidns/alidns.go
index 2d3c38b6..f46df26c 100644
--- a/providers/dns/alidns/alidns.go
+++ b/providers/dns/alidns/alidns.go
@@ -105,7 +105,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
 	return d.config.PropagationTimeout, d.config.PollingInterval
 }
 
-// Present creates a TXT record to fulfil the dns-01 challenge.
+// Present creates a TXT record to fulfill the dns-01 challenge.
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
 
diff --git a/providers/dns/azure/azure.go b/providers/dns/azure/azure.go
index 8012aa65..d04c3d66 100644
--- a/providers/dns/azure/azure.go
+++ b/providers/dns/azure/azure.go
@@ -99,7 +99,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
 	return d.config.PropagationTimeout, d.config.PollingInterval
 }
 
-// Present creates a TXT record to fulfil the dns-01 challenge
+// Present creates a TXT record to fulfill the dns-01 challenge
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	ctx := context.Background()
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
diff --git a/providers/dns/bluecat/bluecat.go b/providers/dns/bluecat/bluecat.go
index cc4369ba..30484bc2 100644
--- a/providers/dns/bluecat/bluecat.go
+++ b/providers/dns/bluecat/bluecat.go
@@ -353,7 +353,7 @@ func (d *DNSProvider) lookupViewID(viewName string) (uint, error) {
 
 	queryArgs := map[string]string{
 		"parentId": strconv.FormatUint(uint64(confID), 10),
-		"name":     d.config.DNSView,
+		"name":     viewName,
 		"type":     viewType,
 	}
 
diff --git a/providers/dns/cloudflare/cloudflare.go b/providers/dns/cloudflare/cloudflare.go
index 25d6fef3..de15650f 100644
--- a/providers/dns/cloudflare/cloudflare.go
+++ b/providers/dns/cloudflare/cloudflare.go
@@ -98,7 +98,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
 	return d.config.PropagationTimeout, d.config.PollingInterval
 }
 
-// Present creates a TXT record to fulfil the dns-01 challenge
+// Present creates a TXT record to fulfill the dns-01 challenge
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
 
diff --git a/providers/dns/cloudxns/cloudxns.go b/providers/dns/cloudxns/cloudxns.go
index 4b73564a..5efff966 100644
--- a/providers/dns/cloudxns/cloudxns.go
+++ b/providers/dns/cloudxns/cloudxns.go
@@ -79,7 +79,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 	return &DNSProvider{client: client}, nil
 }
 
-// Present creates a TXT record to fulfil the dns-01 challenge.
+// Present creates a TXT record to fulfill the dns-01 challenge.
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
 
diff --git a/providers/dns/dnsimple/dnsimple.go b/providers/dns/dnsimple/dnsimple.go
index c9c9ce3d..876117b4 100644
--- a/providers/dns/dnsimple/dnsimple.go
+++ b/providers/dns/dnsimple/dnsimple.go
@@ -82,7 +82,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 	return &DNSProvider{client: client}, nil
 }
 
-// Present creates a TXT record to fulfil the dns-01 challenge.
+// Present creates a TXT record to fulfill the dns-01 challenge.
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
 
@@ -182,7 +182,7 @@ func (d *DNSProvider) findTxtRecords(domain, fqdn string) ([]dnsimple.ZoneRecord
 
 	result, err := d.client.Zones.ListRecords(accountID, zoneName, &dnsimple.ZoneRecordListOptions{Name: recordName, Type: "TXT", ListOptions: dnsimple.ListOptions{}})
 	if err != nil {
-		return []dnsimple.ZoneRecord{}, fmt.Errorf("API call has failed: %v", err)
+		return nil, fmt.Errorf("API call has failed: %v", err)
 	}
 
 	return result.Data, nil
diff --git a/providers/dns/dnspod/dnspod.go b/providers/dns/dnspod/dnspod.go
index 35b74868..19af722b 100644
--- a/providers/dns/dnspod/dnspod.go
+++ b/providers/dns/dnspod/dnspod.go
@@ -84,7 +84,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 	return &DNSProvider{client: client}, nil
 }
 
-// Present creates a TXT record to fulfil the dns-01 challenge.
+// Present creates a TXT record to fulfill the dns-01 challenge.
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
 	zoneID, zoneName, err := d.getHostedZone(domain)
diff --git a/providers/dns/duckdns/duckdns.go b/providers/dns/duckdns/duckdns.go
index 7e2a55a4..6bbf7635 100644
--- a/providers/dns/duckdns/duckdns.go
+++ b/providers/dns/duckdns/duckdns.go
@@ -75,7 +75,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 	return &DNSProvider{config: config}, nil
 }
 
-// Present creates a TXT record to fulfil the dns-01 challenge.
+// Present creates a TXT record to fulfill the dns-01 challenge.
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	_, txtRecord, _ := acme.DNS01Record(domain, keyAuth)
 	return updateTxtRecord(domain, d.config.Token, txtRecord, false)
diff --git a/providers/dns/exec/exec.go b/providers/dns/exec/exec.go
index ea3a4398..b8ff0c7d 100644
--- a/providers/dns/exec/exec.go
+++ b/providers/dns/exec/exec.go
@@ -59,7 +59,7 @@ func NewDNSProviderProgram(program string) (*DNSProvider, error) {
 	return NewDNSProviderConfig(&Config{Program: program})
 }
 
-// Present creates a TXT record to fulfil the dns-01 challenge.
+// Present creates a TXT record to fulfill the dns-01 challenge.
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	var args []string
 	if d.config.Mode == "RAW" {
diff --git a/providers/dns/exoscale/exoscale.go b/providers/dns/exoscale/exoscale.go
index 72015d36..339c5ef6 100644
--- a/providers/dns/exoscale/exoscale.go
+++ b/providers/dns/exoscale/exoscale.go
@@ -93,7 +93,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 	return &DNSProvider{client: client, config: config}, nil
 }
 
-// Present creates a TXT record to fulfil the dns-01 challenge.
+// Present creates a TXT record to fulfill the dns-01 challenge.
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
 	zone, recordName, err := d.FindZoneAndRecordName(fqdn, domain)
diff --git a/providers/dns/fastdns/fastdns.go b/providers/dns/fastdns/fastdns.go
index fb8a9133..7fb6b3c0 100644
--- a/providers/dns/fastdns/fastdns.go
+++ b/providers/dns/fastdns/fastdns.go
@@ -99,10 +99,10 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	}
 
 	record := configdns.NewTxtRecord()
-	record.SetField("name", recordName)
-	record.SetField("ttl", d.config.TTL)
-	record.SetField("target", value)
-	record.SetField("active", true)
+	_ = record.SetField("name", recordName)
+	_ = record.SetField("ttl", d.config.TTL)
+	_ = record.SetField("target", value)
+	_ = record.SetField("active", true)
 
 	existingRecord := d.findExistingRecord(zone, recordName)
 
@@ -110,8 +110,10 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 		if reflect.DeepEqual(existingRecord.ToMap(), record.ToMap()) {
 			return nil
 		}
-		zone.RemoveRecord(existingRecord)
-		return d.createRecord(zone, record)
+		err = zone.RemoveRecord(existingRecord)
+		if err != nil {
+			return fmt.Errorf("fastdns: %v", err)
+		}
 	}
 
 	return d.createRecord(zone, record)
diff --git a/providers/dns/gandi/client.go b/providers/dns/gandi/client.go
index 3af340ec..0ed0bee4 100644
--- a/providers/dns/gandi/client.go
+++ b/providers/dns/gandi/client.go
@@ -82,8 +82,6 @@ type responseBool struct {
 	Value bool `xml:"params>param>value>boolean"`
 }
 
-// POSTing/Marshalling/Unmarshalling
-
 type rpcError struct {
 	faultCode   int
 	faultString string
diff --git a/providers/dns/gandi/gandi.go b/providers/dns/gandi/gandi.go
index 1ac1a6fa..f282d28b 100644
--- a/providers/dns/gandi/gandi.go
+++ b/providers/dns/gandi/gandi.go
@@ -230,9 +230,9 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
 }
 
 // rpcCall makes an XML-RPC call to Gandi's RPC endpoint by
-// marshalling the data given in the call argument to XML and sending
-// that via HTTP Post to Gandi. The response is then unmarshalled into
-// the resp argument.
+// marshaling the data given in the call argument to XML and sending
+// that via HTTP Post to Gandi.
+// The response is then unmarshalled into the resp argument.
 func (d *DNSProvider) rpcCall(call *methodCall, resp response) error {
 	// marshal
 	b, err := xml.MarshalIndent(call, "", "  ")
diff --git a/providers/dns/gcloud/googlecloud.go b/providers/dns/gcloud/googlecloud.go
index d8df7071..f799461b 100644
--- a/providers/dns/gcloud/googlecloud.go
+++ b/providers/dns/gcloud/googlecloud.go
@@ -122,7 +122,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 	return &DNSProvider{config: config, client: svc}, nil
 }
 
-// Present creates a TXT record to fulfil the dns-01 challenge.
+// Present creates a TXT record to fulfill the dns-01 challenge.
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
 
diff --git a/providers/dns/glesys/glesys.go b/providers/dns/glesys/glesys.go
index 78a0cff1..1354d191 100644
--- a/providers/dns/glesys/glesys.go
+++ b/providers/dns/glesys/glesys.go
@@ -160,8 +160,6 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
 	return d.config.PropagationTimeout, d.config.PollingInterval
 }
 
-// POSTing/Marshalling/Unmarshalling
-
 func (d *DNSProvider) sendRequest(method string, resource string, payload interface{}) (*responseStruct, error) {
 	url := fmt.Sprintf("%s/%s", defaultBaseURL, resource)
 
diff --git a/providers/dns/godaddy/godaddy.go b/providers/dns/godaddy/godaddy.go
index 7c5d48a6..804fd180 100644
--- a/providers/dns/godaddy/godaddy.go
+++ b/providers/dns/godaddy/godaddy.go
@@ -103,7 +103,7 @@ func (d *DNSProvider) extractRecordName(fqdn, domain string) string {
 	return name
 }
 
-// Present creates a TXT record to fulfil the dns-01 challenge
+// Present creates a TXT record to fulfill the dns-01 challenge
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
 	domainZone, err := d.getZone(fqdn)
diff --git a/providers/dns/hostingde/hostingde.go b/providers/dns/hostingde/hostingde.go
index 7f8280aa..7a64b1b8 100644
--- a/providers/dns/hostingde/hostingde.go
+++ b/providers/dns/hostingde/hostingde.go
@@ -89,7 +89,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
 	return d.config.PropagationTimeout, d.config.PollingInterval
 }
 
-// Present creates a TXT record to fulfil the dns-01 challenge
+// Present creates a TXT record to fulfill the dns-01 challenge
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
 
diff --git a/providers/dns/lightsail/lightsail.go b/providers/dns/lightsail/lightsail.go
index 4c116dbb..7328c076 100644
--- a/providers/dns/lightsail/lightsail.go
+++ b/providers/dns/lightsail/lightsail.go
@@ -108,7 +108,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
 
-	err := d.newTxtRecord(domain, fqdn, `"`+value+`"`)
+	err := d.newTxtRecord(fqdn, `"`+value+`"`)
 	if err != nil {
 		return fmt.Errorf("lightsail: %v", err)
 	}
@@ -141,7 +141,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
 	return d.config.PropagationTimeout, d.config.PollingInterval
 }
 
-func (d *DNSProvider) newTxtRecord(domain string, fqdn string, value string) error {
+func (d *DNSProvider) newTxtRecord(fqdn string, value string) error {
 	params := &lightsail.CreateDomainEntryInput{
 		DomainName: aws.String(d.config.DNSZone),
 		DomainEntry: &lightsail.DomainEntry{
diff --git a/providers/dns/linodev4/linodev4.go b/providers/dns/linodev4/linodev4.go
index 910f7540..2c75f176 100644
--- a/providers/dns/linodev4/linodev4.go
+++ b/providers/dns/linodev4/linodev4.go
@@ -83,12 +83,12 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 		},
 	}
 
-	linodeClient := linodego.NewClient(oauth2Client)
-	linodeClient.SetUserAgent(fmt.Sprintf("lego-dns linodego/%s", linodego.Version))
+	client := linodego.NewClient(oauth2Client)
+	client.SetUserAgent(fmt.Sprintf("lego-dns linodego/%s", linodego.Version))
 
 	return &DNSProvider{
 		config: config,
-		client: &linodeClient,
+		client: &client,
 	}, nil
 }
 
diff --git a/providers/dns/namecheap/client.go b/providers/dns/namecheap/client.go
index b816e1b4..9d7d8aa2 100644
--- a/providers/dns/namecheap/client.go
+++ b/providers/dns/namecheap/client.go
@@ -2,10 +2,10 @@ package namecheap
 
 import "encoding/xml"
 
-// host describes a DNS record returned by the Namecheap DNS gethosts API.
+// record describes a DNS record returned by the Namecheap DNS gethosts API.
 // Namecheap uses the term "host" to refer to all DNS records that include
 // a host field (A, AAAA, CNAME, NS, TXT, URL).
-type host struct {
+type record struct {
 	Type    string `xml:",attr"`
 	Name    string `xml:",attr"`
 	Address string `xml:",attr"`
@@ -32,7 +32,7 @@ type getHostsResponse struct {
 	XMLName xml.Name   `xml:"ApiResponse"`
 	Status  string     `xml:"Status,attr"`
 	Errors  []apierror `xml:"Errors>Error"`
-	Hosts   []host     `xml:"CommandResponse>DomainDNSGetHostsResult>host"`
+	Hosts   []record   `xml:"CommandResponse>DomainDNSGetHostsResult>host"`
 }
 
 type getTldsResponse struct {
diff --git a/providers/dns/namecheap/namecheap.go b/providers/dns/namecheap/namecheap.go
index c50cc628..2b800fd1 100644
--- a/providers/dns/namecheap/namecheap.go
+++ b/providers/dns/namecheap/namecheap.go
@@ -308,7 +308,7 @@ func (d *DNSProvider) getTLDs() (tlds map[string]string, err error) {
 }
 
 // getHosts reads the full list of DNS host records using the Namecheap API.
-func (d *DNSProvider) getHosts(ch *challenge) (hosts []host, err error) {
+func (d *DNSProvider) getHosts(ch *challenge) (hosts []record, err error) {
 	values := make(url.Values)
 	d.setGlobalParams(&values, "namecheap.domains.dns.getHosts")
 
@@ -348,7 +348,7 @@ func (d *DNSProvider) getHosts(ch *challenge) (hosts []host, err error) {
 }
 
 // setHosts writes the full list of DNS host records using the Namecheap API.
-func (d *DNSProvider) setHosts(ch *challenge, hosts []host) error {
+func (d *DNSProvider) setHosts(ch *challenge, hosts []record) error {
 	values := make(url.Values)
 	d.setGlobalParams(&values, "namecheap.domains.dns.setHosts")
 
@@ -395,8 +395,8 @@ func (d *DNSProvider) setHosts(ch *challenge, hosts []host) error {
 
 // addChallengeRecord adds a DNS challenge TXT record to a list of namecheap
 // host records.
-func (d *DNSProvider) addChallengeRecord(ch *challenge, hosts *[]host) {
-	host := host{
+func (d *DNSProvider) addChallengeRecord(ch *challenge, hosts *[]record) {
+	host := record{
 		Name:    ch.key,
 		Type:    "TXT",
 		Address: ch.keyValue,
@@ -418,7 +418,7 @@ func (d *DNSProvider) addChallengeRecord(ch *challenge, hosts *[]host) {
 
 // removeChallengeRecord removes a DNS challenge TXT record from a list of
 // namecheap host records. Return true if a record was removed.
-func (d *DNSProvider) removeChallengeRecord(ch *challenge, hosts *[]host) bool {
+func (d *DNSProvider) removeChallengeRecord(ch *challenge, hosts *[]record) bool {
 	// Find the challenge TXT record and remove it if found.
 	for i, h := range *hosts {
 		if h.Name == ch.key && h.Type == "TXT" {
diff --git a/providers/dns/namedotcom/namedotcom.go b/providers/dns/namedotcom/namedotcom.go
index 075f0183..20c8b274 100644
--- a/providers/dns/namedotcom/namedotcom.go
+++ b/providers/dns/namedotcom/namedotcom.go
@@ -97,7 +97,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 	return &DNSProvider{client: client, config: config}, nil
 }
 
-// Present creates a TXT record to fulfil the dns-01 challenge.
+// Present creates a TXT record to fulfill the dns-01 challenge.
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
 
diff --git a/providers/dns/ns1/ns1.go b/providers/dns/ns1/ns1.go
index 05397f27..dab0b857 100644
--- a/providers/dns/ns1/ns1.go
+++ b/providers/dns/ns1/ns1.go
@@ -81,7 +81,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 	return &DNSProvider{client: client, config: config}, nil
 }
 
-// Present creates a TXT record to fulfil the dns-01 challenge.
+// Present creates a TXT record to fulfill the dns-01 challenge.
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
 
diff --git a/providers/dns/ovh/ovh.go b/providers/dns/ovh/ovh.go
index c633ea7d..e5e09244 100644
--- a/providers/dns/ovh/ovh.go
+++ b/providers/dns/ovh/ovh.go
@@ -114,7 +114,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 	}, nil
 }
 
-// Present creates a TXT record to fulfil the dns-01 challenge.
+// Present creates a TXT record to fulfill the dns-01 challenge.
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
 
diff --git a/providers/dns/pdns/pdns.go b/providers/dns/pdns/pdns.go
index 44c4e433..8dc9c175 100644
--- a/providers/dns/pdns/pdns.go
+++ b/providers/dns/pdns/pdns.go
@@ -110,7 +110,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
 	return d.config.PropagationTimeout, d.config.PollingInterval
 }
 
-// Present creates a TXT record to fulfil the dns-01 challenge
+// Present creates a TXT record to fulfill the dns-01 challenge
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
 	zone, err := d.getHostedZone(fqdn)
diff --git a/providers/dns/rackspace/rackspace.go b/providers/dns/rackspace/rackspace.go
index 8e56f20a..2a35c907 100644
--- a/providers/dns/rackspace/rackspace.go
+++ b/providers/dns/rackspace/rackspace.go
@@ -146,7 +146,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 
 }
 
-// Present creates a TXT record to fulfil the dns-01 challenge
+// Present creates a TXT record to fulfill the dns-01 challenge
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
 	zoneID, err := d.getHostedZoneID(fqdn)
diff --git a/providers/dns/sakuracloud/sakuracloud.go b/providers/dns/sakuracloud/sakuracloud.go
index b746fd66..b8718d0e 100644
--- a/providers/dns/sakuracloud/sakuracloud.go
+++ b/providers/dns/sakuracloud/sakuracloud.go
@@ -85,7 +85,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 	return &DNSProvider{client: client}, nil
 }
 
-// Present creates a TXT record to fulfil the dns-01 challenge.
+// Present creates a TXT record to fulfill the dns-01 challenge.
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
 
diff --git a/providers/dns/vegadns/vegadns.go b/providers/dns/vegadns/vegadns.go
index 034d5ed4..468c2a07 100644
--- a/providers/dns/vegadns/vegadns.go
+++ b/providers/dns/vegadns/vegadns.go
@@ -87,7 +87,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
 	return d.config.PropagationTimeout, d.config.PollingInterval
 }
 
-// Present creates a TXT record to fulfil the dns-01 challenge
+// Present creates a TXT record to fulfill the dns-01 challenge
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
 
diff --git a/providers/dns/vultr/vultr.go b/providers/dns/vultr/vultr.go
index e6a2a336..80feb9f6 100644
--- a/providers/dns/vultr/vultr.go
+++ b/providers/dns/vultr/vultr.go
@@ -90,7 +90,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
 	return &DNSProvider{client: client, config: config}, nil
 }
 
-// Present creates a TXT record to fulfil the DNS-01 challenge.
+// Present creates a TXT record to fulfill the DNS-01 challenge.
 func (d *DNSProvider) Present(domain, token, keyAuth string) error {
 	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)
 
diff --git a/providers/http/webroot/webroot.go b/providers/http/webroot/webroot.go
index 86c63ef0..680aa8ad 100644
--- a/providers/http/webroot/webroot.go
+++ b/providers/http/webroot/webroot.go
@@ -18,14 +18,10 @@ type HTTPProvider struct {
 // NewHTTPProvider returns a HTTPProvider instance with a configured webroot path
 func NewHTTPProvider(path string) (*HTTPProvider, error) {
 	if _, err := os.Stat(path); os.IsNotExist(err) {
-		return nil, fmt.Errorf("Webroot path does not exist")
+		return nil, fmt.Errorf("webroot path does not exist")
 	}
 
-	c := &HTTPProvider{
-		path: path,
-	}
-
-	return c, nil
+	return &HTTPProvider{path: path}, nil
 }
 
 // Present makes the token available at `HTTP01ChallengePath(token)` by creating a file in the given webroot path


Test patch:
diff --git a/acme/client_test.go b/acme/client_test.go
index 4e39b003..b18047a0 100644
--- a/acme/client_test.go
+++ b/acme/client_test.go
@@ -35,7 +35,12 @@ func TestNewClient(t *testing.T) {
 			RevokeCertURL: "http://test",
 			KeyChangeURL:  "http://test",
 		})
-		w.Write(data)
+
+		_, err = w.Write(data)
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
 	}))
 
 	client, err := NewClient(ts.URL, user, keyType)
@@ -66,7 +71,12 @@ func TestClientOptPort(t *testing.T) {
 			RevokeCertURL: "http://test",
 			KeyChangeURL:  "http://test",
 		})
-		w.Write(data)
+
+		_, err = w.Write(data)
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
 	}))
 
 	optPort := "1234"
@@ -75,7 +85,8 @@ func TestClientOptPort(t *testing.T) {
 	client, err := NewClient(ts.URL, user, RSA2048)
 	require.NoError(t, err, "Could not create client")
 
-	client.SetHTTPAddress(net.JoinHostPort(optHost, optPort))
+	err = client.SetHTTPAddress(net.JoinHostPort(optHost, optPort))
+	require.NoError(t, err)
 
 	require.IsType(t, &httpChallenge{}, client.solvers[HTTP01])
 	httpSolver := client.solvers[HTTP01].(*httpChallenge)
@@ -88,7 +99,8 @@ func TestClientOptPort(t *testing.T) {
 
 	// test setting different host
 	optHost = "127.0.0.1"
-	client.SetHTTPAddress(net.JoinHostPort(optHost, optPort))
+	err = client.SetHTTPAddress(net.JoinHostPort(optHost, optPort))
+	require.NoError(t, err)
 
 	assert.Equal(t, optHost, httpSolver.provider.(*HTTPProviderServer).iface, "iface")
 }
@@ -109,11 +121,17 @@ func TestNotHoldingLockWhileMakingHTTPRequests(t *testing.T) {
 	ch := make(chan bool)
 	resultCh := make(chan bool)
 	go func() {
-		j.Nonce()
+		_, errN := j.Nonce()
+		if errN != nil {
+			t.Log(errN)
+		}
 		ch <- true
 	}()
 	go func() {
-		j.Nonce()
+		_, errN := j.Nonce()
+		if errN != nil {
+			t.Log(errN)
+		}
 		ch <- true
 	}()
 	go func() {
diff --git a/acme/dns_challenge_test.go b/acme/dns_challenge_test.go
index 5d80bac7..e7e44847 100644
--- a/acme/dns_challenge_test.go
+++ b/acme/dns_challenge_test.go
@@ -25,14 +25,19 @@ func TestDNSValidServerResponse(t *testing.T) {
 
 	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		w.Header().Add("Replay-Nonce", "12345")
-		w.Write([]byte("{\"type\":\"dns01\",\"status\":\"valid\",\"uri\":\"http://some.url\",\"token\":\"http8\"}"))
+
+		_, err = w.Write([]byte("{\"type\":\"dns01\",\"status\":\"valid\",\"uri\":\"http://some.url\",\"token\":\"http8\"}"))
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
 	}))
 
 	go func() {
 		time.Sleep(time.Second * 2)
 		f := bufio.NewWriter(os.Stdout)
 		defer f.Flush()
-		f.WriteString("\n")
+		_, _ = f.WriteString("\n")
 	}()
 
 	manualProvider, err := NewDNSProviderManual()
diff --git a/providers/dns/alidns/alidns_test.go b/providers/dns/alidns/alidns_test.go
index a081f90f..ee4f6233 100644
--- a/providers/dns/alidns/alidns_test.go
+++ b/providers/dns/alidns/alidns_test.go
@@ -4,7 +4,7 @@ import (
 	"os"
 	"testing"
 	"time"
-	// "time"
+
 	"github.com/stretchr/testify/assert"
 )
 
diff --git a/providers/dns/cloudflare/client_test.go b/providers/dns/cloudflare/client_test.go
index 1025f8da..46fb4cfa 100644
--- a/providers/dns/cloudflare/client_test.go
+++ b/providers/dns/cloudflare/client_test.go
@@ -47,7 +47,11 @@ func handlerMock(method string, response *APIResponse, data interface{}) http.Ha
 			return
 		}
 
-		rw.Write(content)
+		_, err = rw.Write(content)
+		if err != nil {
+			http.Error(rw, err.Error(), http.StatusInternalServerError)
+			return
+		}
 	})
 }
 
diff --git a/providers/dns/cloudxns/client_test.go b/providers/dns/cloudxns/client_test.go
index 5c41c6d7..da533fa4 100644
--- a/providers/dns/cloudxns/client_test.go
+++ b/providers/dns/cloudxns/client_test.go
@@ -42,7 +42,11 @@ func handlerMock(method string, response *apiResponse, data interface{}) http.Ha
 			return
 		}
 
-		rw.Write(content)
+		_, err = rw.Write(content)
+		if err != nil {
+			http.Error(rw, err.Error(), http.StatusInternalServerError)
+			return
+		}
 	})
 }
 
diff --git a/providers/dns/dyn/dyn_test.go b/providers/dns/dyn/dyn_test.go
index 0d28d5d0..5bbca10c 100644
--- a/providers/dns/dyn/dyn_test.go
+++ b/providers/dns/dyn/dyn_test.go
@@ -6,6 +6,7 @@ import (
 	"time"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 var (
@@ -32,7 +33,7 @@ func TestLiveDynPresent(t *testing.T) {
 	}
 
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.Present(dynDomain, "", "123d==")
 	assert.NoError(t, err)
diff --git a/providers/dns/exoscale/exoscale_test.go b/providers/dns/exoscale/exoscale_test.go
index 2c2f6748..0dacc653 100644
--- a/providers/dns/exoscale/exoscale_test.go
+++ b/providers/dns/exoscale/exoscale_test.go
@@ -6,6 +6,7 @@ import (
 	"time"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 var (
@@ -39,7 +40,7 @@ func TestNewDNSProviderValid(t *testing.T) {
 	config.APISecret = "123"
 
 	_, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestNewDNSProviderValidEnv(t *testing.T) {
@@ -48,7 +49,7 @@ func TestNewDNSProviderValidEnv(t *testing.T) {
 	os.Setenv("EXOSCALE_API_SECRET", "123")
 
 	_, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestNewDNSProviderMissingCredErr(t *testing.T) {
@@ -60,32 +61,56 @@ func TestNewDNSProviderMissingCredErr(t *testing.T) {
 	assert.EqualError(t, err, "exoscale: some credentials information are missing: EXOSCALE_API_KEY,EXOSCALE_API_SECRET")
 }
 
-func TestExtractRootRecordName(t *testing.T) {
+func TestDNSProvider_FindZoneAndRecordName(t *testing.T) {
 	config := NewDefaultConfig()
 	config.APIKey = "example@example.com"
 	config.APISecret = "123"
 
 	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
-	zone, recordName, err := provider.FindZoneAndRecordName("_acme-challenge.bar.com.", "bar.com")
-	assert.NoError(t, err)
-	assert.Equal(t, "bar.com", zone)
-	assert.Equal(t, "_acme-challenge", recordName)
-}
+	type expected struct {
+		zone       string
+		recordName string
+	}
 
-func TestExtractSubRecordName(t *testing.T) {
-	config := NewDefaultConfig()
-	config.APIKey = "example@example.com"
-	config.APISecret = "123"
+	testCases := []struct {
+		desc     string
+		fqdn     string
+		domain   string
+		expected expected
+	}{
+		{
+			desc:   "Extract root record name",
+			fqdn:   "_acme-challenge.bar.com.",
+			domain: "bar.com",
+			expected: expected{
+				zone:       "bar.com",
+				recordName: "_acme-challenge",
+			},
+		},
+		{
+			desc:   "Extract sub record name",
+			fqdn:   "_acme-challenge.foo.bar.com.",
+			domain: "foo.bar.com",
+			expected: expected{
+				zone:       "bar.com",
+				recordName: "_acme-challenge.foo",
+			},
+		},
+	}
 
-	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	for _, test := range testCases {
+		test := test
+		t.Run(test.desc, func(t *testing.T) {
+			t.Parallel()
 
-	zone, recordName, err := provider.FindZoneAndRecordName("_acme-challenge.foo.bar.com.", "foo.bar.com")
-	assert.NoError(t, err)
-	assert.Equal(t, "bar.com", zone)
-	assert.Equal(t, "_acme-challenge.foo", recordName)
+			zone, recordName, err := provider.FindZoneAndRecordName(test.fqdn, test.domain)
+			require.NoError(t, err)
+			assert.Equal(t, test.expected.zone, zone)
+			assert.Equal(t, test.expected.recordName, recordName)
+		})
+	}
 }
 
 func TestLiveExoscalePresent(t *testing.T) {
@@ -98,14 +123,14 @@ func TestLiveExoscalePresent(t *testing.T) {
 	config.APISecret = exoscaleAPISecret
 
 	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.Present(exoscaleDomain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	// Present Twice to handle create / update
 	err = provider.Present(exoscaleDomain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestLiveExoscaleCleanUp(t *testing.T) {
@@ -120,8 +145,8 @@ func TestLiveExoscaleCleanUp(t *testing.T) {
 	config.APISecret = exoscaleAPISecret
 
 	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.CleanUp(exoscaleDomain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
diff --git a/providers/dns/fastdns/fastdns_test.go b/providers/dns/fastdns/fastdns_test.go
index 859af226..abd21236 100644
--- a/providers/dns/fastdns/fastdns_test.go
+++ b/providers/dns/fastdns/fastdns_test.go
@@ -6,6 +6,7 @@ import (
 	"time"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 var (
@@ -50,7 +51,7 @@ func TestNewDNSProviderValid(t *testing.T) {
 	config.AccessToken = "someaccesstoken"
 
 	_, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestNewDNSProviderValidEnv(t *testing.T) {
@@ -61,7 +62,7 @@ func TestNewDNSProviderValidEnv(t *testing.T) {
 	os.Setenv("AKAMAI_ACCESS_TOKEN", "someaccesstoken")
 
 	_, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestNewDNSProviderMissingCredErr(t *testing.T) {
@@ -87,17 +88,17 @@ func TestLiveFastdnsPresent(t *testing.T) {
 	config.AccessToken = accessToken
 
 	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.Present(testDomain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	// Present Twice to handle create / update
 	err = provider.Present(testDomain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
-func TestExtractRootRecordName(t *testing.T) {
+func TestDNSProvider_findZoneAndRecordName(t *testing.T) {
 	config := NewDefaultConfig()
 	config.Host = "somehost"
 	config.ClientToken = "someclienttoken"
@@ -105,28 +106,50 @@ func TestExtractRootRecordName(t *testing.T) {
 	config.AccessToken = "someaccesstoken"
 
 	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
-	zone, recordName, err := provider.findZoneAndRecordName("_acme-challenge.bar.com.", "bar.com")
-	assert.NoError(t, err)
-	assert.Equal(t, "bar.com", zone)
-	assert.Equal(t, "_acme-challenge", recordName)
-}
+	type expected struct {
+		zone       string
+		recordName string
+	}
 
-func TestExtractSubRecordName(t *testing.T) {
-	config := NewDefaultConfig()
-	config.Host = "somehost"
-	config.ClientToken = "someclienttoken"
-	config.ClientSecret = "someclientsecret"
-	config.AccessToken = "someaccesstoken"
+	testCases := []struct {
+		desc     string
+		fqdn     string
+		domain   string
+		expected expected
+	}{
+		{
+			desc:   "Extract root record name",
+			fqdn:   "_acme-challenge.bar.com.",
+			domain: "bar.com",
+			expected: expected{
+				zone:       "bar.com",
+				recordName: "_acme-challenge",
+			},
+		},
+		{
+			desc:   "Extract sub record name",
+			fqdn:   "_acme-challenge.foo.bar.com.",
+			domain: "foo.bar.com",
+			expected: expected{
+				zone:       "bar.com",
+				recordName: "_acme-challenge.foo",
+			},
+		},
+	}
 
-	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	for _, test := range testCases {
+		test := test
+		t.Run(test.desc, func(t *testing.T) {
+			t.Parallel()
 
-	zone, recordName, err := provider.findZoneAndRecordName("_acme-challenge.foo.bar.com.", "foo.bar.com")
-	assert.NoError(t, err)
-	assert.Equal(t, "bar.com", zone)
-	assert.Equal(t, "_acme-challenge.foo", recordName)
+			zone, recordName, err := provider.findZoneAndRecordName(test.fqdn, test.domain)
+			require.NoError(t, err)
+			assert.Equal(t, test.expected.zone, zone)
+			assert.Equal(t, test.expected.recordName, recordName)
+		})
+	}
 }
 
 func TestLiveFastdnsCleanUp(t *testing.T) {
@@ -143,8 +166,8 @@ func TestLiveFastdnsCleanUp(t *testing.T) {
 	config.AccessToken = accessToken
 
 	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.CleanUp(testDomain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
diff --git a/providers/dns/gandi/gandi_test.go b/providers/dns/gandi/gandi_test.go
index 1d75a01d..ea416232 100644
--- a/providers/dns/gandi/gandi_test.go
+++ b/providers/dns/gandi/gandi_test.go
@@ -24,15 +24,15 @@ func TestDNSProvider(t *testing.T) {
 	fakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		require.Equal(t, "text/xml", r.Header.Get("Content-Type"), "invalid content type")
 
-		req, err := ioutil.ReadAll(r.Body)
-		require.NoError(t, err)
+		req, errS := ioutil.ReadAll(r.Body)
+		require.NoError(t, errS)
 
 		req = regexpDate.ReplaceAllLiteral(req, []byte(`[ACME Challenge 01 Jan 16 00:00 +0000]`))
 		resp, ok := serverResponses[string(req)]
 		require.True(t, ok, "Server response for request not found")
 
-		_, err = io.Copy(w, strings.NewReader(resp))
-		require.NoError(t, err)
+		_, errS = io.Copy(w, strings.NewReader(resp))
+		require.NoError(t, errS)
 	}))
 	defer fakeServer.Close()
 
diff --git a/providers/dns/gandiv5/gandiv5_test.go b/providers/dns/gandiv5/gandiv5_test.go
index 720b2a44..e4e0cbef 100644
--- a/providers/dns/gandiv5/gandiv5_test.go
+++ b/providers/dns/gandiv5/gandiv5_test.go
@@ -24,16 +24,16 @@ func TestDNSProvider(t *testing.T) {
 	fakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		require.Equal(t, "application/json", r.Header.Get("Content-Type"), "invalid content type")
 
-		req, err := ioutil.ReadAll(r.Body)
-		require.NoError(t, err)
+		req, errS := ioutil.ReadAll(r.Body)
+		require.NoError(t, errS)
 
 		req = regexpToken.ReplaceAllLiteral(req, []byte(`"rrset_values":["TOKEN"]`))
 
 		resp, ok := serverResponses[string(req)]
 		require.True(t, ok, "Server response for request not found")
 
-		_, err = io.Copy(w, strings.NewReader(resp))
-		require.NoError(t, err)
+		_, errS = io.Copy(w, strings.NewReader(resp))
+		require.NoError(t, errS)
 	}))
 	defer fakeServer.Close()
 
diff --git a/providers/dns/gcloud/googlecloud_test.go b/providers/dns/gcloud/googlecloud_test.go
index 9bc9330c..ec94a79d 100644
--- a/providers/dns/gcloud/googlecloud_test.go
+++ b/providers/dns/gcloud/googlecloud_test.go
@@ -6,6 +6,7 @@ import (
 	"time"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 	"golang.org/x/net/context"
 	"golang.org/x/oauth2/google"
 	"google.golang.org/api/dns/v1"
@@ -39,7 +40,7 @@ func TestNewDNSProviderValid(t *testing.T) {
 	os.Setenv("GCE_PROJECT", "")
 
 	_, err := NewDNSProviderCredentials("my-project")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestNewDNSProviderValidEnv(t *testing.T) {
@@ -51,7 +52,7 @@ func TestNewDNSProviderValidEnv(t *testing.T) {
 	os.Setenv("GCE_PROJECT", "my-project")
 
 	_, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestNewDNSProviderMissingCredErr(t *testing.T) {
@@ -68,10 +69,10 @@ func TestLiveGoogleCloudPresent(t *testing.T) {
 	}
 
 	provider, err := NewDNSProviderCredentials(gcloudProject)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.Present(gcloudDomain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestLiveGoogleCloudPresentMultiple(t *testing.T) {
@@ -80,13 +81,13 @@ func TestLiveGoogleCloudPresentMultiple(t *testing.T) {
 	}
 
 	provider, err := NewDNSProviderCredentials(gcloudProject)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	// Check that we're able to create multiple entries
 	err = provider.Present(gcloudDomain, "1", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	err = provider.Present(gcloudDomain, "2", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestLiveGoogleCloudCleanUp(t *testing.T) {
@@ -97,8 +98,8 @@ func TestLiveGoogleCloudCleanUp(t *testing.T) {
 	time.Sleep(time.Second * 1)
 
 	provider, err := NewDNSProviderCredentials(gcloudProject)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.CleanUp(gcloudDomain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
diff --git a/providers/dns/glesys/glesys_test.go b/providers/dns/glesys/glesys_test.go
index c10ba3a7..ccb5d5e8 100644
--- a/providers/dns/glesys/glesys_test.go
+++ b/providers/dns/glesys/glesys_test.go
@@ -5,6 +5,7 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 var (
@@ -41,10 +42,10 @@ func TestDNSProvider_Present(t *testing.T) {
 	}
 
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.Present(glesysDomain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestDNSProvider_CleanUp(t *testing.T) {
@@ -53,8 +54,8 @@ func TestDNSProvider_CleanUp(t *testing.T) {
 	}
 
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.CleanUp(glesysDomain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
diff --git a/providers/dns/lightsail/lightsail_integration_test.go b/providers/dns/lightsail/lightsail_integration_test.go
index a26d7868..b81e1a55 100644
--- a/providers/dns/lightsail/lightsail_integration_test.go
+++ b/providers/dns/lightsail/lightsail_integration_test.go
@@ -20,41 +20,42 @@ func TestLightsailTTL(t *testing.T) {
 	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	err = provider.Present(m["lightsailDomain"], "foo", "bar")
+	lightsailDomain := m["lightsailDomain"]
+
+	err = provider.Present(lightsailDomain, "foo", "bar")
 	require.NoError(t, err)
 
 	// we need a separate Lightshail client here as the one in the DNS provider is
 	// unexported.
-	fqdn := "_acme-challenge." + m["lightsailDomain"]
+	fqdn := "_acme-challenge." + lightsailDomain
 	sess, err := session.NewSession()
 	require.NoError(t, err)
 
 	svc := lightsail.New(sess)
-	if err != nil {
-		provider.CleanUp(m["lightsailDomain"], "foo", "bar")
-		t.Fatal(err)
-	}
+	require.NoError(t, err)
+
+	defer func() {
+		errC := provider.CleanUp(lightsailDomain, "foo", "bar")
+		if errC != nil {
+			t.Log(errC)
+		}
+	}()
 
 	params := &lightsail.GetDomainInput{
-		DomainName: aws.String(m["lightsailDomain"]),
+		DomainName: aws.String(lightsailDomain),
 	}
 
 	resp, err := svc.GetDomain(params)
-	if err != nil {
-		provider.CleanUp(m["lightsailDomain"], "foo", "bar")
-		t.Fatal(err)
-	}
+	require.NoError(t, err)
 
 	entries := resp.Domain.DomainEntries
 	for _, entry := range entries {
 		if *entry.Type == "TXT" && *entry.Name == fqdn {
-			provider.CleanUp(m["lightsailDomain"], "foo", "bar")
 			return
 		}
 	}
 
-	provider.CleanUp(m["lightsailDomain"], "foo", "bar")
-	t.Fatalf("Could not find a TXT record for _acme-challenge.%s", m["lightsailDomain"])
+	t.Fatalf("Could not find a TXT record for _acme-challenge.%s", lightsailDomain)
 }
 
 func testGetAndPreCheck() (map[string]string, error) {
diff --git a/providers/dns/lightsail/mock_server_test.go b/providers/dns/lightsail/mock_server_test.go
index bba3b37a..a90d2f71 100644
--- a/providers/dns/lightsail/mock_server_test.go
+++ b/providers/dns/lightsail/mock_server_test.go
@@ -27,7 +27,11 @@ func newMockServer(t *testing.T, responses map[string]MockResponse) *httptest.Se
 
 		w.Header().Set("Content-Type", "application/xml")
 		w.WriteHeader(resp.StatusCode)
-		w.Write([]byte(resp.Body))
+		_, err := w.Write([]byte(resp.Body))
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
 	}))
 
 	time.Sleep(100 * time.Millisecond)
diff --git a/providers/dns/linode/linode_test.go b/providers/dns/linode/linode_test.go
index 78331f35..702da864 100644
--- a/providers/dns/linode/linode_test.go
+++ b/providers/dns/linode/linode_test.go
@@ -48,7 +48,7 @@ func newMockServer(t *testing.T, responses MockResponseMap) *httptest.Server {
 		action := r.URL.Query().Get("api_action")
 		resp, ok := responses[action]
 		if !ok {
-			require.FailNowf(t, "Unsupported mock action: %s", action)
+			require.FailNowf(t, "Unsupported mock action: %q", action)
 		}
 
 		// Build the response that the server will return.
@@ -66,7 +66,11 @@ func newMockServer(t *testing.T, responses MockResponseMap) *httptest.Server {
 		// Send the response.
 		w.Header().Set("Content-Type", "application/json")
 		w.WriteHeader(http.StatusOK)
-		w.Write(rawResponse)
+		_, err = w.Write(rawResponse)
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
 	}))
 
 	time.Sleep(100 * time.Millisecond)
@@ -78,7 +82,7 @@ func TestNewDNSProviderWithEnv(t *testing.T) {
 	os.Setenv("LINODE_API_KEY", "testing")
 
 	_, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestNewDNSProviderWithoutEnv(t *testing.T) {
@@ -89,15 +93,15 @@ func TestNewDNSProviderWithoutEnv(t *testing.T) {
 	assert.EqualError(t, err, "linode: some credentials information are missing: LINODE_API_KEY")
 }
 
-func TestNewDNSProviderCredentialsWithKey(t *testing.T) {
+func TestNewDNSProviderWithKey(t *testing.T) {
 	config := NewDefaultConfig()
 	config.APIKey = "testing"
 
 	_, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
-func TestNewDNSProviderCredentialsWithoutKey(t *testing.T) {
+func TestNewDNSProviderWithoutKey(t *testing.T) {
 	config := NewDefaultConfig()
 
 	_, err := NewDNSProviderConfig(config)
@@ -109,105 +113,94 @@ func TestDNSProvider_Present(t *testing.T) {
 	os.Setenv("LINODE_API_KEY", "testing")
 
 	p, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	domain := "example.com"
 	keyAuth := "dGVzdGluZw=="
-	mockResponses := MockResponseMap{
-		"domain.list": MockResponse{
-			Response: []dns.Domain{
-				{
-					Domain:   domain,
-					DomainID: 1234,
+
+	testCases := []struct {
+		desc          string
+		mockResponses MockResponseMap
+		expectedError string
+	}{
+		{
+			desc: "success",
+			mockResponses: MockResponseMap{
+				"domain.list": MockResponse{
+					Response: []dns.Domain{
+						{
+							Domain:   domain,
+							DomainID: 1234,
+						},
+					},
+				},
+				"domain.resource.create": MockResponse{
+					Response: dns.ResourceResponse{
+						ResourceID: 1234,
+					},
 				},
 			},
 		},
-		"domain.resource.create": MockResponse{
-			Response: dns.ResourceResponse{
-				ResourceID: 1234,
+		{
+			desc: "NoDomain",
+			mockResponses: MockResponseMap{
+				"domain.list": MockResponse{
+					Response: []dns.Domain{{
+						Domain:   "foobar.com",
+						DomainID: 1234,
+					}},
+				},
 			},
+			expectedError: "dns: requested domain not found",
 		},
-	}
-
-	mockSrv := newMockServer(t, mockResponses)
-	defer mockSrv.Close()
-
-	p.client.ToLinode().SetEndpoint(mockSrv.URL)
-
-	err = p.Present(domain, "", keyAuth)
-	assert.NoError(t, err)
-}
-
-func TestDNSProvider_PresentNoDomain(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("LINODE_API_KEY", "testing")
-
-	p, err := NewDNSProvider()
-	assert.NoError(t, err)
-
-	domain := "example.com"
-	keyAuth := "dGVzdGluZw=="
-	mockResponses := MockResponseMap{
-		"domain.list": MockResponse{
-			Response: []dns.Domain{
-				{
-					Domain:   "foobar.com",
-					DomainID: 1234,
+		{
+			desc: "CreateFailed",
+			mockResponses: MockResponseMap{
+				"domain.list": MockResponse{
+					Response: []dns.Domain{
+						{
+							Domain:   domain,
+							DomainID: 1234,
+						},
+					},
+				},
+				"domain.resource.create": MockResponse{
+					Response: nil,
+					Errors: []linode.ResponseError{
+						{
+							Code:    1234,
+							Message: "Failed to create domain resource",
+						},
+					},
 				},
 			},
+			expectedError: "Failed to create domain resource",
 		},
 	}
 
-	mockSrv := newMockServer(t, mockResponses)
-	defer mockSrv.Close()
-
-	p.client.ToLinode().SetEndpoint(mockSrv.URL)
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
 
-	err = p.Present(domain, "", keyAuth)
-	assert.EqualError(t, err, "dns: requested domain not found")
-}
+			mockSrv := newMockServer(t, test.mockResponses)
+			defer mockSrv.Close()
 
-func TestDNSProvider_PresentCreateFailed(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("LINODE_API_KEY", "testing")
+			p.client.ToLinode().SetEndpoint(mockSrv.URL)
 
-	p, err := NewDNSProvider()
-	assert.NoError(t, err)
-
-	domain := "example.com"
-	keyAuth := "dGVzdGluZw=="
-	mockResponses := MockResponseMap{
-		"domain.list": MockResponse{
-			Response: []dns.Domain{
-				{
-					Domain:   domain,
-					DomainID: 1234,
-				},
-			},
-		},
-		"domain.resource.create": MockResponse{
-			Response: nil,
-			Errors: []linode.ResponseError{
-				{
-					Code:    1234,
-					Message: "Failed to create domain resource",
-				},
-			},
-		},
+			err = p.Present(domain, "", keyAuth)
+			if len(test.expectedError) == 0 {
+				assert.NoError(t, err)
+			} else {
+				assert.EqualError(t, err, test.expectedError)
+			}
+		})
 	}
-	mockSrv := newMockServer(t, mockResponses)
-	defer mockSrv.Close()
-
-	p.client.ToLinode().SetEndpoint(mockSrv.URL)
-
-	err = p.Present(domain, "", keyAuth)
-	assert.EqualError(t, err, "Failed to create domain resource")
 }
 
 func TestDNSProvider_PresentLive(t *testing.T) {
 	if !isTestLive {
 		t.Skip("Skipping live test")
 	}
+	// TODO implement this test
 }
 
 func TestDNSProvider_CleanUp(t *testing.T) {
@@ -215,120 +208,108 @@ func TestDNSProvider_CleanUp(t *testing.T) {
 	os.Setenv("LINODE_API_KEY", "testing")
 
 	p, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	domain := "example.com"
 	keyAuth := "dGVzdGluZw=="
-	mockResponses := MockResponseMap{
-		"domain.list": MockResponse{
-			Response: []dns.Domain{
-				{
-					Domain:   domain,
-					DomainID: 1234,
+
+	testCases := []struct {
+		desc          string
+		mockResponses MockResponseMap
+		expectedError string
+	}{
+		{
+			desc: "success",
+			mockResponses: MockResponseMap{
+				"domain.list": MockResponse{
+					Response: []dns.Domain{
+						{
+							Domain:   domain,
+							DomainID: 1234,
+						},
+					},
 				},
-			},
-		},
-		"domain.resource.list": MockResponse{
-			Response: []dns.Resource{
-				{
-					DomainID:   1234,
-					Name:       "_acme-challenge",
-					ResourceID: 1234,
-					Target:     "ElbOJKOkFWiZLQeoxf-wb3IpOsQCdvoM0y_wn0TEkxM",
-					Type:       "TXT",
+				"domain.resource.list": MockResponse{
+					Response: []dns.Resource{
+						{
+							DomainID:   1234,
+							Name:       "_acme-challenge",
+							ResourceID: 1234,
+							Target:     "ElbOJKOkFWiZLQeoxf-wb3IpOsQCdvoM0y_wn0TEkxM",
+							Type:       "TXT",
+						},
+					},
 				},
-			},
-		},
-		"domain.resource.delete": MockResponse{
-			Response: dns.ResourceResponse{
-				ResourceID: 1234,
-			},
-		},
-	}
-
-	mockSrv := newMockServer(t, mockResponses)
-	defer mockSrv.Close()
-
-	p.client.ToLinode().SetEndpoint(mockSrv.URL)
-
-	err = p.CleanUp(domain, "", keyAuth)
-	assert.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUpNoDomain(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("LINODE_API_KEY", "testing")
-
-	p, err := NewDNSProvider()
-	assert.NoError(t, err)
-
-	domain := "example.com"
-	keyAuth := "dGVzdGluZw=="
-	mockResponses := MockResponseMap{
-		"domain.list": MockResponse{
-			Response: []dns.Domain{
-				{
-					Domain:   "foobar.com",
-					DomainID: 1234,
+				"domain.resource.delete": MockResponse{
+					Response: dns.ResourceResponse{
+						ResourceID: 1234,
+					},
 				},
 			},
 		},
-	}
-
-	mockSrv := newMockServer(t, mockResponses)
-	defer mockSrv.Close()
-
-	p.client.ToLinode().SetEndpoint(mockSrv.URL)
-
-	err = p.CleanUp(domain, "", keyAuth)
-	assert.EqualError(t, err, "dns: requested domain not found")
-}
-
-func TestDNSProvider_CleanUpDeleteFailed(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("LINODE_API_KEY", "testing")
-
-	p, err := NewDNSProvider()
-	assert.NoError(t, err)
-
-	domain := "example.com"
-	keyAuth := "dGVzdGluZw=="
-	mockResponses := MockResponseMap{
-		"domain.list": MockResponse{
-			Response: []dns.Domain{
-				{
-					Domain:   domain,
-					DomainID: 1234,
+		{
+			desc: "NoDomain",
+			mockResponses: MockResponseMap{
+				"domain.list": MockResponse{
+					Response: []dns.Domain{
+						{
+							Domain:   "foobar.com",
+							DomainID: 1234,
+						},
+					},
 				},
 			},
+			expectedError: "dns: requested domain not found",
 		},
-		"domain.resource.list": MockResponse{
-			Response: []dns.Resource{
-				{
-					DomainID:   1234,
-					Name:       "_acme-challenge",
-					ResourceID: 1234,
-					Target:     "ElbOJKOkFWiZLQeoxf-wb3IpOsQCdvoM0y_wn0TEkxM",
-					Type:       "TXT",
+		{
+			desc: "DeleteFailed",
+			mockResponses: MockResponseMap{
+				"domain.list": MockResponse{
+					Response: []dns.Domain{
+						{
+							Domain:   domain,
+							DomainID: 1234,
+						},
+					},
 				},
-			},
-		},
-		"domain.resource.delete": MockResponse{
-			Response: nil,
-			Errors: []linode.ResponseError{
-				{
-					Code:    1234,
-					Message: "Failed to delete domain resource",
+				"domain.resource.list": MockResponse{
+					Response: []dns.Resource{
+						{
+							DomainID:   1234,
+							Name:       "_acme-challenge",
+							ResourceID: 1234,
+							Target:     "ElbOJKOkFWiZLQeoxf-wb3IpOsQCdvoM0y_wn0TEkxM",
+							Type:       "TXT",
+						},
+					},
+				},
+				"domain.resource.delete": MockResponse{
+					Response: nil,
+					Errors: []linode.ResponseError{
+						{
+							Code:    1234,
+							Message: "Failed to delete domain resource",
+						},
+					},
 				},
 			},
+			expectedError: "Failed to delete domain resource",
 		},
 	}
 
-	mockSrv := newMockServer(t, mockResponses)
-	defer mockSrv.Close()
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			mockSrv := newMockServer(t, test.mockResponses)
+			defer mockSrv.Close()
 
-	p.client.ToLinode().SetEndpoint(mockSrv.URL)
+			p.client.ToLinode().SetEndpoint(mockSrv.URL)
 
-	err = p.CleanUp(domain, "", keyAuth)
-	assert.EqualError(t, err, "Failed to delete domain resource")
+			err = p.CleanUp(domain, "", keyAuth)
+			if len(test.expectedError) == 0 {
+				assert.NoError(t, err)
+			} else {
+				assert.EqualError(t, err, test.expectedError)
+			}
+		})
+	}
 }
diff --git a/providers/dns/linodev4/linodev4_test.go b/providers/dns/linodev4/linodev4_test.go
index 1682bed3..4f0bd16e 100644
--- a/providers/dns/linodev4/linodev4_test.go
+++ b/providers/dns/linodev4/linodev4_test.go
@@ -58,7 +58,11 @@ func newMockServer(t *testing.T, responses MockResponseMap) *httptest.Server {
 		} else {
 			w.WriteHeader(http.StatusOK)
 		}
-		w.Write(rawResponse)
+
+		_, err = w.Write(rawResponse)
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+		}
 	}))
 
 	time.Sleep(100 * time.Millisecond)
@@ -81,7 +85,7 @@ func TestNewDNSProviderWithoutEnv(t *testing.T) {
 	assert.EqualError(t, err, "linodev4: some credentials information are missing: LINODE_TOKEN")
 }
 
-func TestNewDNSProviderCredentialsWithKey(t *testing.T) {
+func TestNewDNSProviderWithKey(t *testing.T) {
 	config := NewDefaultConfig()
 	config.Token = "testing"
 
@@ -89,7 +93,7 @@ func TestNewDNSProviderCredentialsWithKey(t *testing.T) {
 	assert.NoError(t, err)
 }
 
-func TestNewDNSProviderCredentialsWithoutKey(t *testing.T) {
+func TestNewDNSProviderWithoutKey(t *testing.T) {
 	config := NewDefaultConfig()
 	config.Token = ""
 
@@ -102,104 +106,96 @@ func TestDNSProvider_Present(t *testing.T) {
 	os.Setenv("LINODE_TOKEN", "testing")
 
 	p, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
+	require.NotNil(t, p)
 
 	domain := "example.com"
 	keyAuth := "dGVzdGluZw=="
 
-	mockResponses := MockResponseMap{
-		"GET:/domains": linodego.DomainsPagedResponse{
-			PageOptions: &linodego.PageOptions{
-				Pages:   1,
-				Results: 1,
-				Page:    1,
+	testCases := []struct {
+		desc          string
+		mockResponses MockResponseMap
+		expectedError string
+	}{
+		{
+			desc: "Success",
+			mockResponses: MockResponseMap{
+				"GET:/domains": linodego.DomainsPagedResponse{
+					PageOptions: &linodego.PageOptions{
+						Pages:   1,
+						Results: 1,
+						Page:    1,
+					},
+					Data: []linodego.Domain{{
+						Domain: domain,
+						ID:     1234,
+					}},
+				},
+				"POST:/domains/1234/records": linodego.DomainRecord{
+					ID: 1234,
+				},
 			},
-			Data: []linodego.Domain{{
-				Domain: domain,
-				ID:     1234,
-			}},
 		},
-		"POST:/domains/1234/records": linodego.DomainRecord{
-			ID: 1234,
+		{
+			desc: "NoDomain",
+			mockResponses: MockResponseMap{
+				"GET:/domains": linodego.APIError{
+					Errors: []linodego.APIErrorReason{{
+						Reason: "Not found",
+					}},
+				},
+			},
+			expectedError: "[404] Not found",
 		},
-	}
-
-	mockSrv := newMockServer(t, mockResponses)
-	defer mockSrv.Close()
-
-	p.client.SetBaseURL(mockSrv.URL)
-
-	err = p.Present(domain, "", keyAuth)
-	assert.NoError(t, err)
-}
-
-func TestDNSProvider_PresentNoDomain(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("LINODE_TOKEN", "testing")
-
-	p, err := NewDNSProvider()
-	assert.NoError(t, err)
-
-	domain := "example.com"
-	keyAuth := "dGVzdGluZw=="
-	mockResponses := MockResponseMap{
-		"GET:/domains": linodego.APIError{
-			Errors: []linodego.APIErrorReason{{
-				Reason: "Not found",
-			}},
+		{
+			desc: "CreateFailed",
+			mockResponses: MockResponseMap{
+				"GET:/domains": &linodego.DomainsPagedResponse{
+					PageOptions: &linodego.PageOptions{
+						Pages:   1,
+						Results: 1,
+						Page:    1,
+					},
+					Data: []linodego.Domain{{
+						Domain: "foobar.com",
+						ID:     1234,
+					}},
+				},
+				"POST:/domains/1234/records": linodego.APIError{
+					Errors: []linodego.APIErrorReason{{
+						Reason: "Failed to create domain resource",
+						Field:  "somefield",
+					}},
+				},
+			},
+			expectedError: "[400] [somefield] Failed to create domain resource",
 		},
 	}
 
-	mockSrv := newMockServer(t, mockResponses)
-	defer mockSrv.Close()
-
-	p.client.SetBaseURL(mockSrv.URL)
-
-	err = p.Present(domain, "", keyAuth)
-	assert.EqualError(t, err, "[404] Not found")
-}
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
 
-func TestDNSProvider_PresentCreateFailed(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("LINODE_TOKEN", "testing")
+			mockSrv := newMockServer(t, test.mockResponses)
+			defer mockSrv.Close()
 
-	p, err := NewDNSProvider()
-	assert.NoError(t, err)
+			assert.NotNil(t, p.client)
+			p.client.SetBaseURL(mockSrv.URL)
 
-	domain := "example.com"
-	keyAuth := "dGVzdGluZw=="
-	mockResponses := MockResponseMap{
-		"GET:/domains": &linodego.DomainsPagedResponse{
-			PageOptions: &linodego.PageOptions{
-				Pages:   1,
-				Results: 1,
-				Page:    1,
-			},
-			Data: []linodego.Domain{{
-				Domain: "foobar.com",
-				ID:     1234,
-			}},
-		},
-		"POST:/domains/1234/records": linodego.APIError{
-			Errors: []linodego.APIErrorReason{{
-				Reason: "Failed to create domain resource",
-				Field:  "somefield",
-			}},
-		},
+			err = p.Present(domain, "", keyAuth)
+			if len(test.expectedError) == 0 {
+				assert.NoError(t, err)
+			} else {
+				assert.EqualError(t, err, test.expectedError)
+			}
+		})
 	}
-	mockSrv := newMockServer(t, mockResponses)
-	defer mockSrv.Close()
-
-	p.client.SetBaseURL(mockSrv.URL)
-
-	err = p.Present(domain, "", keyAuth)
-	assert.EqualError(t, err, "[400] [somefield] Failed to create domain resource")
 }
 
 func TestDNSProvider_PresentLive(t *testing.T) {
 	if !isTestLive {
 		t.Skip("Skipping live test")
 	}
+	// TODO implement this test
 }
 
 func TestDNSProvider_CleanUp(t *testing.T) {
@@ -207,124 +203,112 @@ func TestDNSProvider_CleanUp(t *testing.T) {
 	os.Setenv("LINODE_TOKEN", "testing")
 
 	p, err := NewDNSProvider()
-	assert.NoError(t, err)
-
-	domain := "example.com"
-	keyAuth := "dGVzdGluZw=="
-	mockResponses := MockResponseMap{
-		"GET:/domains": &linodego.DomainsPagedResponse{
-			PageOptions: &linodego.PageOptions{
-				Pages:   1,
-				Results: 1,
-				Page:    1,
-			},
-			Data: []linodego.Domain{{
-				Domain: "foobar.com",
-				ID:     1234,
-			}},
-		},
-		"GET:/domains/1234/records": &linodego.DomainRecordsPagedResponse{
-			PageOptions: &linodego.PageOptions{
-				Pages:   1,
-				Results: 1,
-				Page:    1,
-			},
-			Data: []linodego.DomainRecord{{
-				ID:     1234,
-				Name:   "_acme-challenge",
-				Target: "ElbOJKOkFWiZLQeoxf-wb3IpOsQCdvoM0y_wn0TEkxM",
-				Type:   "TXT",
-			}},
-		},
-		"DELETE:/domains/1234/records/1234": struct{}{},
-	}
-
-	mockSrv := newMockServer(t, mockResponses)
-	defer mockSrv.Close()
-
-	p.client.SetBaseURL(mockSrv.URL)
-
-	err = p.CleanUp(domain, "", keyAuth)
-	assert.NoError(t, err)
-}
-
-func TestDNSProvider_CleanUpNoDomain(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("LINODE_TOKEN", "testing")
-
-	p, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	domain := "example.com"
 	keyAuth := "dGVzdGluZw=="
-	mockResponses := MockResponseMap{
-		"GET:/domains": linodego.APIError{
-			Errors: []linodego.APIErrorReason{{
-				Reason: "Not found",
-			}},
-		},
-		"GET:/domains/1234/records": linodego.APIError{
-			Errors: []linodego.APIErrorReason{{
-				Reason: "Not found",
-			}},
-		},
-	}
-
-	mockSrv := newMockServer(t, mockResponses)
-	defer mockSrv.Close()
-
-	p.client.SetBaseURL(mockSrv.URL)
-
-	err = p.CleanUp(domain, "", keyAuth)
-	assert.EqualError(t, err, "[404] Not found")
-}
-
-func TestDNSProvider_CleanUpDeleteFailed(t *testing.T) {
-	defer restoreEnv()
-	os.Setenv("LINODE_TOKEN", "testing")
 
-	p, err := NewDNSProvider()
-	assert.NoError(t, err)
-
-	domain := "example.com"
-	keyAuth := "dGVzdGluZw=="
-	mockResponses := MockResponseMap{
-		"GET:/domains": linodego.DomainsPagedResponse{
-			PageOptions: &linodego.PageOptions{
-				Pages:   1,
-				Results: 1,
-				Page:    1,
+	testCases := []struct {
+		desc          string
+		mockResponses MockResponseMap
+		expectedError string
+	}{
+		{
+			desc: "Success",
+			mockResponses: MockResponseMap{
+				"GET:/domains": &linodego.DomainsPagedResponse{
+					PageOptions: &linodego.PageOptions{
+						Pages:   1,
+						Results: 1,
+						Page:    1,
+					},
+					Data: []linodego.Domain{{
+						Domain: "foobar.com",
+						ID:     1234,
+					}},
+				},
+				"GET:/domains/1234/records": &linodego.DomainRecordsPagedResponse{
+					PageOptions: &linodego.PageOptions{
+						Pages:   1,
+						Results: 1,
+						Page:    1,
+					},
+					Data: []linodego.DomainRecord{{
+						ID:     1234,
+						Name:   "_acme-challenge",
+						Target: "ElbOJKOkFWiZLQeoxf-wb3IpOsQCdvoM0y_wn0TEkxM",
+						Type:   "TXT",
+					}},
+				},
+				"DELETE:/domains/1234/records/1234": struct{}{},
 			},
-			Data: []linodego.Domain{{
-				ID:     1234,
-				Domain: "example.com",
-			}},
 		},
-		"GET:/domains/1234/records": linodego.DomainRecordsPagedResponse{
-			PageOptions: &linodego.PageOptions{
-				Pages:   1,
-				Results: 1,
-				Page:    1,
+		{
+			desc: "NoDomain",
+			mockResponses: MockResponseMap{
+				"GET:/domains": linodego.APIError{
+					Errors: []linodego.APIErrorReason{{
+						Reason: "Not found",
+					}},
+				},
+				"GET:/domains/1234/records": linodego.APIError{
+					Errors: []linodego.APIErrorReason{{
+						Reason: "Not found",
+					}},
+				},
 			},
-			Data: []linodego.DomainRecord{{
-				ID:     1234,
-				Name:   "_acme-challenge",
-				Target: "ElbOJKOkFWiZLQeoxf-wb3IpOsQCdvoM0y_wn0TEkxM",
-				Type:   "TXT",
-			}},
+			expectedError: "[404] Not found",
 		},
-		"DELETE:/domains/1234/records/1234": linodego.APIError{
-			Errors: []linodego.APIErrorReason{{
-				Reason: "Failed to delete domain resource",
-			}},
+		{
+			desc: "DeleteFailed",
+			mockResponses: MockResponseMap{
+				"GET:/domains": linodego.DomainsPagedResponse{
+					PageOptions: &linodego.PageOptions{
+						Pages:   1,
+						Results: 1,
+						Page:    1,
+					},
+					Data: []linodego.Domain{{
+						ID:     1234,
+						Domain: "example.com",
+					}},
+				},
+				"GET:/domains/1234/records": linodego.DomainRecordsPagedResponse{
+					PageOptions: &linodego.PageOptions{
+						Pages:   1,
+						Results: 1,
+						Page:    1,
+					},
+					Data: []linodego.DomainRecord{{
+						ID:     1234,
+						Name:   "_acme-challenge",
+						Target: "ElbOJKOkFWiZLQeoxf-wb3IpOsQCdvoM0y_wn0TEkxM",
+						Type:   "TXT",
+					}},
+				},
+				"DELETE:/domains/1234/records/1234": linodego.APIError{
+					Errors: []linodego.APIErrorReason{{
+						Reason: "Failed to delete domain resource",
+					}},
+				},
+			},
+			expectedError: "[400] Failed to delete domain resource",
 		},
 	}
 
-	mockSrv := newMockServer(t, mockResponses)
-	defer mockSrv.Close()
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			mockSrv := newMockServer(t, test.mockResponses)
+			defer mockSrv.Close()
 
-	p.client.SetBaseURL(mockSrv.URL)
+			p.client.SetBaseURL(mockSrv.URL)
 
-	err = p.CleanUp(domain, "", keyAuth)
-	assert.EqualError(t, err, "[400] Failed to delete domain resource")
+			err = p.CleanUp(domain, "", keyAuth)
+			if len(test.expectedError) == 0 {
+				assert.NoError(t, err)
+			} else {
+				assert.EqualError(t, err, test.expectedError)
+			}
+		})
+	}
 }
diff --git a/providers/dns/namecheap/namecheap_test.go b/providers/dns/namecheap/namecheap_test.go
index f089670a..fc7ebdf4 100644
--- a/providers/dns/namecheap/namecheap_test.go
+++ b/providers/dns/namecheap/namecheap_test.go
@@ -93,14 +93,14 @@ func TestSetHosts(t *testing.T) {
 			if test.errString != "" {
 				assert.EqualError(t, err, test.errString)
 			} else {
-				assert.NoError(t, err)
+				require.NoError(t, err)
 			}
 			if err != nil {
 				return
 			}
 
 			err = prov.setHosts(ch, hosts)
-			assert.NoError(t, err)
+			require.NoError(t, err)
 		})
 	}
 }
@@ -232,7 +232,11 @@ func mockServer(tc *testcase, t *testing.T, w http.ResponseWriter, r *http.Reque
 		}
 
 	case http.MethodPost:
-		r.ParseForm()
+		err := r.ParseForm()
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
 		values := r.Form
 		cmd := values.Get("Command")
 		switch cmd {
@@ -246,7 +250,6 @@ func mockServer(tc *testcase, t *testing.T, w http.ResponseWriter, r *http.Reque
 
 	default:
 		t.Errorf("Unexpected http method: %s", r.Method)
-
 	}
 }
 
@@ -265,7 +268,7 @@ func mockDNSProvider(url string) *DNSProvider {
 type testcase struct {
 	name             string
 	domain           string
-	hosts            []host
+	hosts            []record
 	errString        string
 	getHostsResponse string
 	setHostsResponse string
@@ -275,7 +278,7 @@ var testcases = []testcase{
 	{
 		name:   "Test:Success:1",
 		domain: "test.example.com",
-		hosts: []host{
+		hosts: []record{
 			{Type: "A", Name: "home", Address: "10.0.0.1", MXPref: "10", TTL: "1799"},
 			{Type: "A", Name: "www", Address: "10.0.0.2", MXPref: "10", TTL: "1200"},
 			{Type: "AAAA", Name: "a", Address: "::0", MXPref: "10", TTL: "1799"},
@@ -289,7 +292,7 @@ var testcases = []testcase{
 	{
 		name:   "Test:Success:2",
 		domain: "example.com",
-		hosts: []host{
+		hosts: []record{
 			{Type: "A", Name: "@", Address: "10.0.0.2", MXPref: "10", TTL: "1200"},
 			{Type: "A", Name: "www", Address: "10.0.0.3", MXPref: "10", TTL: "60"},
 		},
diff --git a/providers/dns/namedotcom/namedotcom_test.go b/providers/dns/namedotcom/namedotcom_test.go
index 88109ee4..85a0d117 100644
--- a/providers/dns/namedotcom/namedotcom_test.go
+++ b/providers/dns/namedotcom/namedotcom_test.go
@@ -5,7 +5,7 @@ import (
 	"testing"
 	"time"
 
-	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 var (
@@ -38,10 +38,10 @@ func TestLiveNamedotcomPresent(t *testing.T) {
 	config.Server = namedotcomServer
 
 	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.Present(namedotcomDomain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 //
@@ -61,8 +61,8 @@ func TestLiveNamedotcomCleanUp(t *testing.T) {
 	config.Server = namedotcomServer
 
 	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.CleanUp(namedotcomDomain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
diff --git a/providers/dns/nifcloud/nifcloud_test.go b/providers/dns/nifcloud/nifcloud_test.go
index 363e635c..f82b5bd6 100644
--- a/providers/dns/nifcloud/nifcloud_test.go
+++ b/providers/dns/nifcloud/nifcloud_test.go
@@ -5,7 +5,7 @@ import (
 	"testing"
 	"time"
 
-	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 var (
@@ -31,10 +31,10 @@ func TestLivenifcloudPresent(t *testing.T) {
 	}
 
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.Present(nifcloudDomain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestLivenifcloudCleanUp(t *testing.T) {
@@ -45,8 +45,8 @@ func TestLivenifcloudCleanUp(t *testing.T) {
 	time.Sleep(time.Second * 1)
 
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.CleanUp(nifcloudDomain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
diff --git a/providers/dns/ns1/ns1_test.go b/providers/dns/ns1/ns1_test.go
index cf0c2c27..c40cc736 100644
--- a/providers/dns/ns1/ns1_test.go
+++ b/providers/dns/ns1/ns1_test.go
@@ -86,7 +86,7 @@ func TestNewDNSProviderValid(t *testing.T) {
 	config.APIKey = "123"
 
 	_, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestNewDNSProviderMissingCredErr(t *testing.T) {
@@ -106,10 +106,10 @@ func TestLivePresent(t *testing.T) {
 	config.APIKey = apiKey
 
 	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.Present(domain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestLiveCleanUp(t *testing.T) {
@@ -123,8 +123,8 @@ func TestLiveCleanUp(t *testing.T) {
 	config.APIKey = apiKey
 
 	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.CleanUp(domain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
diff --git a/providers/dns/ovh/ovh_test.go b/providers/dns/ovh/ovh_test.go
index 8c851f82..2e6a3c8a 100644
--- a/providers/dns/ovh/ovh_test.go
+++ b/providers/dns/ovh/ovh_test.go
@@ -6,6 +6,7 @@ import (
 	"time"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 var (
@@ -40,7 +41,7 @@ func TestNewDNSProviderValidEnv(t *testing.T) {
 	os.Setenv("OVH_CONSUMER_KEY", "abcde")
 
 	_, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestNewDNSProviderMissingCredErr(t *testing.T) {
@@ -123,10 +124,10 @@ func TestLivePresent(t *testing.T) {
 	}
 
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.Present(domain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestLiveCleanUp(t *testing.T) {
@@ -137,8 +138,8 @@ func TestLiveCleanUp(t *testing.T) {
 	time.Sleep(time.Second * 1)
 
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.CleanUp(domain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
diff --git a/providers/dns/pdns/pdns_test.go b/providers/dns/pdns/pdns_test.go
index a13392d3..68d204d9 100644
--- a/providers/dns/pdns/pdns_test.go
+++ b/providers/dns/pdns/pdns_test.go
@@ -6,6 +6,7 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 var (
@@ -43,7 +44,7 @@ func TestNewDNSProviderValid(t *testing.T) {
 	config.APIKey = "123"
 
 	_, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestNewDNSProviderValidEnv(t *testing.T) {
@@ -52,7 +53,7 @@ func TestNewDNSProviderValidEnv(t *testing.T) {
 	os.Setenv("PDNS_API_KEY", "123")
 
 	_, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestNewDNSProviderMissingHostErr(t *testing.T) {
@@ -83,11 +84,11 @@ func TestPdnsPresentAndCleanup(t *testing.T) {
 	config.APIKey = pdnsAPIKey
 
 	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.Present(pdnsDomain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.CleanUp(pdnsDomain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
diff --git a/providers/dns/rackspace/rackspace_test.go b/providers/dns/rackspace/rackspace_test.go
index 666c4770..ab214ab6 100644
--- a/providers/dns/rackspace/rackspace_test.go
+++ b/providers/dns/rackspace/rackspace_test.go
@@ -180,7 +180,7 @@ func TestOfflineRackspaceCleanUp(t *testing.T) {
 
 	if assert.NoError(t, err) {
 		err = provider.CleanUp("example.com", "token", "keyAuth")
-		assert.NoError(t, err)
+		require.NoError(t, err)
 	}
 }
 
@@ -191,7 +191,7 @@ func TestNewDNSProviderValidEnv(t *testing.T) {
 
 	liveRackspaceEnv()
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	assert.Contains(t, provider.cloudDNSEndpoint, "https://dns.api.rackspacecloud.com/v1.0/", "The endpoint URL should contain the base")
 }
 
@@ -202,10 +202,10 @@ func TestRackspacePresent(t *testing.T) {
 
 	liveRackspaceEnv()
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.Present(rackspaceDomain, "", "112233445566==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestRackspaceCleanUp(t *testing.T) {
@@ -217,10 +217,10 @@ func TestRackspaceCleanUp(t *testing.T) {
 
 	liveRackspaceEnv()
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.CleanUp(rackspaceDomain, "", "112233445566==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestMain(m *testing.M) {
diff --git a/providers/dns/rfc2136/rfc2136_test.go b/providers/dns/rfc2136/rfc2136_test.go
index 4c04ba50..fc1ce7ce 100644
--- a/providers/dns/rfc2136/rfc2136_test.go
+++ b/providers/dns/rfc2136/rfc2136_test.go
@@ -33,9 +33,14 @@ func TestRFC2136CanaryLocalTestServer(t *testing.T) {
 	dns.HandleFunc("example.com.", serverHandlerHello)
 	defer dns.HandleRemove("example.com.")
 
-	server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", false)
+	server, addrstr, err := runLocalDNSTestServer(false)
 	require.NoError(t, err, "Failed to start test server")
-	defer server.Shutdown()
+	defer func() {
+		errS := server.Shutdown()
+		if errS != nil {
+			t.Log(errS)
+		}
+	}()
 
 	c := new(dns.Client)
 	m := new(dns.Msg)
@@ -55,9 +60,14 @@ func TestRFC2136ServerSuccess(t *testing.T) {
 	dns.HandleFunc(rfc2136TestZone, serverHandlerReturnSuccess)
 	defer dns.HandleRemove(rfc2136TestZone)
 
-	server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", false)
+	server, addrstr, err := runLocalDNSTestServer(false)
 	require.NoError(t, err, "Failed to start test server")
-	defer server.Shutdown()
+	defer func() {
+		errS := server.Shutdown()
+		if errS != nil {
+			t.Log(errS)
+		}
+	}()
 
 	config := NewDefaultConfig()
 	config.Nameserver = addrstr
@@ -74,9 +84,14 @@ func TestRFC2136ServerError(t *testing.T) {
 	dns.HandleFunc(rfc2136TestZone, serverHandlerReturnErr)
 	defer dns.HandleRemove(rfc2136TestZone)
 
-	server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", false)
+	server, addrstr, err := runLocalDNSTestServer(false)
 	require.NoError(t, err, "Failed to start test server")
-	defer server.Shutdown()
+	defer func() {
+		errS := server.Shutdown()
+		if errS != nil {
+			t.Log(errS)
+		}
+	}()
 
 	config := NewDefaultConfig()
 	config.Nameserver = addrstr
@@ -96,9 +111,14 @@ func TestRFC2136TsigClient(t *testing.T) {
 	dns.HandleFunc(rfc2136TestZone, serverHandlerReturnSuccess)
 	defer dns.HandleRemove(rfc2136TestZone)
 
-	server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", true)
+	server, addrstr, err := runLocalDNSTestServer(true)
 	require.NoError(t, err, "Failed to start test server")
-	defer server.Shutdown()
+	defer func() {
+		errS := server.Shutdown()
+		if errS != nil {
+			t.Log(errS)
+		}
+	}()
 
 	config := NewDefaultConfig()
 	config.Nameserver = addrstr
@@ -117,9 +137,14 @@ func TestRFC2136ValidUpdatePacket(t *testing.T) {
 	dns.HandleFunc(rfc2136TestZone, serverHandlerPassBackRequest)
 	defer dns.HandleRemove(rfc2136TestZone)
 
-	server, addrstr, err := runLocalDNSTestServer("127.0.0.1:0", false)
+	server, addrstr, err := runLocalDNSTestServer(false)
 	require.NoError(t, err, "Failed to start test server")
-	defer server.Shutdown()
+	defer func() {
+		errS := server.Shutdown()
+		if errS != nil {
+			t.Log(errS)
+		}
+	}()
 
 	txtRR, _ := dns.NewRR(fmt.Sprintf("%s %d IN TXT %s", rfc2136TestFqdn, rfc2136TestTTL, rfc2136TestValue))
 	rrs := []dns.RR{txtRR}
@@ -157,8 +182,8 @@ func TestRFC2136ValidUpdatePacket(t *testing.T) {
 	}
 }
 
-func runLocalDNSTestServer(listenAddr string, tsig bool) (*dns.Server, string, error) {
-	pc, err := net.ListenPacket("udp", listenAddr)
+func runLocalDNSTestServer(tsig bool) (*dns.Server, string, error) {
+	pc, err := net.ListenPacket("udp", "127.0.0.1:0")
 	if err != nil {
 		return nil, "", err
 	}
@@ -172,7 +197,7 @@ func runLocalDNSTestServer(listenAddr string, tsig bool) (*dns.Server, string, e
 	server.NotifyStartedFunc = waitLock.Unlock
 
 	go func() {
-		server.ActivateAndServe()
+		_ = server.ActivateAndServe()
 		pc.Close()
 	}()
 
@@ -188,7 +213,7 @@ func serverHandlerHello(w dns.ResponseWriter, req *dns.Msg) {
 		Hdr: dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0},
 		Txt: []string{"Hello world"},
 	}
-	w.WriteMsg(m)
+	_ = w.WriteMsg(m)
 }
 
 func serverHandlerReturnSuccess(w dns.ResponseWriter, req *dns.Msg) {
@@ -207,13 +232,13 @@ func serverHandlerReturnSuccess(w dns.ResponseWriter, req *dns.Msg) {
 		}
 	}
 
-	w.WriteMsg(m)
+	_ = w.WriteMsg(m)
 }
 
 func serverHandlerReturnErr(w dns.ResponseWriter, req *dns.Msg) {
 	m := new(dns.Msg)
 	m.SetRcode(req, dns.RcodeNotZone)
-	w.WriteMsg(m)
+	_ = w.WriteMsg(m)
 }
 
 func serverHandlerPassBackRequest(w dns.ResponseWriter, req *dns.Msg) {
@@ -232,7 +257,7 @@ func serverHandlerPassBackRequest(w dns.ResponseWriter, req *dns.Msg) {
 		}
 	}
 
-	w.WriteMsg(m)
+	_ = w.WriteMsg(m)
 	if req.Opcode != dns.OpcodeQuery || req.Question[0].Qtype != dns.TypeSOA || req.Question[0].Qclass != dns.ClassINET {
 		// Only talk back when it is not the SOA RR.
 		reqChan <- req
diff --git a/providers/dns/route53/route53_integration_test.go b/providers/dns/route53/route53_integration_test.go
index 886f1889..6d0d9e89 100644
--- a/providers/dns/route53/route53_integration_test.go
+++ b/providers/dns/route53/route53_integration_test.go
@@ -19,35 +19,36 @@ func TestRoute53TTL(t *testing.T) {
 	provider, err := NewDNSProvider()
 	require.NoError(t, err)
 
-	err = provider.Present(config["R53_DOMAIN"], "foo", "bar")
+	r53Domain := config["R53_DOMAIN"]
+
+	err = provider.Present(r53Domain, "foo", "bar")
 	require.NoError(t, err)
 
-	// we need a separate R53 client here as the one in the DNS provider is
-	// unexported.
-	fqdn := "_acme-challenge." + config["R53_DOMAIN"] + "."
+	// we need a separate R53 client here as the one in the DNS provider is unexported.
+	fqdn := "_acme-challenge." + r53Domain + "."
 	svc := route53.New(session.New())
+
+	defer func() {
+		errC := provider.CleanUp(r53Domain, "foo", "bar")
+		if errC != nil {
+			t.Log(errC)
+		}
+	}()
+
 	zoneID, err := provider.getHostedZoneID(fqdn)
-	if err != nil {
-		provider.CleanUp(config["R53_DOMAIN"], "foo", "bar")
-		t.Fatal(err)
-	}
+	require.NoError(t, err)
 
 	params := &route53.ListResourceRecordSetsInput{
 		HostedZoneId: aws.String(zoneID),
 	}
 	resp, err := svc.ListResourceRecordSets(params)
-	if err != nil {
-		provider.CleanUp(config["R53_DOMAIN"], "foo", "bar")
-		t.Fatal(err)
-	}
+	require.NoError(t, err)
 
 	for _, v := range resp.ResourceRecordSets {
 		if aws.StringValue(v.Name) == fqdn && aws.StringValue(v.Type) == "TXT" && aws.Int64Value(v.TTL) == 10 {
-			provider.CleanUp(config["R53_DOMAIN"], "foo", "bar")
 			return
 		}
 	}
 
-	provider.CleanUp(config["R53_DOMAIN"], "foo", "bar")
-	t.Fatalf("Could not find a TXT record for _acme-challenge.%s with a TTL of 10", config["R53_DOMAIN"])
+	t.Fatalf("Could not find a TXT record for _acme-challenge.%s with a TTL of 10", r53Domain)
 }
diff --git a/providers/dns/route53/testutil_test.go b/providers/dns/route53/testutil_test.go
index e448a685..22ad228c 100644
--- a/providers/dns/route53/testutil_test.go
+++ b/providers/dns/route53/testutil_test.go
@@ -30,7 +30,11 @@ func newMockServer(t *testing.T, responses MockResponseMap) *httptest.Server {
 
 		w.Header().Set("Content-Type", "application/xml")
 		w.WriteHeader(resp.StatusCode)
-		w.Write([]byte(resp.Body))
+		_, err := w.Write([]byte(resp.Body))
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
 	}))
 
 	time.Sleep(100 * time.Millisecond)
diff --git a/providers/dns/sakuracloud/sakuracloud_test.go b/providers/dns/sakuracloud/sakuracloud_test.go
index 3c00baa0..d8713a54 100644
--- a/providers/dns/sakuracloud/sakuracloud_test.go
+++ b/providers/dns/sakuracloud/sakuracloud_test.go
@@ -45,7 +45,7 @@ func TestNewDNSProviderValid(t *testing.T) {
 
 	assert.NotNil(t, provider)
 	assert.Equal(t, acme.UserAgent, provider.client.UserAgent)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestNewDNSProviderInvalidWithMissingAccessToken(t *testing.T) {
@@ -96,10 +96,10 @@ func TestLiveSakuraCloudPresent(t *testing.T) {
 	config.Secret = sakuracloudAccessSecret
 
 	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.Present(sakuracloudDomain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 //
@@ -118,8 +118,8 @@ func TestLiveSakuraCloudCleanUp(t *testing.T) {
 	config.Secret = sakuracloudAccessSecret
 
 	provider, err := NewDNSProviderConfig(config)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.CleanUp(sakuracloudDomain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
diff --git a/providers/dns/vegadns/vegadns_test.go b/providers/dns/vegadns/vegadns_test.go
index a505801f..257f2dda 100644
--- a/providers/dns/vegadns/vegadns_test.go
+++ b/providers/dns/vegadns/vegadns_test.go
@@ -15,6 +15,8 @@ import (
 	"github.com/stretchr/testify/require"
 )
 
+const testDomain = "example.com"
+
 var ipPort = "127.0.0.1:2112"
 
 var jsonMap = map[string]string{
@@ -122,88 +124,90 @@ func TestVegaDNSTimeoutSuccess(t *testing.T) {
 	assert.Equal(t, interval, time.Duration(60000000000))
 }
 
-func TestVegaDNSPresentSuccess(t *testing.T) {
-	ts, err := startTestServer(vegaDNSMuxSuccess)
-	require.NoError(t, err)
-
-	defer ts.Close()
-	defer os.Clearenv()
-
-	provider, err := NewDNSProvider()
-	require.NoError(t, err)
-
-	err = provider.Present("example.com", "token", "keyAuth")
-	assert.NoError(t, err)
-}
-
-func TestVegaDNSPresentFailToFindZone(t *testing.T) {
-	ts, err := startTestServer(vegaDNSMuxFailToFindZone)
-	require.NoError(t, err)
-
-	defer ts.Close()
-	defer os.Clearenv()
-
-	provider, err := NewDNSProvider()
-	require.NoError(t, err)
-
-	err = provider.Present("example.com", "token", "keyAuth")
-	assert.EqualError(t, err, "vegadns: can't find Authoritative Zone for _acme-challenge.example.com. in Present: Unable to find auth zone for fqdn _acme-challenge.example.com")
-}
-
-func TestVegaDNSPresentFailToCreateTXT(t *testing.T) {
-	ts, err := startTestServer(vegaDNSMuxFailToCreateTXT)
-	require.NoError(t, err)
-
-	defer ts.Close()
-	defer os.Clearenv()
-
-	provider, err := NewDNSProvider()
-	require.NoError(t, err)
-
-	err = provider.Present("example.com", "token", "keyAuth")
-	assert.EqualError(t, err, "vegadns: Got bad answer from VegaDNS on CreateTXT. Code: 400. Message: ")
-}
+func TestDNSProvider_Present(t *testing.T) {
+	testCases := []struct {
+		desc          string
+		callback      muxCallback
+		expectedError string
+	}{
+		{
+			desc:     "Success",
+			callback: vegaDNSMuxSuccess,
+		},
+		{
+			desc:          "FailToFindZone",
+			callback:      vegaDNSMuxFailToFindZone,
+			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",
+			callback:      vegaDNSMuxFailToCreateTXT,
+			expectedError: "vegadns: Got bad answer from VegaDNS on CreateTXT. Code: 400. Message: ",
+		},
+	}
 
-func TestVegaDNSCleanUpSuccess(t *testing.T) {
-	ts, err := startTestServer(vegaDNSMuxSuccess)
-	require.NoError(t, err)
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			ts, err := startTestServer(test.callback)
+			require.NoError(t, err)
 
-	defer ts.Close()
-	defer os.Clearenv()
+			defer ts.Close()
+			defer os.Clearenv()
 
-	provider, err := NewDNSProvider()
-	require.NoError(t, err)
+			provider, err := NewDNSProvider()
+			require.NoError(t, err)
 
-	err = provider.CleanUp("example.com", "token", "keyAuth")
-	assert.NoError(t, err)
+			err = provider.Present(testDomain, "token", "keyAuth")
+			if len(test.expectedError) == 0 {
+				assert.NoError(t, err)
+			} else {
+				assert.EqualError(t, err, test.expectedError)
+			}
+		})
+	}
 }
 
-func TestVegaDNSCleanUpFailToFindZone(t *testing.T) {
-	ts, err := startTestServer(vegaDNSMuxFailToFindZone)
-	require.NoError(t, err)
-
-	defer ts.Close()
-	defer os.Clearenv()
-
-	provider, err := NewDNSProvider()
-	require.NoError(t, err)
-
-	err = provider.CleanUp("example.com", "token", "keyAuth")
-	assert.EqualError(t, err, "vegadns: can't find Authoritative Zone for _acme-challenge.example.com. in CleanUp: Unable to find auth zone for fqdn _acme-challenge.example.com")
-}
+func TestDNSProvider_CleanUp(t *testing.T) {
+	testCases := []struct {
+		desc          string
+		callback      muxCallback
+		expectedError string
+	}{
+		{
+			desc:     "Success",
+			callback: vegaDNSMuxSuccess,
+		},
+		{
+			desc:          "FailToFindZone",
+			callback:      vegaDNSMuxFailToFindZone,
+			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",
+			callback:      vegaDNSMuxFailToGetRecordID,
+			expectedError: "vegadns: couldn't get Record ID in CleanUp: Got bad answer from VegaDNS on GetRecordID. Code: 404. Message: ",
+		},
+	}
 
-func TestVegaDNSCleanUpFailToGetRecordID(t *testing.T) {
-	ts, err := startTestServer(vegaDNSMuxFailToGetRecordID)
-	require.NoError(t, err)
+	for _, test := range testCases {
+		t.Run(test.desc, func(t *testing.T) {
+			ts, err := startTestServer(test.callback)
+			require.NoError(t, err)
 
-	defer ts.Close()
-	defer os.Clearenv()
+			defer ts.Close()
+			defer os.Clearenv()
 
-	provider, err := NewDNSProvider()
-	require.NoError(t, err)
+			provider, err := NewDNSProvider()
+			require.NoError(t, err)
 
-	err = provider.CleanUp("example.com", "token", "keyAuth")
-	assert.EqualError(t, err, "vegadns: couldn't get Record ID in CleanUp: Got bad answer from VegaDNS on GetRecordID. Code: 404. Message: ")
+			err = provider.CleanUp(testDomain, "token", "keyAuth")
+			if len(test.expectedError) == 0 {
+				assert.NoError(t, err)
+			} else {
+				assert.EqualError(t, err, test.expectedError)
+			}
+		})
+	}
 }
 
 func vegaDNSMuxSuccess() *http.ServeMux {
@@ -298,7 +302,7 @@ func vegaDNSMuxFailToCreateTXT() *http.ServeMux {
 	})
 
 	mux.HandleFunc("/1.0/domains", func(w http.ResponseWriter, r *http.Request) {
-		if r.URL.Query().Get("search") == "example.com" {
+		if r.URL.Query().Get("search") == testDomain {
 			w.WriteHeader(http.StatusOK)
 			fmt.Fprintf(w, jsonMap["domains"])
 			return
@@ -340,7 +344,7 @@ func vegaDNSMuxFailToGetRecordID() *http.ServeMux {
 	})
 
 	mux.HandleFunc("/1.0/domains", func(w http.ResponseWriter, r *http.Request) {
-		if r.URL.Query().Get("search") == "example.com" {
+		if r.URL.Query().Get("search") == testDomain {
 			w.WriteHeader(http.StatusOK)
 			fmt.Fprintf(w, jsonMap["domains"])
 			return
diff --git a/providers/dns/vultr/vultr_test.go b/providers/dns/vultr/vultr_test.go
index 4c9b8a37..0f045c01 100644
--- a/providers/dns/vultr/vultr_test.go
+++ b/providers/dns/vultr/vultr_test.go
@@ -6,6 +6,7 @@ import (
 	"time"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 var (
@@ -29,7 +30,7 @@ func TestNewDNSProviderValidEnv(t *testing.T) {
 	os.Setenv("VULTR_API_KEY", "123")
 
 	_, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestNewDNSProviderMissingCredErr(t *testing.T) {
@@ -46,10 +47,10 @@ func TestLivePresent(t *testing.T) {
 	}
 
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.Present(domain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestLiveCleanUp(t *testing.T) {
@@ -60,8 +61,8 @@ func TestLiveCleanUp(t *testing.T) {
 	time.Sleep(time.Second * 1)
 
 	provider, err := NewDNSProvider()
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	err = provider.CleanUp(domain, "", "123d==")
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
diff --git a/providers/http/memcached/memcached_test.go b/providers/http/memcached/memcached_test.go
index f9488a1d..7c61007b 100644
--- a/providers/http/memcached/memcached_test.go
+++ b/providers/http/memcached/memcached_test.go
@@ -8,6 +8,7 @@ import (
 
 	"github.com/rainycape/memcache"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 	"github.com/xenolf/lego/acme"
 )
 
@@ -39,7 +40,7 @@ func TestNewMemcachedProviderValid(t *testing.T) {
 		t.Skip("Skipping memcached tests")
 	}
 	_, err := NewMemcachedProvider(memcachedHosts)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 }
 
 func TestMemcachedPresentSingleHost(t *testing.T) {
@@ -47,16 +48,16 @@ func TestMemcachedPresentSingleHost(t *testing.T) {
 		t.Skip("Skipping memcached tests")
 	}
 	p, err := NewMemcachedProvider(memcachedHosts[0:1])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	challengePath := path.Join("/", acme.HTTP01ChallengePath(token))
 
 	err = p.Present(domain, token, keyAuth)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	mc, err := memcache.New(memcachedHosts[0])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	i, err := mc.Get(challengePath)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	assert.Equal(t, i.Value, []byte(keyAuth))
 }
 
@@ -65,17 +66,17 @@ func TestMemcachedPresentMultiHost(t *testing.T) {
 		t.Skip("Skipping memcached multi-host tests")
 	}
 	p, err := NewMemcachedProvider(memcachedHosts)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	challengePath := path.Join("/", acme.HTTP01ChallengePath(token))
 
 	err = p.Present(domain, token, keyAuth)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	for _, host := range memcachedHosts {
 		mc, err := memcache.New(host)
-		assert.NoError(t, err)
+		require.NoError(t, err)
 		i, err := mc.Get(challengePath)
-		assert.NoError(t, err)
+		require.NoError(t, err)
 		assert.Equal(t, i.Value, []byte(keyAuth))
 	}
 }
@@ -86,17 +87,17 @@ func TestMemcachedPresentPartialFailureMultiHost(t *testing.T) {
 	}
 	hosts := append(memcachedHosts, "5.5.5.5:11211")
 	p, err := NewMemcachedProvider(hosts)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	challengePath := path.Join("/", acme.HTTP01ChallengePath(token))
 
 	err = p.Present(domain, token, keyAuth)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	for _, host := range memcachedHosts {
 		mc, err := memcache.New(host)
-		assert.NoError(t, err)
+		require.NoError(t, err)
 		i, err := mc.Get(challengePath)
-		assert.NoError(t, err)
+		require.NoError(t, err)
 		assert.Equal(t, i.Value, []byte(keyAuth))
 	}
 }
@@ -106,6 +107,6 @@ func TestMemcachedCleanup(t *testing.T) {
 		t.Skip("Skipping memcached tests")
 	}
 	p, err := NewMemcachedProvider(memcachedHosts)
-	assert.NoError(t, err)
-	assert.NoError(t, p.CleanUp(domain, token, keyAuth))
+	require.NoError(t, err)
+	require.NoError(t, p.CleanUp(domain, token, keyAuth))
 }
diff --git a/providers/http/webroot/webroot_test.go b/providers/http/webroot/webroot_test.go
index 99c930ed..5fccae37 100644
--- a/providers/http/webroot/webroot_test.go
+++ b/providers/http/webroot/webroot_test.go
@@ -4,6 +4,9 @@ import (
 	"io/ioutil"
 	"os"
 	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 func TestHTTPProvider(t *testing.T) {
@@ -13,34 +16,26 @@ func TestHTTPProvider(t *testing.T) {
 	keyAuth := "keyAuth"
 	challengeFilePath := webroot + "/.well-known/acme-challenge/" + token
 
-	os.MkdirAll(webroot+"/.well-known/acme-challenge", 0777)
+	require.NoError(t, os.MkdirAll(webroot+"/.well-known/acme-challenge", 0777))
 	defer os.RemoveAll(webroot)
 
 	provider, err := NewHTTPProvider(webroot)
-	if err != nil {
-		t.Errorf("Webroot provider error: got %v, want nil", err)
-	}
+	require.NoError(t, err)
 
 	err = provider.Present(domain, token, keyAuth)
-	if err != nil {
-		t.Errorf("Webroot provider present() error: got %v, want nil", err)
-	}
+	require.NoError(t, err)
 
-	if _, err := os.Stat(challengeFilePath); os.IsNotExist(err) {
+	if _, err = os.Stat(challengeFilePath); os.IsNotExist(err) {
 		t.Error("Challenge file was not created in webroot")
 	}
 
-	data, err := ioutil.ReadFile(challengeFilePath)
-	if err != nil {
-		t.Errorf("Webroot provider ReadFile() error: got %v, want nil", err)
-	}
+	var data []byte
+	data, err = ioutil.ReadFile(challengeFilePath)
+	require.NoError(t, err)
+
 	dataStr := string(data)
-	if dataStr != keyAuth {
-		t.Errorf("Challenge file content: got %q, want %q", dataStr, keyAuth)
-	}
+	assert.Equal(t, keyAuth, dataStr)
 
 	err = provider.CleanUp(domain, token, keyAuth)
-	if err != nil {
-		t.Errorf("Webroot provider CleanUp() error: got %v, want nil", err)
-	}
+	require.NoError(t, err)
 }