Fix tests and add Drone CI config
This commit is contained in:
parent
44dd1c17a0
commit
54a3d14449
27
.drone.yml
Normal file
27
.drone.yml
Normal 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,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)
|
[![Build Status](https://ci.mills.io/api/badges/prologic/go-gopher/status.svg)](https://ci.mills.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)
|
|
||||||
|
|
||||||
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
go.mod
1
go.mod
@ -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
go.sum
4
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.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=
|
||||||
|
33
gopher.go
33
gopher.go
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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()
|
port, err := pickUnusedPort()
|
||||||
defer stopTestServer(ch)
|
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")
|
res, err := gopher.Get(fmt.Sprintf("gopher://%s:%d/1hello", testHost, testPort))
|
||||||
assert.NoError(err)
|
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/")
|
res, err := gopher.Get(fmt.Sprintf("gopher://%s:%d/", testHost, testPort))
|
||||||
assert.NoError(err)
|
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…
Reference in New Issue
Block a user