-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Expose writer deadline as part of the ResponseWriter interface (#39)
* feat(writer): add support for SetWriteDeadline and SetReadDeadline * feat(writer): add support for SetWriteDeadline and SetReadDeadline * feat(writer): improve code coverage
- Loading branch information
1 parent
9172015
commit 07edc7e
Showing
3 changed files
with
327 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,287 @@ | ||
package fox | ||
|
||
import ( | ||
"bufio" | ||
"errors" | ||
"github.com/stretchr/testify/assert" | ||
"net" | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
"time" | ||
) | ||
|
||
type flushErrorWriterFunc func() error | ||
|
||
func (f flushErrorWriterFunc) FlushError() error { | ||
return f() | ||
} | ||
|
||
type flushWriterFunc func() | ||
|
||
func (f flushWriterFunc) Flush() { | ||
f() | ||
} | ||
|
||
type hijackWriterFunc func() (net.Conn, *bufio.ReadWriter, error) | ||
|
||
func (f hijackWriterFunc) Hijack() (net.Conn, *bufio.ReadWriter, error) { | ||
return f() | ||
} | ||
|
||
type pushWriterFunc func(target string, opts *http.PushOptions) error | ||
|
||
func (f pushWriterFunc) Push(target string, opts *http.PushOptions) error { | ||
return f(target, opts) | ||
} | ||
|
||
type deadlineWriterFunc func(deadline time.Time) error | ||
|
||
func (f deadlineWriterFunc) SetReadDeadline(deadline time.Time) error { | ||
return f(deadline) | ||
} | ||
|
||
func (f deadlineWriterFunc) SetWriteDeadline(deadline time.Time) error { | ||
return f(deadline) | ||
} | ||
|
||
func TestRecorder_FlushError(t *testing.T) { | ||
type flushError interface { | ||
FlushError() error | ||
} | ||
|
||
cases := []struct { | ||
name string | ||
rec *recorder | ||
assert func(t *testing.T, w ResponseWriter) | ||
}{ | ||
{ | ||
name: "implement FlushError and flush returns error", | ||
rec: &recorder{ | ||
ResponseWriter: struct { | ||
http.ResponseWriter | ||
flushError | ||
}{ | ||
ResponseWriter: httptest.NewRecorder(), | ||
flushError: flushErrorWriterFunc(func() error { | ||
return errors.New("error") | ||
}), | ||
}, | ||
}, | ||
assert: func(t *testing.T, w ResponseWriter) { | ||
assert.Error(t, w.FlushError()) | ||
}, | ||
}, | ||
{ | ||
name: "implement Flusher and flush return nil", | ||
rec: &recorder{ | ||
ResponseWriter: struct { | ||
http.ResponseWriter | ||
http.Flusher | ||
}{ | ||
ResponseWriter: httptest.NewRecorder(), | ||
Flusher: flushWriterFunc(func() {}), | ||
}, | ||
}, | ||
assert: func(t *testing.T, w ResponseWriter) { | ||
assert.Nil(t, w.FlushError()) | ||
}, | ||
}, | ||
{ | ||
name: "does not implement flusher and return http.ErrNotSupported", | ||
rec: &recorder{ | ||
ResponseWriter: struct { | ||
http.ResponseWriter | ||
}{ | ||
ResponseWriter: httptest.NewRecorder(), | ||
}, | ||
}, | ||
assert: func(t *testing.T, w ResponseWriter) { | ||
assert.ErrorIs(t, w.FlushError(), http.ErrNotSupported) | ||
}, | ||
}, | ||
} | ||
|
||
for _, tc := range cases { | ||
t.Run(tc.name, func(t *testing.T) { | ||
tc.assert(t, tc.rec) | ||
}) | ||
} | ||
} | ||
|
||
func TestRecorder_Hijack(t *testing.T) { | ||
cases := []struct { | ||
name string | ||
rec *recorder | ||
assert func(t *testing.T, w ResponseWriter) | ||
}{ | ||
{ | ||
name: "implements Hijacker and hijack returns no error", | ||
rec: &recorder{ | ||
ResponseWriter: struct { | ||
http.ResponseWriter | ||
http.Hijacker | ||
}{ | ||
ResponseWriter: httptest.NewRecorder(), | ||
Hijacker: hijackWriterFunc(func() (net.Conn, *bufio.ReadWriter, error) { | ||
return nil, nil, nil | ||
}), | ||
}, | ||
}, | ||
assert: func(t *testing.T, w ResponseWriter) { | ||
_, _, err := w.Hijack() | ||
assert.NoError(t, err) | ||
}, | ||
}, | ||
{ | ||
name: "does not implement Hijacker and return http.ErrNotSupported", | ||
rec: &recorder{ | ||
ResponseWriter: httptest.NewRecorder(), | ||
}, | ||
assert: func(t *testing.T, w ResponseWriter) { | ||
_, _, err := w.Hijack() | ||
assert.ErrorIs(t, err, http.ErrNotSupported) | ||
}, | ||
}, | ||
} | ||
|
||
for _, tc := range cases { | ||
t.Run(tc.name, func(t *testing.T) { | ||
tc.assert(t, tc.rec) | ||
}) | ||
} | ||
} | ||
|
||
func TestRecorder_Push(t *testing.T) { | ||
cases := []struct { | ||
name string | ||
rec *recorder | ||
assert func(t *testing.T, w ResponseWriter) | ||
}{ | ||
{ | ||
name: "implements Pusher and push returns no error", | ||
rec: &recorder{ | ||
ResponseWriter: struct { | ||
http.ResponseWriter | ||
http.Pusher | ||
}{ | ||
ResponseWriter: httptest.NewRecorder(), | ||
Pusher: pushWriterFunc(func(target string, opts *http.PushOptions) error { | ||
return nil | ||
}), | ||
}, | ||
}, | ||
assert: func(t *testing.T, w ResponseWriter) { | ||
assert.NoError(t, w.Push("/path", nil)) | ||
}, | ||
}, | ||
{ | ||
name: "does not implement Pusher and return http.ErrNotSupported", | ||
rec: &recorder{ | ||
ResponseWriter: httptest.NewRecorder(), | ||
}, | ||
assert: func(t *testing.T, w ResponseWriter) { | ||
err := w.Push("/path", nil) | ||
assert.ErrorIs(t, err, http.ErrNotSupported) | ||
}, | ||
}, | ||
} | ||
|
||
for _, tc := range cases { | ||
t.Run(tc.name, func(t *testing.T) { | ||
tc.assert(t, tc.rec) | ||
}) | ||
} | ||
} | ||
|
||
func TestRecorder_SetReadDeadline(t *testing.T) { | ||
type deadlineWriter interface { | ||
SetReadDeadline(time.Time) error | ||
} | ||
|
||
cases := []struct { | ||
name string | ||
rec *recorder | ||
assert func(t *testing.T, w ResponseWriter) | ||
}{ | ||
{ | ||
name: "implements SetReadDeadline and returns no error", | ||
rec: &recorder{ | ||
ResponseWriter: struct { | ||
http.ResponseWriter | ||
deadlineWriter | ||
}{ | ||
ResponseWriter: httptest.NewRecorder(), | ||
deadlineWriter: deadlineWriterFunc(func(deadline time.Time) error { | ||
return nil | ||
}), | ||
}, | ||
}, | ||
assert: func(t *testing.T, w ResponseWriter) { | ||
assert.NoError(t, w.SetReadDeadline(time.Now())) | ||
}, | ||
}, | ||
{ | ||
name: "does not implement SetReadDeadline and returns http.ErrNotSupported", | ||
rec: &recorder{ | ||
ResponseWriter: httptest.NewRecorder(), | ||
}, | ||
assert: func(t *testing.T, w ResponseWriter) { | ||
err := w.SetReadDeadline(time.Now()) | ||
assert.ErrorIs(t, err, http.ErrNotSupported) | ||
}, | ||
}, | ||
} | ||
|
||
for _, tc := range cases { | ||
t.Run(tc.name, func(t *testing.T) { | ||
tc.assert(t, tc.rec) | ||
}) | ||
} | ||
} | ||
|
||
func TestRecorder_SetWriteDeadline(t *testing.T) { | ||
type deadlineWriter interface { | ||
SetWriteDeadline(time.Time) error | ||
} | ||
|
||
cases := []struct { | ||
name string | ||
rec *recorder | ||
assert func(t *testing.T, w ResponseWriter) | ||
}{ | ||
{ | ||
name: "implements SetWriteDeadline and returns no error", | ||
rec: &recorder{ | ||
ResponseWriter: struct { | ||
http.ResponseWriter | ||
deadlineWriter | ||
}{ | ||
ResponseWriter: httptest.NewRecorder(), | ||
deadlineWriter: deadlineWriterFunc(func(deadline time.Time) error { | ||
return nil | ||
}), | ||
}, | ||
}, | ||
assert: func(t *testing.T, w ResponseWriter) { | ||
assert.NoError(t, w.SetWriteDeadline(time.Now())) | ||
}, | ||
}, | ||
{ | ||
name: "does not implement SetWriteDeadline and returns http.ErrNotSupported", | ||
rec: &recorder{ | ||
ResponseWriter: httptest.NewRecorder(), | ||
}, | ||
assert: func(t *testing.T, w ResponseWriter) { | ||
err := w.SetWriteDeadline(time.Now()) | ||
assert.ErrorIs(t, err, http.ErrNotSupported) | ||
}, | ||
}, | ||
} | ||
|
||
for _, tc := range cases { | ||
t.Run(tc.name, func(t *testing.T) { | ||
tc.assert(t, tc.rec) | ||
}) | ||
} | ||
} |