diff --git a/webhook/forward.go b/webhook/forward.go index f313903..0983629 100644 --- a/webhook/forward.go +++ b/webhook/forward.go @@ -27,8 +27,9 @@ func NewCmdForward() *cobra.Command { ) cmd := &cobra.Command{ - Use: "forward --events= [--url=]", - Short: "Receive test events locally", + Use: "forward --events= [--url=]", + Short: "Receive test events locally", + SilenceUsage: true, Example: heredoc.Doc(` # create a dev webhook for the 'issue_open' event in the monalisa/smile repo in GitHub running locally, and # forward payloads for the triggered event to http://localhost:9999/webhooks @@ -90,10 +91,10 @@ func runFwd(out io.Writer, url, token, wsURL string, activateHook func() error) err := handleWebsocket(out, url, token, wsURL, activateHook) if err != nil { // If the error is a server disconnect (1006), retry connecting - if websocket.IsCloseError(err, websocket.CloseAbnormalClosure) { + if isWebsocketCloseError(err, websocket.CloseAbnormalClosure) { time.Sleep(5 * time.Second) continue - } else if websocket.IsCloseError(err, websocket.CloseNormalClosure) { + } else if isWebsocketCloseError(err, websocket.CloseNormalClosure) { return nil } return err @@ -102,6 +103,11 @@ func runFwd(out io.Writer, url, token, wsURL string, activateHook func() error) return fmt.Errorf("unable to connect to webhooks server, forwarding stopped") } +func isWebsocketCloseError(err error, code int) bool { + var closeError *websocket.CloseError + return errors.As(err, &closeError) && closeError.Code == code +} + // handleWebsocket mediates between websocket server and local web server func handleWebsocket(out io.Writer, url, token, wsURL string, activateHook func() error) error { c, err := dial(token, wsURL) diff --git a/webhook/forward_test.go b/webhook/forward_test.go new file mode 100644 index 0000000..b295cd4 --- /dev/null +++ b/webhook/forward_test.go @@ -0,0 +1,38 @@ +package webhook + +import ( + "fmt" + "testing" + + "github.com/gorilla/websocket" +) + +func TestNewCmdForwardSilencesUsage(t *testing.T) { + cmd := NewCmdForward() + + if !cmd.SilenceUsage { + t.Fatal("expected runtime errors not to print command usage") + } +} + +func TestIsWebsocketCloseErrorUnwrapsError(t *testing.T) { + err := fmt.Errorf( + "error receiving json event: %w", + &websocket.CloseError{Code: websocket.CloseAbnormalClosure}, + ) + + if !isWebsocketCloseError(err, websocket.CloseAbnormalClosure) { + t.Fatal("expected wrapped abnormal closure to be recognized") + } +} + +func TestIsWebsocketCloseErrorRejectsDifferentCode(t *testing.T) { + err := fmt.Errorf( + "error receiving json event: %w", + &websocket.CloseError{Code: websocket.CloseNormalClosure}, + ) + + if isWebsocketCloseError(err, websocket.CloseAbnormalClosure) { + t.Fatal("expected close error with a different code not to match") + } +}