From 54a3d144498cc8b8b4e07d62b9f7b4464ae668e1 Mon Sep 17 00:00:00 2001 From: James Mills Date: Fri, 1 Apr 2022 00:02:21 +1000 Subject: [PATCH] Fix tests and add Drone CI config --- .drone.yml | 27 ++++++++++++++ README.md | 6 +--- go.mod | 1 + go.sum | 4 +++ gopher.go | 33 +---------------- gopher_test.go | 97 ++++++++++++++++++++++++++++---------------------- 6 files changed, 89 insertions(+), 79 deletions(-) create mode 100644 .drone.yml diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..74426b1 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,27 @@ +--- +kind: pipeline +name: default + +steps: + - name: build-and-test + image: r.mills.io/prologic/golang-alpine:latest + commands: + - go test + + - name: notify-irc + image: plugins/webhook + settings: + urls: + - https://msgbus.mills.io/ci.mills.io + when: + status: + - success + - failure + +trigger: + branch: + - main + event: + - tag + - push + - pull_request diff --git a/README.md b/README.md index 7eab1a4..ad0c343 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,6 @@ # Gopher protocol library for Golang -[![Build Status](https://cloud.drone.io/api/badges/prologic/go-gopher/status.svg)](https://cloud.drone.io/prologic/go-gopher) -[![CodeCov](https://codecov.io/gh/prologic/go-gopher/branch/master/graph/badge.svg)](https://codecov.io/gh/prologic/go-gopher) -[![Go Report Card](https://goreportcard.com/badge/prologic/go-gopher)](https://goreportcard.com/report/prologic/go-gopher) -[![GoDoc](https://godoc.org/git.mills.io/prologic/go-gopher?status.svg)](https://godoc.org/git.mills.io/prologic/go-gopher) -[![Sourcegraph](https://sourcegraph.com/git.mills.io/prologic/go-gopher/-/badge.svg)](https://sourcegraph.com/git.mills.io/prologic/go-gopher?badge) +[![Build Status](https://ci.mills.io/api/badges/prologic/go-gopher/status.svg)](https://ci.mills.io/prologic/go-gopher) This is a standards compliant Gopher library for the Go programming language implementing the RFC 1436 specification. The library includes both client and diff --git a/go.mod b/go.mod index 1a0e4ef..7f1692a 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,7 @@ module git.mills.io/prologic/go-gopher require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/sasha-s/go-deadlock v0.3.1 github.com/stretchr/testify v1.7.0 golang.org/x/net v0.0.0-20181220203305-927f97764cc3 ) diff --git a/go.sum b/go.sum index e2dfe40..1fe6245 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,12 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= +github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= diff --git a/gopher.go b/gopher.go index 875e8bc..de9e1d4 100644 --- a/gopher.go +++ b/gopher.go @@ -26,8 +26,8 @@ import ( "sort" "strconv" "strings" - "sync" + sync "github.com/sasha-s/go-deadlock" "golang.org/x/net/context" ) @@ -437,7 +437,6 @@ func (i *Item) FetchDirectory() (Directory, error) { // LocalHost and LocalPort may be used by the Handler for local links. // These are specified in the call to ListenAndServe. type Request struct { - conn net.Conn Selector string LocalHost string LocalPort int @@ -672,10 +671,6 @@ type conn struct { // This is the value of a Handler's (*Request).RemoteAddr. remoteAddr string - // tlsState is the TLS connection state when using TLS. - // nil means not TLS. - tlsState *tls.ConnectionState - // mu guards hijackedv, use of bufr, (*response).closeNotifyCh. mu sync.Mutex } @@ -777,14 +772,6 @@ func (c *conn) readRequest(ctx context.Context) (w *response, err error) { return w, nil } -func (s *Server) logf(format string, args ...interface{}) { - if s.ErrorLog != nil { - s.ErrorLog.Printf(format, args...) - } else { - log.Printf(format, args...) - } -} - // ListenAndServe listens on the TCP network address addr // and then calls Serve with handler to handle requests // on incoming connections. @@ -911,23 +898,6 @@ func selectorMatch(pattern, selector string) bool { return len(selector) >= n && selector[0:n] == pattern } -// Return the canonical path for p, eliminating . and .. elements. -func cleanPath(p string) string { - if p == "" { - return "/" - } - if p[0] != '/' { - p = "/" + p - } - np := path.Clean(p) - // path.Clean removes trailing slash except for root; - // put the trailing slash back if necessary. - if p[len(p)-1] == '/' && np != "/" { - np += "/" - } - return np -} - // Find a handler on a handler map given a path string // Most-specific (longest) pattern wins func (mux *ServeMux) match(selector string) (h Handler, pattern string) { @@ -1342,7 +1312,6 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string) { defer ff.Close() dd, err := ff.Stat() if err == nil { - name = gophermap d = dd f = ff } diff --git a/gopher_test.go b/gopher_test.go index 94f51f1..ae60b7c 100644 --- a/gopher_test.go +++ b/gopher_test.go @@ -3,17 +3,52 @@ package gopher_test import ( "fmt" "log" + "net" "os" "testing" "time" - "git.mills.io/prologic/go-gopher" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "git.mills.io/prologic/go-gopher" ) +var ( + testHost string = "localhost" + testPort int +) + +func pickUnusedPort() (int, error) { + addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:0") + if err != nil { + return 0, err + } + + l, err := net.ListenTCP("tcp", addr) + if err != nil { + return 0, err + } + port := l.Addr().(*net.TCPAddr).Port + if err := l.Close(); err != nil { + return 0, err + } + return port, nil +} + func TestMain(m *testing.M) { - ch := startTestServer() - defer stopTestServer(ch) + port, err := pickUnusedPort() + if err != nil { + log.Fatalf("error finding a free port: %s", err) + } + testPort = port + + go func() { + gopher.Handle("/", gopher.FileServer(gopher.Dir("./testdata"))) + gopher.HandleFunc("/hello", hello) + log.Printf("Test server starting on :%d\n", testPort) + log.Fatal(gopher.ListenAndServe(fmt.Sprintf(":%d", testPort), nil)) + }() // Because it can take some time for the server to spin up // the tests are inconsistent - they'll fail if the server isn't @@ -22,15 +57,14 @@ func TestMain(m *testing.M) { // // It seems like there should be a better way to do this for attempts := 3; attempts > 0; attempts-- { - _, err := gopher.Get("gopher://localhost:7000") + _, err := gopher.Get(fmt.Sprintf("gopher://%s:%d", testHost, testPort)) if err == nil { - fmt.Println("Server ready") + log.Println("Server ready") break } - fmt.Printf("Server not ready, going to try again in a sec. %v", err) + log.Printf("Server not ready, going to try again in a sec. %v\n", err) time.Sleep(1 * time.Second) } - ///// code := m.Run() os.Exit(code) @@ -40,32 +74,6 @@ func hello(w gopher.ResponseWriter, r *gopher.Request) { w.WriteInfo("Hello World!") } -func startTestServer() chan bool { - quit := make(chan bool) - go func() { - for { - select { - case <-quit: - return - default: - gopher.Handle("/", gopher.FileServer(gopher.Dir("./testdata"))) - gopher.HandleFunc("/hello", hello) - log.Println("Test server starting on 7000") - err := gopher.ListenAndServe("localhost:7000", nil) - if err != nil { - log.Fatal(err) - } - } - } - }() - - return quit -} - -func stopTestServer(c chan bool) { - c <- true -} - func Example_client() { res, err := gopher.Get("gopher://gopher.floodgap.com") if err != nil { @@ -86,27 +94,29 @@ func Example_fileserver() { func TestGet(t *testing.T) { assert := assert.New(t) + require := require.New(t) - res, err := gopher.Get("gopher://localhost:7000/1hello") - assert.NoError(err) + res, err := gopher.Get(fmt.Sprintf("gopher://%s:%d/1hello", testHost, testPort)) + require.NoError(err) assert.Len(res.Dir.Items, 1) assert.Equal(res.Dir.Items[0].Type, gopher.INFO) assert.Equal(res.Dir.Items[0].Description, "Hello World!") out, err := res.Dir.ToText() - assert.NoError(err) + require.NoError(err) assert.Equal(string(out), "iHello World!\t\terror.host\t1\r\n") } func TestFileServer(t *testing.T) { assert := assert.New(t) + require := require.New(t) - res, err := gopher.Get("gopher://localhost:7000/") - assert.NoError(err) + res, err := gopher.Get(fmt.Sprintf("gopher://%s:%d/", testHost, testPort)) + require.NoError(err) assert.Len(res.Dir.Items, 1) json, err := res.Dir.ToJSON() - assert.Nil(err) + require.NoError(err) log.Println(string(json)) assert.JSONEq( @@ -124,9 +134,10 @@ func TestParseItemNull(t *testing.T) { func TestParseItem(t *testing.T) { assert := assert.New(t) + require := require.New(t) item, err := gopher.ParseItem("0foo\t/foo\tlocalhost\t70\r\n") - assert.NoError(err) + require.NoError(err) assert.NotNil(item) assert.Equal(item, &gopher.Item{ Type: gopher.FILE, @@ -140,10 +151,11 @@ func TestParseItem(t *testing.T) { func TestParseItemMarshal(t *testing.T) { assert := assert.New(t) + require := require.New(t) data := "0foo\t/foo\tlocalhost\t70\r\n" item, err := gopher.ParseItem(data) - assert.NoError(err) + require.NoError(err) assert.NotNil(item) assert.Equal(item, &gopher.Item{ Type: gopher.FILE, @@ -161,10 +173,11 @@ func TestParseItemMarshal(t *testing.T) { func TestParseItemMarshalIdempotency(t *testing.T) { assert := assert.New(t) + require := require.New(t) data := "0" item, err := gopher.ParseItem(data) - assert.NoError(err) + require.NoError(err) assert.NotNil(item) data1, err := item.MarshalText()