Browse Source

Fix tests and add Drone CI config

master
James Mills 2 years ago
parent
commit
54a3d14449
No known key found for this signature in database GPG Key ID: AC4C014F1440EBD6
6 changed files with 89 additions and 79 deletions
  1. +27
    -0
      .drone.yml
  2. +1
    -5
      README.md
  3. +1
    -0
      go.mod
  4. +4
    -0
      go.sum
  5. +1
    -32
      gopher.go
  6. +55
    -42
      gopher_test.go

+ 27
- 0
.drone.yml View File

@@ -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

+ 1
- 5
README.md View File

@@ -1,10 +1,6 @@
# Gopher protocol library for Golang # 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 This is a standards compliant Gopher library for the Go programming language
implementing the RFC 1436 specification. The library includes both client and implementing the RFC 1436 specification. The library includes both client and


+ 1
- 0
go.mod View File

@@ -2,6 +2,7 @@ module git.mills.io/prologic/go-gopher


require ( require (
github.com/davecgh/go-spew v1.1.1 // indirect 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 github.com/stretchr/testify v1.7.0
golang.org/x/net v0.0.0-20181220203305-927f97764cc3 golang.org/x/net v0.0.0-20181220203305-927f97764cc3
) )


+ 4
- 0
go.sum View File

@@ -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.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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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/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 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=


+ 1
- 32
gopher.go View File

@@ -26,8 +26,8 @@ import (
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"sync"


sync "github.com/sasha-s/go-deadlock"
"golang.org/x/net/context" "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. // LocalHost and LocalPort may be used by the Handler for local links.
// These are specified in the call to ListenAndServe. // These are specified in the call to ListenAndServe.
type Request struct { type Request struct {
conn net.Conn
Selector string Selector string
LocalHost string LocalHost string
LocalPort int LocalPort int
@@ -672,10 +671,6 @@ type conn struct {
// This is the value of a Handler's (*Request).RemoteAddr. // This is the value of a Handler's (*Request).RemoteAddr.
remoteAddr string 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 guards hijackedv, use of bufr, (*response).closeNotifyCh.
mu sync.Mutex mu sync.Mutex
} }
@@ -777,14 +772,6 @@ func (c *conn) readRequest(ctx context.Context) (w *response, err error) {
return w, nil 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 // ListenAndServe listens on the TCP network address addr
// and then calls Serve with handler to handle requests // and then calls Serve with handler to handle requests
// on incoming connections. // on incoming connections.
@@ -911,23 +898,6 @@ func selectorMatch(pattern, selector string) bool {
return len(selector) >= n && selector[0:n] == pattern 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 // Find a handler on a handler map given a path string
// Most-specific (longest) pattern wins // Most-specific (longest) pattern wins
func (mux *ServeMux) match(selector string) (h Handler, pattern string) { 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() defer ff.Close()
dd, err := ff.Stat() dd, err := ff.Stat()
if err == nil { if err == nil {
name = gophermap
d = dd d = dd
f = ff f = ff
} }


+ 55
- 42
gopher_test.go View File

@@ -3,17 +3,52 @@ package gopher_test
import ( import (
"fmt" "fmt"
"log" "log"
"net"
"os" "os"
"testing" "testing"
"time" "time"


"git.mills.io/prologic/go-gopher"
"github.com/stretchr/testify/assert" "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) { 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 // Because it can take some time for the server to spin up
// the tests are inconsistent - they'll fail if the server isn't // 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 // It seems like there should be a better way to do this
for attempts := 3; attempts > 0; attempts-- { 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 { if err == nil {
fmt.Println("Server ready")
log.Println("Server ready")
break 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) time.Sleep(1 * time.Second)
} }
/////


code := m.Run() code := m.Run()
os.Exit(code) os.Exit(code)
@@ -40,32 +74,6 @@ func hello(w gopher.ResponseWriter, r *gopher.Request) {
w.WriteInfo("Hello World!") 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() { func Example_client() {
res, err := gopher.Get("gopher://gopher.floodgap.com") res, err := gopher.Get("gopher://gopher.floodgap.com")
if err != nil { if err != nil {
@@ -86,27 +94,29 @@ func Example_fileserver() {


func TestGet(t *testing.T) { func TestGet(t *testing.T) {
assert := assert.New(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.Len(res.Dir.Items, 1)
assert.Equal(res.Dir.Items[0].Type, gopher.INFO) assert.Equal(res.Dir.Items[0].Type, gopher.INFO)
assert.Equal(res.Dir.Items[0].Description, "Hello World!") assert.Equal(res.Dir.Items[0].Description, "Hello World!")


out, err := res.Dir.ToText() out, err := res.Dir.ToText()
assert.NoError(err)
require.NoError(err)
assert.Equal(string(out), "iHello World!\t\terror.host\t1\r\n") assert.Equal(string(out), "iHello World!\t\terror.host\t1\r\n")
} }


func TestFileServer(t *testing.T) { func TestFileServer(t *testing.T) {
assert := assert.New(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) assert.Len(res.Dir.Items, 1)


json, err := res.Dir.ToJSON() json, err := res.Dir.ToJSON()
assert.Nil(err)
require.NoError(err)


log.Println(string(json)) log.Println(string(json))
assert.JSONEq( assert.JSONEq(
@@ -124,9 +134,10 @@ func TestParseItemNull(t *testing.T) {


func TestParseItem(t *testing.T) { func TestParseItem(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
require := require.New(t)


item, err := gopher.ParseItem("0foo\t/foo\tlocalhost\t70\r\n") item, err := gopher.ParseItem("0foo\t/foo\tlocalhost\t70\r\n")
assert.NoError(err)
require.NoError(err)
assert.NotNil(item) assert.NotNil(item)
assert.Equal(item, &gopher.Item{ assert.Equal(item, &gopher.Item{
Type: gopher.FILE, Type: gopher.FILE,
@@ -140,10 +151,11 @@ func TestParseItem(t *testing.T) {


func TestParseItemMarshal(t *testing.T) { func TestParseItemMarshal(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
require := require.New(t)


data := "0foo\t/foo\tlocalhost\t70\r\n" data := "0foo\t/foo\tlocalhost\t70\r\n"
item, err := gopher.ParseItem(data) item, err := gopher.ParseItem(data)
assert.NoError(err)
require.NoError(err)
assert.NotNil(item) assert.NotNil(item)
assert.Equal(item, &gopher.Item{ assert.Equal(item, &gopher.Item{
Type: gopher.FILE, Type: gopher.FILE,
@@ -161,10 +173,11 @@ func TestParseItemMarshal(t *testing.T) {


func TestParseItemMarshalIdempotency(t *testing.T) { func TestParseItemMarshalIdempotency(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
require := require.New(t)


data := "0" data := "0"
item, err := gopher.ParseItem(data) item, err := gopher.ParseItem(data)
assert.NoError(err)
require.NoError(err)
assert.NotNil(item) assert.NotNil(item)


data1, err := item.MarshalText() data1, err := item.MarshalText()


Loading…
Cancel
Save