Skip to content

Commit

Permalink
Merge pull request #140 from abhishalya/ext_links
Browse files Browse the repository at this point in the history
Add option: `IgnoreExternalBrokenLinks`
  • Loading branch information
wjdp committed Jan 25, 2020
2 parents 3e6b803 + 3ff9286 commit 1171a50
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 5 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ htmltest uses a YAML configuration file. Put `.htmltest.yml` in the same directo
| `IgnoreInternalEmptyHash` | When true prevents raising an error for links with `href="#"`. | `false` |
| `IgnoreEmptyHref` | When true prevents raising an error for links with `href=""`. | `false` |
| `IgnoreCanonicalBrokenLinks` | When true produces a warning, rather than an error, for broken canonical links. When testing a site which isn't live yet or before publishing a new page canonical links will fail. | `true` |
| `IgnoreExternalBrokenLinks` | When true produces a warning, rather than an error, for broken external links. Useful when testing a site having hundreds of external links. | `false` |
| `IgnoreAltMissing` | Turns off image alt attribute checking. | `false` |
| `IgnoreDirectoryMissingTrailingSlash` | Turns off errors for links to directories without a trailing slash. | `false` |
| `IgnoreSSLVerify` | Turns off x509 errors for self-signed certificates. | `false` |
Expand Down
6 changes: 5 additions & 1 deletion htmltest/check-generic.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,14 @@ func (hT *HTMLTest) enforceHTTPS(ref *htmldoc.Reference) {
if hT.opts.isURLIgnored(ref.URLString()) {
return
}
issueLevel := issues.LevelError
if hT.opts.IgnoreExternalBrokenLinks {
issueLevel = issues.LevelWarning
}

if hT.opts.EnforceHTTPS {
hT.issueStore.AddIssue(issues.Issue{
Level: issues.LevelError,
Level: issueLevel,
Message: "is not an HTTPS target",
Reference: ref,
})
Expand Down
12 changes: 8 additions & 4 deletions htmltest/check-link.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ func (hT *HTMLTest) checkLink(document *htmldoc.Document, node *html.Node) {
}

func (hT *HTMLTest) checkExternal(ref *htmldoc.Reference) {
issueLevel := issues.LevelError
if hT.opts.IgnoreExternalBrokenLinks {
issueLevel = issues.LevelWarning
}
if !hT.opts.CheckExternal {
hT.issueStore.AddIssue(issues.Issue{
Level: issues.LevelDebug,
Expand Down Expand Up @@ -184,15 +188,15 @@ func (hT *HTMLTest) checkExternal(ref *htmldoc.Reference) {
cleanedMessage := strings.TrimPrefix(err.Error(), prefix)
// Add error
hT.issueStore.AddIssue(issues.Issue{
Level: issues.LevelError,
Level: issueLevel,
Message: cleanedMessage,
Reference: ref,
})
return
}
if strings.Contains(err.Error(), "Client.Timeout") {
hT.issueStore.AddIssue(issues.Issue{
Level: issues.LevelError,
Level: issueLevel,
Message: "request exceeded our ExternalTimeout",
Reference: ref,
})
Expand All @@ -213,7 +217,7 @@ func (hT *HTMLTest) checkExternal(ref *htmldoc.Reference) {

// Unhandled client error, return generic error
hT.issueStore.AddIssue(issues.Issue{
Level: issues.LevelError,
Level: issueLevel,
Message: err.Error(),
Reference: ref,
})
Expand Down Expand Up @@ -249,7 +253,7 @@ func (hT *HTMLTest) checkExternal(ref *htmldoc.Reference) {
} else {
// Failed VCRed requests end up here with a status code of zero
hT.issueStore.AddIssue(issues.Issue{
Level: issues.LevelError,
Level: issueLevel,
Message: fmt.Sprintf("%s %d", "Non-OK status:", statusCode),
Reference: ref,
})
Expand Down
57 changes: 57 additions & 0 deletions htmltest/check-link_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ func TestAnchorExternalBroken(t *testing.T) {
tExpectIssueCount(t, hT, 1)
}

func TestAnchorExternalBrokenOption(t *testing.T) {
// passes for broken external links when asked
hT := tTestFileOpts("fixtures/links/brokenLinkExternal.html",
map[string]interface{}{"IgnoreExternalBrokenLinks": true, "VCREnable": true})
tExpectIssueCount(t, hT, 0)
}

func TestAnchorExternalBrokenNoVCR(t *testing.T) {
// fails for broken external links without VCR. This is needed as the code that handles 'dial tcp' errors doesn't
// get called with VCR. It returns a rather empty response with status code of 0.
Expand All @@ -50,6 +57,14 @@ func TestAnchorExternalBrokenNoVCR(t *testing.T) {
tExpectIssueCount(t, hT, 1)
}

func TestAnchorExternalBrokenOptionNoVCR(t *testing.T) {
// passes for broken external links without VCR when asked.
tSkipShortExternal(t)
hT := tTestFileOpts("fixtures/links/brokenLinkExternal.html",
map[string]interface{}{"IgnoreExternalBrokenLinks": true})
tExpectIssueCount(t, hT, 0)
}

func TestAnchorExternalIgnore(t *testing.T) {
// ignores external links when asked
hT := tTestFileOpts("fixtures/links/brokenLinkExternal.html",
Expand Down Expand Up @@ -103,6 +118,13 @@ func TestAnchorExternalInsecureOption(t *testing.T) {
tExpectIssue(t, hT, "is not an HTTPS target", 1)
}

func TestAnchorExternalBrokenOptionInsecure(t *testing.T) {
// passes for non-HTTPS links when asked
hT := tTestFileOpts("fixtures/links/non_https.html",
map[string]interface{}{"EnforceHTTPS": true, "IgnoreExternalBrokenLinks": true, "VCREnable": true})
tExpectIssueCount(t, hT, 0)
}

func TestAnchorExternalInsecureOptionIgnored(t *testing.T) {
// passes when checking for non-HTTPS links but they're in the IgnoreURLs list
hT := tTestFileOpts("fixtures/links/issues/94.html",
Expand All @@ -120,6 +142,13 @@ func TestAnchorExternalHrefIP(t *testing.T) {
tExpectIssueCount(t, hT, 2)
}

func TestAnchorExternalBrokenOptionHrefIP(t *testing.T) {
// passes for broken IP address links when asked
hT := tTestFileOpts("fixtures/links/ip_href.html",
map[string]interface{}{"VCREnable": true, "IgnoreExternalBrokenLinks": true})
tExpectIssueCount(t, hT, 0)
}

func TestAnchorExternalHrefIPTimeout(t *testing.T) {
// fails for broken IP address links
hT := tTestFileOpts("fixtures/links/ip_timeout.html",
Expand All @@ -128,6 +157,13 @@ func TestAnchorExternalHrefIPTimeout(t *testing.T) {
tExpectIssue(t, hT, "request exceeded our ExternalTimeout", 1)
}

func TestAnchorExternalBrokenOptionHrefIPTimeout(t *testing.T) {
// passes for broken IP address links when aksed
hT := tTestFileOpts("fixtures/links/ip_timeout.html",
map[string]interface{}{"IgnoreExternalBrokenLinks": true, "ExternalTimeout": 1})
tExpectIssueCount(t, hT, 0)
}

func TestAnchorExternalFollowRedirects(t *testing.T) {
// should follow redirects
hT := tTestFileOpts("fixtures/links/linkWithRedirect.html",
Expand Down Expand Up @@ -158,6 +194,13 @@ func TestAnchorExternalHTTPSInvalid(t *testing.T) {
tExpectIssueCount(t, hT, 6)
}

func TestAnchorExternalBrokenOptionHTTPSInvalid(t *testing.T) {
// should pass for invalid https when asked
hT := tTestFileOpts("fixtures/links/https-invalid.html",
map[string]interface{}{"IgnoreExternalBrokenLinks": true, "VCREnable": true})
tExpectIssueCount(t, hT, 0)
}

func TestAnchorExternalHTTPSMissingChain(t *testing.T) {
// should support https aia
// see issue #130
Expand All @@ -166,6 +209,13 @@ func TestAnchorExternalHTTPSMissingChain(t *testing.T) {
tExpectIssue(t, hT, "incomplete certificate chain", 1)
}

func TestAnchorExternalBrokenOptionHTTPSMissingChain(t *testing.T) {
// should pass for incomplete chains when asked
hT := tTestFileOpts("fixtures/links/https-incomplete-chain.html",
map[string]interface{}{"IgnoreExternalBrokenLinks": true, "VCREnable": false})
tExpectIssueCount(t, hT, 0)
}

func TestAnchorExternalHTTPSBadH2(t *testing.T) {
// should connect to servers with bad http/2 support
// See issue #49
Expand Down Expand Up @@ -197,6 +247,13 @@ func TestAnchorExternalMissingProtocolInvalid(t *testing.T) {
// tExpectIssue(t, hT, "no such host", 1)
}

func TestAnchorExternalBrokenOptionMissingProtocol(t *testing.T) {
// passes for invalid links missing the protocol when asked
hT := tTestFileOpts("fixtures/links/link_missing_protocol_invalid.html",
map[string]interface{}{"IgnoreExternalBrokenLinks": true, "VCREnable": true})
tExpectIssueCount(t, hT, 0)
}

func TestLinkExternalHrefPipes(t *testing.T) {
// works for pipes in the URL
hT := tTestFileOpts("fixtures/links/escape_pipes.html",
Expand Down
2 changes: 2 additions & 0 deletions htmltest/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type Options struct {
IgnoreInternalEmptyHash bool
IgnoreEmptyHref bool
IgnoreCanonicalBrokenLinks bool
IgnoreExternalBrokenLinks bool
IgnoreAltMissing bool
IgnoreDirectoryMissingTrailingSlash bool
IgnoreSSLVerify bool
Expand Down Expand Up @@ -106,6 +107,7 @@ func DefaultOptions() map[string]interface{} {
"IgnoreInternalEmptyHash": false,
"IgnoreEmptyHref": false,
"IgnoreCanonicalBrokenLinks": true,
"IgnoreExternalBrokenLinks": false,
"IgnoreAltMissing": false,
"IgnoreDirectoryMissingTrailingSlash": false,
"IgnoreSSLVerify": false,
Expand Down

0 comments on commit 1171a50

Please sign in to comment.