Skip to content

Commit 2a2e1ff

Browse files
dpittnerseborama
andauthored
feat: add support for some more errors (syscall errors and DNS specifically) (#114)
* feat: add support for some more errors * linter compliance --------- Co-authored-by: seborama <seborama@users.noreply.github.com>
1 parent ecffe9c commit 2a2e1ff

File tree

12 files changed

+83
-56
lines changed

12 files changed

+83
-56
lines changed

.golangci.yml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ run:
7070
# Define the Go version limit.
7171
# Mainly related to generics support in go1.18.
7272
# Default: use Go version from the go.mod file, fallback on the env var `GOVERSION`, fallback on 1.17
73-
go: '1.17'
73+
go: '1.20'
7474

7575

7676
# output configuration options
@@ -457,7 +457,7 @@ linters-settings:
457457
govet:
458458
# Report about shadowed variables.
459459
# Default: false
460-
check-shadowing: false
460+
shadow: true
461461

462462
# Settings per analyzer.
463463
settings:
@@ -625,6 +625,7 @@ linters:
625625
- bodyclose
626626
- containedctx
627627
- contextcheck
628+
- copyloopvar
628629
- cyclop
629630
# - decorder
630631
# - depguard
@@ -637,7 +638,6 @@ linters:
637638
# - errorlint
638639
# - exhaustive
639640
# - exhaustivestruct
640-
- exportloopref
641641
# - forbidigo
642642
# - forcetypeassert
643643
# - funlen
@@ -650,7 +650,7 @@ linters:
650650
- gocyclo
651651
- godot
652652
# - godox
653-
- goerr113
653+
- err113
654654
- gofmt
655655
- gofumpt
656656
# - goheader
@@ -697,7 +697,6 @@ linters:
697697
- unparam
698698
- unused
699699
# - varnamelen
700-
- vetshadow
701700
# - wastedassign
702701
# - whitespace
703702
# - wrapcheck
@@ -729,7 +728,7 @@ issues:
729728
- dupl
730729
- gocognit
731730
- gocyclo
732-
- goerr113
731+
- err113
733732
- gosec
734733

735734
- path: _test\.go

README.md

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -41,35 +41,44 @@ This project is an adaptation for Google's Go / Golang programming language.
4141

4242
## Table of content
4343

44-
- [Simple VCR example](#simple-vcr-example)
45-
- [Install](#install)
46-
- [Glossary of Terms](#glossary-of-terms)
47-
- [Concepts](#concepts)
48-
- [VCRSettings](#vcrsettings)
49-
- [Match a request to a cassette track](#match-a-request-to-a-cassette-track)
50-
- [Track mutators](#track-mutators)
51-
- [Cassette encryption](#cassette-encryption)
52-
- [Cookbook](#cookbook)
53-
- [Run the examples](#run-the-examples)
54-
- [Recipe: VCR with custom `http.Client`](#recipe-vcr-with-custom-httpclient)
55-
- [Recipe: Remove Response TLS](#recipe-remove-response-tls)
56-
- [Recipe: Change the playback mode of the VCR](#recipe-change-the-playback-mode-of-the-vcr)
57-
- [Recipe: VCR with encrypted cassette](#recipe-vcr-with-encrypted-cassette)
58-
- [Recipe: VCR with encrypted cassette - custom nonce generator](#recipe-vcr-with-encrypted-cassette---custom-nonce-generator)
59-
- [Recipe: Cassette decryption](#recipe-cassette-decryption)
60-
- [Recipe: Changing cassette encryption](#recipe-changing-cassette-encryption)
61-
- [Recipe: VCR with cassette storage on AWS S3](#recipe-vcr-with-cassette-storage-on-aws-s3)
62-
- [Recipe: VCR with a custom RequestMatcher](#recipe-vcr-with-a-custom-requestmatcher)
63-
- [Recipe: VCR with a replaying Track Mutator](#recipe-vcr-with-a-replaying-track-mutator)
64-
- [Recipe: VCR with a recording Track Mutator](#recipe-vcr-with-a-recording-track-mutator)
65-
- [More](#more)
66-
- [Stats](#stats)
67-
- [Run the tests](#run-the-tests)
68-
- [Bugs](#bugs)
69-
- [Improvements](#improvements)
70-
- [Limitations](#limitations)
71-
- [Contribute](#contribute)
72-
- [Community Support Appeal](#community-support-appeal)
44+
- [govcr](#govcr)
45+
- [Table of content](#table-of-content)
46+
- [Simple VCR example](#simple-vcr-example)
47+
- [Install](#install)
48+
- [Glossary of Terms](#glossary-of-terms)
49+
- [Concepts](#concepts)
50+
- [VCRSettings](#vcrsettings)
51+
- [Match a request to a cassette track](#match-a-request-to-a-cassette-track)
52+
- [Track mutators](#track-mutators)
53+
- [Cassette encryption](#cassette-encryption)
54+
- [Cookbook](#cookbook)
55+
- [Run the examples](#run-the-examples)
56+
- [Recipe: VCR with custom `http.Client`](#recipe-vcr-with-custom-httpclient)
57+
- [Recipe: Remove Response TLS](#recipe-remove-response-tls)
58+
- [Recipe: Change the playback mode of the VCR](#recipe-change-the-playback-mode-of-the-vcr)
59+
- [Normal HTTP mode](#normal-http-mode)
60+
- [Live only HTTP mode](#live-only-http-mode)
61+
- [Read only cassette mode](#read-only-cassette-mode)
62+
- [Offline HTTP mode](#offline-http-mode)
63+
- [Recipe: VCR with encrypted cassette](#recipe-vcr-with-encrypted-cassette)
64+
- [Recipe: VCR with encrypted cassette - custom nonce generator](#recipe-vcr-with-encrypted-cassette---custom-nonce-generator)
65+
- [Recipe: Cassette decryption](#recipe-cassette-decryption)
66+
- [Recipe: Changing cassette encryption](#recipe-changing-cassette-encryption)
67+
- [Recipe: VCR with cassette storage on AWS S3](#recipe-vcr-with-cassette-storage-on-aws-s3)
68+
- [Recipe: VCR with a custom RequestMatcher](#recipe-vcr-with-a-custom-requestmatcher)
69+
- [Recipe: VCR with a replaying Track Mutator](#recipe-vcr-with-a-replaying-track-mutator)
70+
- [Recipe: VCR with a recording Track Mutator](#recipe-vcr-with-a-recording-track-mutator)
71+
- [More](#more)
72+
- [Stats](#stats)
73+
- [Run the tests](#run-the-tests)
74+
- [Bugs](#bugs)
75+
- [Improvements](#improvements)
76+
- [Limitations](#limitations)
77+
- [Go empty interfaces (`interface{}` / `any`)](#go-empty-interfaces-interface--any)
78+
- [Support for multiple values in HTTP headers](#support-for-multiple-values-in-http-headers)
79+
- [HTTP transport errors](#http-transport-errors)
80+
- [Contribute](#contribute)
81+
- [Community Support Appeal](#community-support-appeal)
7382

7483
## Simple VCR example
7584

@@ -626,7 +635,7 @@ Objects cannot be created by name at runtime in Go. Rather than re-create the or
626635

627636
In practice, the implications for you depend on how much you care about the error type. If all you need to know is that an error occurred, you won't mind this limitation.
628637

629-
Mitigation: Support for common errors (network down) has been implemented. Support for more error types can be implemented, if there is appetite for it.
638+
Mitigation: Support for common errors (network down, dns failure, timeout) has been implemented. Support for more error types can be implemented, if there is appetite for it.
630639

631640
[(toc)](#table-of-content)
632641

cassette/cassette.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
)
2424

2525
// Cassette contains a set of tracks.
26-
// nolint: govet
26+
// nolint:govet
2727
type Cassette struct {
2828
Tracks []track.Track
2929

@@ -134,7 +134,7 @@ func (k7 *Cassette) NumberOfTracks() int32 {
134134
k7.trackSliceMutex.RLock()
135135
defer k7.trackSliceMutex.RUnlock()
136136

137-
return int32(len(k7.Tracks))
137+
return int32(len(k7.Tracks)) //nolint:gosec // int32 can more than sufficiently hold the number of tracks on a cassette.
138138
}
139139

140140
// ReplayTrack returns the specified track number, as recorded on cassette.
@@ -257,7 +257,7 @@ func (k7 *Cassette) EncryptionFilter(data []byte) ([]byte, error) {
257257
header = append(header, byte(nonceLen))
258258
header = append(header, nonce...)
259259

260-
// nolint: gocritic
260+
// nolint:gocritic
261261
eData := append(header, ciphertext...)
262262

263263
return eData, nil

cassette/track/http.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import (
1919
// with a RequestMatcher (albeit perfectly possible).
2020
// These fields also help when converting Response to http.Response to
2121
// populate http.Response.Request.
22-
// nolint: govet
22+
// nolint:govet
2323
type Request struct {
2424
Method string
2525
URL *url.URL
@@ -172,7 +172,7 @@ func ToRequest(httpRequest *http.Request) *Request {
172172
}
173173

174174
// Response is a track HTTP Response.
175-
// nolint: govet
175+
// nolint:govet
176176
type Response struct {
177177
Status string
178178
StatusCode int
@@ -270,13 +270,13 @@ func cloneTLS(tlsCS *tls.ConnectionState) *tls.ConnectionState {
270270
DidResume: tlsCS.DidResume,
271271
CipherSuite: tlsCS.CipherSuite,
272272
NegotiatedProtocol: tlsCS.NegotiatedProtocol,
273-
NegotiatedProtocolIsMutual: tlsCS.NegotiatedProtocolIsMutual, //nolint: staticcheck
273+
NegotiatedProtocolIsMutual: tlsCS.NegotiatedProtocolIsMutual, //nolint:staticcheck
274274
ServerName: tlsCS.ServerName,
275275
PeerCertificates: peerCertificatesClone,
276276
VerifiedChains: verifiedChainsClone,
277277
SignedCertificateTimestamps: signedCertificateTimestampsClone,
278278
OCSPResponse: []byte(string(tlsCS.OCSPResponse)),
279-
TLSUnique: []byte(string(tlsCS.TLSUnique)), //nolint: staticcheck
279+
TLSUnique: []byte(string(tlsCS.TLSUnique)), //nolint:staticcheck
280280
}
281281
}
282282

cassette/track/track.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"io"
77
"net"
88
"net/http"
9+
"os"
910

1011
"github.com/pkg/errors"
1112

@@ -73,14 +74,32 @@ func (trk *Track) ToErr() error {
7374
errMsg = *trk.ErrMsg
7475
}
7576

76-
if errType == "*net.OpError" {
77+
switch errType {
78+
case "*net.OpError":
7779
return &net.OpError{
7880
Op: "govcr",
7981
Net: "govcr",
8082
Source: nil,
8183
Addr: nil,
8284
Err: errors.WithStack(trkerr.NewErrTransportFailure(errType, errMsg)),
8385
}
86+
87+
case "*os.SyscallError":
88+
return &os.SyscallError{
89+
Syscall: errMsg,
90+
Err: errors.WithStack(trkerr.NewErrTransportFailure(errType, errMsg)),
91+
}
92+
93+
case "*net.DNSError":
94+
return &net.DNSError{
95+
UnwrapErr: errors.WithStack(trkerr.NewErrTransportFailure(errType, errMsg)),
96+
Err: errMsg,
97+
Name: "govcr",
98+
Server: "govcr",
99+
IsTimeout: false,
100+
IsTemporary: false,
101+
IsNotFound: false,
102+
}
84103
}
85104

86105
return errors.WithStack(trkerr.NewErrTransportFailure(errType, errMsg))
@@ -117,7 +136,7 @@ func (trk *Track) toHTTPRequest() *http.Request {
117136
}
118137

119138
// ToHTTPResponse converts the track Response to an http.Response.
120-
// nolint: gocritic
139+
// nolint:gocritic
121140
func (trk Track) ToHTTPResponse() *http.Response {
122141
if trk.Response == nil {
123142
return nil

concurrency_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func TestConcurrencySafety(t *testing.T) {
9797
// check outcome of the request
9898
expectedBody := generateBinaryBody(i1)
9999
if err := validateResponseForTestPlaybackOrder(resp, expectedBody); err != nil {
100-
t.Fatalf(err.Error())
100+
t.Fatal(err.Error())
101101
}
102102
}()
103103
})

controlpanel.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,5 +100,5 @@ func (controlPanel *ControlPanel) NumberOfTracks() int32 {
100100
}
101101

102102
func (controlPanel *ControlPanel) vcrTransport() *vcrTransport {
103-
return controlPanel.client.Transport.(*vcrTransport)
103+
return controlPanel.client.Transport.(*vcrTransport) //nolint:errcheck // either way, this would require a panic.
104104
}

encryption/.study/rsa.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
cryptoerr "github.com/seborama/govcr/v15/encryption/errors"
1515
)
1616

17-
// nolint: deadcode
17+
// nolint:deadcode
1818
// TODO: offer ability to supply the key via an environment variable in base64 format.
1919
func readSSHRSAPrivateKeyFile(privKeyFile, passphrase string) (rsaPrivKey *rsa.PrivateKey, sshSigner ssh.Signer, rsaPubKey *rsa.PublicKey, err error) {
2020
keyData, err := os.ReadFile(privKeyFile)
@@ -61,7 +61,7 @@ func readSSHRSAPrivateKeyFile(privKeyFile, passphrase string) (rsaPrivKey *rsa.P
6161
return rsaPrivKey, sshSigner, rsaPubKey, nil
6262
}
6363

64-
// nolint: deadcode
64+
// nolint:deadcode
6565
// TODO: offer ability to supply the key via an environment variable in base64 format.
6666
func readSSHRSAPublicKeyFile(pubKeyFile string) (*rsa.PublicKey, error) {
6767
keyData, err := os.ReadFile(pubKeyFile)

govcr_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ func (ts *GoVCRTestSuite) TestVCR_OfflineMode() {
294294
// we've run out of tracks on the cassette and we're in offline mode so we expect a transport error
295295
req, err := http.NewRequest(http.MethodGet, ts.testServer.URL, nil)
296296
ts.Require().NoError(err)
297-
resp, err := vcr.HTTPClient().Do(req) //nolint: bodyclose
297+
resp, err := vcr.HTTPClient().Do(req) //nolint:bodyclose
298298
ts.Require().Error(err)
299299
ts.Assert().Contains(err.Error(), "no track matched on cassette and offline mode is active")
300300
ts.Assert().Nil(resp)
@@ -338,7 +338,7 @@ func (ts *GoVCRTestSuite) TestRoundTrip_ReplaysError() {
338338
// execute HTTP call and record on cassette
339339
vcr := ts.newVCR(cassetteName, actionDeleteCassette)
340340

341-
resp, err := vcr.HTTPClient().Get(tc.reqURL) //nolint: bodyclose
341+
resp, err := vcr.HTTPClient().Get(tc.reqURL) //nolint:bodyclose
342342
ts.Require().Error(err)
343343
ts.EqualError(err, tc.wantErr)
344344
ts.Require().Nil(resp)
@@ -356,7 +356,7 @@ func (ts *GoVCRTestSuite) TestRoundTrip_ReplaysError() {
356356
vcr = ts.newVCR(cassetteName, actionKeepCassette)
357357
ts.EqualValues(1, vcr.NumberOfTracks())
358358

359-
resp, err = vcr.HTTPClient().Get(tc.reqURL) //nolint: bodyclose
359+
resp, err = vcr.HTTPClient().Get(tc.reqURL) //nolint:bodyclose
360360
ts.Require().Error(err)
361361
ts.EqualError(err, tc.wantVCRErr)
362362
ts.Require().Nil(resp)

govcr_wb_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ func (ts *GoVCRWBTestSuite) TestRoundTrip_RequestMatcherDoesNotMutateState() {
140140
req, err = http.NewRequest(http.MethodGet, ts.testServer.URL, nil)
141141
ts.Require().NoError(err)
142142

143-
resp2, err := vcr.HTTPClient().Do(req) //nolint: bodyclose
143+
resp2, err := vcr.HTTPClient().Do(req) //nolint:bodyclose
144144
ts.Require().NoError(err)
145145
defer func() { _ = resp.Body.Close() }()
146146

0 commit comments

Comments
 (0)