mirror of
https://github.com/adnanh/webhook.git
synced 2025-05-14 17:44:42 +00:00
tests: add test for the -socket option
Refactored webhook_test so that the test HTTP requests are made using an explicitly-provided http.Client, so we can run at least one test with the server bound to a socket instead of a port number, using an http.Client whose transport has been configured with a suitable Unix-domain or Windows named pipe dialer function.
This commit is contained in:
parent
596cc5e70c
commit
c72da0b125
3 changed files with 173 additions and 85 deletions
30
testutils.go
Normal file
30
testutils.go
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
|
||||||
|
func prepareTestSocket(_ string) (socketPath string, transport *http.Transport, cleanup func(), err error) {
|
||||||
|
tmp, err := ioutil.TempDir("", "webhook-socket-")
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, nil, err
|
||||||
|
}
|
||||||
|
cleanup = func() { os.RemoveAll(tmp) }
|
||||||
|
socketPath = path.Join(tmp, "webhook.sock")
|
||||||
|
socketDialer := &net.Dialer{}
|
||||||
|
transport = &http.Transport{
|
||||||
|
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
|
||||||
|
return socketDialer.DialContext(ctx, "unix", socketPath)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return socketPath, transport, cleanup, nil
|
||||||
|
}
|
22
testutils_windows.go
Normal file
22
testutils_windows.go
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
//go:build windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/Microsoft/go-winio"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func prepareTestSocket(hookTmpl string) (socketPath string, transport *http.Transport, cleanup func(), err error) {
|
||||||
|
socketPath = "\\\\.\\pipe\\webhook-" + hookTmpl
|
||||||
|
transport = &http.Transport{
|
||||||
|
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
|
||||||
|
return winio.DialPipeContext(ctx, socketPath)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return socketPath, transport, nil, nil
|
||||||
|
}
|
|
@ -79,10 +79,9 @@ func TestWebhook(t *testing.T) {
|
||||||
configPath, cleanupConfigFn := genConfig(t, hookecho, hookTmpl)
|
configPath, cleanupConfigFn := genConfig(t, hookecho, hookTmpl)
|
||||||
defer cleanupConfigFn()
|
defer cleanupConfigFn()
|
||||||
|
|
||||||
for _, tt := range hookHandlerTests {
|
runTest := func(t *testing.T, tt hookHandlerTest, authority string, bindArgs []string, httpClient *http.Client) {
|
||||||
t.Run(tt.desc+"@"+hookTmpl, func(t *testing.T) {
|
args := []string{fmt.Sprintf("-hooks=%s", configPath), "-debug"}
|
||||||
ip, port := serverAddress(t)
|
args = append(args, bindArgs...)
|
||||||
args := []string{fmt.Sprintf("-hooks=%s", configPath), fmt.Sprintf("-ip=%s", ip), fmt.Sprintf("-port=%s", port), "-debug"}
|
|
||||||
|
|
||||||
if len(tt.cliMethods) != 0 {
|
if len(tt.cliMethods) != 0 {
|
||||||
args = append(args, "-http-methods="+strings.Join(tt.cliMethods, ","))
|
args = append(args, "-http-methods="+strings.Join(tt.cliMethods, ","))
|
||||||
|
@ -100,9 +99,9 @@ func TestWebhook(t *testing.T) {
|
||||||
}
|
}
|
||||||
defer killAndWait(cmd)
|
defer killAndWait(cmd)
|
||||||
|
|
||||||
waitForServerReady(t, ip, port)
|
waitForServerReady(t, authority, httpClient)
|
||||||
|
|
||||||
url := fmt.Sprintf("http://%s:%s/hooks/%s", ip, port, tt.id)
|
url := fmt.Sprintf("http://%s/hooks/%s", authority, tt.id)
|
||||||
|
|
||||||
req, err := http.NewRequest(tt.method, url, ioutil.NopCloser(strings.NewReader(tt.body)))
|
req, err := http.NewRequest(tt.method, url, ioutil.NopCloser(strings.NewReader(tt.body)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -118,8 +117,7 @@ func TestWebhook(t *testing.T) {
|
||||||
req.Header.Add("Content-Type", tt.contentType)
|
req.Header.Add("Content-Type", tt.contentType)
|
||||||
req.ContentLength = int64(len(tt.body))
|
req.ContentLength = int64(len(tt.body))
|
||||||
|
|
||||||
client := &http.Client{}
|
res, err = httpClient.Do(req)
|
||||||
res, err = client.Do(req)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("client.Do failed: %s", err)
|
t.Errorf("client.Do failed: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -160,8 +158,43 @@ func TestWebhook(t *testing.T) {
|
||||||
if !matched {
|
if !matched {
|
||||||
t.Errorf("failed log match for %q (id: %s):\nmatch pattern: %q\ngot:\n%s", tt.desc, tt.id, tt.logMatch, b)
|
t.Errorf("failed log match for %q (id: %s):\nmatch pattern: %q\ngot:\n%s", tt.desc, tt.id, tt.logMatch, b)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
for _, tt := range hookHandlerTests {
|
||||||
|
ip, port := serverAddress(t)
|
||||||
|
|
||||||
|
t.Run(tt.desc+"@"+hookTmpl, func(t *testing.T) {
|
||||||
|
runTest(t, tt, fmt.Sprintf("%s:%s", ip, port),
|
||||||
|
[]string{
|
||||||
|
fmt.Sprintf("-ip=%s", ip),
|
||||||
|
fmt.Sprintf("-port=%s", port),
|
||||||
|
},
|
||||||
|
&http.Client{},
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// run a single test using socket rather than TCP binding - wrap in an
|
||||||
|
// anonymous function so the deferred cleanup happens at the right time
|
||||||
|
func() {
|
||||||
|
socketPath, transport, cleanup, err := prepareTestSocket(hookTmpl)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if cleanup != nil {
|
||||||
|
defer cleanup()
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := hookHandlerTests[0]
|
||||||
|
t.Run(tt.desc+":socket@"+hookTmpl, func(t *testing.T) {
|
||||||
|
runTest(t, tt, "socket",
|
||||||
|
[]string{
|
||||||
|
fmt.Sprintf("-socket=%s", socketPath),
|
||||||
|
},
|
||||||
|
&http.Client{
|
||||||
|
Transport: transport,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,20 +296,21 @@ func serverAddress(t *testing.T) (string, string) {
|
||||||
return host, port
|
return host, port
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForServerReady(t *testing.T, ip, port string) {
|
func waitForServerReady(t *testing.T, authority string, httpClient *http.Client) {
|
||||||
waitForServer(t,
|
waitForServer(t,
|
||||||
fmt.Sprintf("http://%v:%v/", ip, port),
|
httpClient,
|
||||||
|
fmt.Sprintf("http://%s/", authority),
|
||||||
http.StatusOK,
|
http.StatusOK,
|
||||||
5*time.Second)
|
5*time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
const pollInterval = 200 * time.Millisecond
|
const pollInterval = 200 * time.Millisecond
|
||||||
|
|
||||||
func waitForServer(t *testing.T, url string, status int, timeout time.Duration) {
|
func waitForServer(t *testing.T, httpClient *http.Client, url string, status int, timeout time.Duration) {
|
||||||
deadline := time.Now().Add(timeout)
|
deadline := time.Now().Add(timeout)
|
||||||
for time.Now().Before(deadline) {
|
for time.Now().Before(deadline) {
|
||||||
time.Sleep(pollInterval)
|
time.Sleep(pollInterval)
|
||||||
res, err := http.Get(url)
|
res, err := httpClient.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -308,7 +342,7 @@ func webhookEnv() (env []string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var hookHandlerTests = []struct {
|
type hookHandlerTest struct {
|
||||||
desc string
|
desc string
|
||||||
id string
|
id string
|
||||||
cliMethods []string
|
cliMethods []string
|
||||||
|
@ -321,7 +355,9 @@ var hookHandlerTests = []struct {
|
||||||
respStatus int
|
respStatus int
|
||||||
respBody string
|
respBody string
|
||||||
logMatch string
|
logMatch string
|
||||||
}{
|
}
|
||||||
|
|
||||||
|
var hookHandlerTests = []hookHandlerTest{
|
||||||
{
|
{
|
||||||
"github",
|
"github",
|
||||||
"github",
|
"github",
|
||||||
|
|
Loading…
Add table
Reference in a new issue