mirror of
https://github.com/binwiederhier/ntfy.git
synced 2024-11-21 19:03:26 +01:00
Tests for cliet package
This commit is contained in:
parent
6a7e9071b6
commit
fe5734d9f0
8 changed files with 162 additions and 43 deletions
23
Makefile
23
Makefile
|
@ -1,4 +1,3 @@
|
||||||
GO=$(shell which go)
|
|
||||||
VERSION := $(shell git describe --tag)
|
VERSION := $(shell git describe --tag)
|
||||||
|
|
||||||
.PHONY:
|
.PHONY:
|
||||||
|
@ -50,20 +49,20 @@ docs: docs-deps
|
||||||
check: test fmt-check vet lint staticcheck
|
check: test fmt-check vet lint staticcheck
|
||||||
|
|
||||||
test: .PHONY
|
test: .PHONY
|
||||||
$(GO) test -v ./...
|
go test -v $(shell go list ./... | grep -vE 'ntfy/(test|examples|tools)')
|
||||||
|
|
||||||
race: .PHONY
|
race: .PHONY
|
||||||
$(GO) test -race ./...
|
go test -race $(shell go list ./... | grep -vE 'ntfy/(test|examples|tools)')
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
mkdir -p build/coverage
|
mkdir -p build/coverage
|
||||||
$(GO) test -race -coverprofile=build/coverage/coverage.txt -covermode=atomic ./...
|
go test -race -coverprofile=build/coverage/coverage.txt -covermode=atomic $(shell go list ./... | grep -vE 'ntfy/(test|examples|tools)')
|
||||||
$(GO) tool cover -func build/coverage/coverage.txt
|
go tool cover -func build/coverage/coverage.txt
|
||||||
|
|
||||||
coverage-html:
|
coverage-html:
|
||||||
mkdir -p build/coverage
|
mkdir -p build/coverage
|
||||||
$(GO) test -race -coverprofile=build/coverage/coverage.txt -covermode=atomic ./...
|
go test -race -coverprofile=build/coverage/coverage.txt -covermode=atomic $(shell go list ./... | grep -vE 'ntfy/(test|examples|tools)')
|
||||||
$(GO) tool cover -html build/coverage/coverage.txt
|
go tool cover -html build/coverage/coverage.txt
|
||||||
|
|
||||||
coverage-upload:
|
coverage-upload:
|
||||||
cd build/coverage && (curl -s https://codecov.io/bash | bash)
|
cd build/coverage && (curl -s https://codecov.io/bash | bash)
|
||||||
|
@ -78,17 +77,17 @@ fmt-check:
|
||||||
test -z $(shell gofmt -l .)
|
test -z $(shell gofmt -l .)
|
||||||
|
|
||||||
vet:
|
vet:
|
||||||
$(GO) vet ./...
|
go vet ./...
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
which golint || $(GO) get -u golang.org/x/lint/golint
|
which golint || go get -u golang.org/x/lint/golint
|
||||||
$(GO) list ./... | grep -v /vendor/ | xargs -L1 golint -set_exit_status
|
go list ./... | grep -v /vendor/ | xargs -L1 golint -set_exit_status
|
||||||
|
|
||||||
staticcheck: .PHONY
|
staticcheck: .PHONY
|
||||||
rm -rf build/staticcheck
|
rm -rf build/staticcheck
|
||||||
which staticcheck || go install honnef.co/go/tools/cmd/staticcheck@latest
|
which staticcheck || go install honnef.co/go/tools/cmd/staticcheck@latest
|
||||||
mkdir -p build/staticcheck
|
mkdir -p build/staticcheck
|
||||||
ln -s "$(GO)" build/staticcheck/go
|
ln -s "go" build/staticcheck/go
|
||||||
PATH="$(PWD)/build/staticcheck:$(PATH)" staticcheck ./...
|
PATH="$(PWD)/build/staticcheck:$(PATH)" staticcheck ./...
|
||||||
rm -rf build/staticcheck
|
rm -rf build/staticcheck
|
||||||
|
|
||||||
|
@ -108,7 +107,7 @@ build-snapshot: build-deps
|
||||||
build-simple: clean
|
build-simple: clean
|
||||||
mkdir -p dist/ntfy_linux_amd64
|
mkdir -p dist/ntfy_linux_amd64
|
||||||
export CGO_ENABLED=1
|
export CGO_ENABLED=1
|
||||||
$(GO) build \
|
go build \
|
||||||
-o dist/ntfy_linux_amd64/ntfy \
|
-o dist/ntfy_linux_amd64/ntfy \
|
||||||
-tags sqlite_omit_load_extension,osusergo,netgo \
|
-tags sqlite_omit_load_extension,osusergo,netgo \
|
||||||
-ldflags \
|
-ldflags \
|
||||||
|
|
|
@ -35,7 +35,7 @@ type Client struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message is a struct that represents a ntfy message
|
// Message is a struct that represents a ntfy message
|
||||||
type Message struct {
|
type Message struct { // TODO combine with server.message
|
||||||
ID string
|
ID string
|
||||||
Event string
|
Event string
|
||||||
Time int64
|
Time int64
|
||||||
|
@ -60,7 +60,7 @@ type subscription struct {
|
||||||
// New creates a new Client using a given Config
|
// New creates a new Client using a given Config
|
||||||
func New(config *Config) *Client {
|
func New(config *Config) *Client {
|
||||||
return &Client{
|
return &Client{
|
||||||
Messages: make(chan *Message),
|
Messages: make(chan *Message, 50), // Allow reading a few messages
|
||||||
config: config,
|
config: config,
|
||||||
subscriptions: make(map[string]*subscription),
|
subscriptions: make(map[string]*subscription),
|
||||||
}
|
}
|
||||||
|
@ -237,7 +237,9 @@ func performSubscribeRequest(ctx context.Context, msgChan chan *Message, topicUR
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
msgChan <- m
|
if m.Event == MessageEvent {
|
||||||
|
msgChan <- m
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,42 +1,78 @@
|
||||||
package client_test
|
package client_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"heckel.io/ntfy/client"
|
"heckel.io/ntfy/client"
|
||||||
"heckel.io/ntfy/server"
|
"heckel.io/ntfy/test"
|
||||||
"net/http"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestClient_Publish(t *testing.T) {
|
func TestClient_Publish_Subscribe(t *testing.T) {
|
||||||
s := startTestServer(t)
|
s, port := test.StartServer(t)
|
||||||
defer s.Stop()
|
defer test.StopServer(t, s, port)
|
||||||
c := client.New(newTestConfig())
|
c := client.New(newTestConfig(port))
|
||||||
|
|
||||||
time.Sleep(time.Second) // FIXME Wait for port up
|
subscriptionID := c.Subscribe("mytopic")
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
_, err := c.Publish("mytopic", "some message")
|
msg, err := c.Publish("mytopic", "some message")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, "some message", msg.Message)
|
||||||
|
|
||||||
|
msg, err = c.Publish("mytopic", "some other message",
|
||||||
|
client.WithTitle("some title"),
|
||||||
|
client.WithPriority("high"),
|
||||||
|
client.WithTags([]string{"tag1", "tag 2"}))
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, "some other message", msg.Message)
|
||||||
|
require.Equal(t, "some title", msg.Title)
|
||||||
|
require.Equal(t, []string{"tag1", "tag 2"}, msg.Tags)
|
||||||
|
require.Equal(t, 4, msg.Priority)
|
||||||
|
|
||||||
|
msg, err = c.Publish("mytopic", "some delayed message",
|
||||||
|
client.WithDelay("25 hours"))
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, "some delayed message", msg.Message)
|
||||||
|
require.True(t, time.Now().Add(24*time.Hour).Unix() < msg.Time)
|
||||||
|
|
||||||
|
msg = nextMessage(c)
|
||||||
|
require.NotNil(t, msg)
|
||||||
|
require.Equal(t, "some message", msg.Message)
|
||||||
|
|
||||||
|
msg = nextMessage(c)
|
||||||
|
require.NotNil(t, msg)
|
||||||
|
require.Equal(t, "some other message", msg.Message)
|
||||||
|
require.Equal(t, "some title", msg.Title)
|
||||||
|
require.Equal(t, []string{"tag1", "tag 2"}, msg.Tags)
|
||||||
|
require.Equal(t, 4, msg.Priority)
|
||||||
|
|
||||||
|
msg = nextMessage(c)
|
||||||
|
require.Nil(t, msg)
|
||||||
|
|
||||||
|
c.Unsubscribe(subscriptionID)
|
||||||
|
time.Sleep(200 * time.Millisecond)
|
||||||
|
|
||||||
|
msg, err = c.Publish("mytopic", "a message that won't be received")
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, "a message that won't be received", msg.Message)
|
||||||
|
|
||||||
|
msg = nextMessage(c)
|
||||||
|
require.Nil(t, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestConfig() *client.Config {
|
func newTestConfig(port int) *client.Config {
|
||||||
c := client.NewConfig()
|
c := client.NewConfig()
|
||||||
c.DefaultHost = "http://127.0.0.1:12345"
|
c.DefaultHost = fmt.Sprintf("http://127.0.0.1:%d", port)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func startTestServer(t *testing.T) *server.Server {
|
func nextMessage(c *client.Client) *client.Message {
|
||||||
conf := server.NewConfig()
|
select {
|
||||||
conf.ListenHTTP = ":12345"
|
case m := <-c.Messages:
|
||||||
s, err := server.New(conf)
|
return m
|
||||||
if err != nil {
|
default:
|
||||||
t.Fatal(err)
|
return nil
|
||||||
}
|
}
|
||||||
go func() {
|
|
||||||
if err := s.Run(); err != nil && err != http.ErrServerClosed {
|
|
||||||
panic(err) // 'go vet' complains about 't.Fatal(err)'
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
return s
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,9 +158,6 @@ func doSubscribe(c *cli.Context, cl *client.Client, conf *client.Config, topic,
|
||||||
}
|
}
|
||||||
|
|
||||||
func printMessageOrRunCommand(c *cli.Context, m *client.Message, command string) {
|
func printMessageOrRunCommand(c *cli.Context, m *client.Message, command string) {
|
||||||
if m.Event != client.MessageEvent {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if command != "" {
|
if command != "" {
|
||||||
runCommand(c, command, m)
|
runCommand(c, command, m)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -191,9 +191,6 @@ func createFirebaseSubscriber(conf *Config) (subscriber, error) {
|
||||||
// Run executes the main server. It listens on HTTP (+ HTTPS, if configured), and starts
|
// Run executes the main server. It listens on HTTP (+ HTTPS, if configured), and starts
|
||||||
// a manager go routine to print stats and prune messages.
|
// a manager go routine to print stats and prune messages.
|
||||||
func (s *Server) Run() error {
|
func (s *Server) Run() error {
|
||||||
go s.runManager()
|
|
||||||
go s.runAtSender()
|
|
||||||
go s.runFirebaseKeepliver()
|
|
||||||
listenStr := fmt.Sprintf("%s/http", s.config.ListenHTTP)
|
listenStr := fmt.Sprintf("%s/http", s.config.ListenHTTP)
|
||||||
if s.config.ListenHTTPS != "" {
|
if s.config.ListenHTTPS != "" {
|
||||||
listenStr += fmt.Sprintf(" %s/https", s.config.ListenHTTPS)
|
listenStr += fmt.Sprintf(" %s/https", s.config.ListenHTTPS)
|
||||||
|
@ -214,6 +211,9 @@ func (s *Server) Run() error {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
|
go s.runManager()
|
||||||
|
go s.runAtSender()
|
||||||
|
go s.runFirebaseKeepliver()
|
||||||
return <-errChan
|
return <-errChan
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
38
test/server.go
Normal file
38
test/server.go
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"heckel.io/ntfy/server"
|
||||||
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rand.Seed(time.Now().Unix())
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartServer starts a server.Server with a random port and waits for the server to be up
|
||||||
|
func StartServer(t *testing.T) (*server.Server, int) {
|
||||||
|
port := 10000 + rand.Intn(20000)
|
||||||
|
conf := server.NewConfig()
|
||||||
|
conf.ListenHTTP = fmt.Sprintf(":%d", port)
|
||||||
|
s, err := server.New(conf)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
if err := s.Run(); err != nil && err != http.ErrServerClosed {
|
||||||
|
panic(err) // 'go vet' complains about 't.Fatal(err)'
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
WaitForPortUp(t, port)
|
||||||
|
return s, port
|
||||||
|
}
|
||||||
|
|
||||||
|
// StopServer stops the test server and waits for the port to be down
|
||||||
|
func StopServer(t *testing.T, s *server.Server, port int) {
|
||||||
|
s.Stop()
|
||||||
|
WaitForPortDown(t, port)
|
||||||
|
}
|
3
test/test.go
Normal file
3
test/test.go
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
// Package test provides test helpers for unit and integration tests.
|
||||||
|
// This code is not meant to be used outside of tests.
|
||||||
|
package test
|
44
test/util.go
Normal file
44
test/util.go
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WaitForPortUp waits up to 7s for a port to come up and fails t if that fails
|
||||||
|
func WaitForPortUp(t *testing.T, port int) {
|
||||||
|
success := false
|
||||||
|
for i := 0; i < 500; i++ {
|
||||||
|
startTime := time.Now()
|
||||||
|
conn, _ := net.DialTimeout("tcp", net.JoinHostPort("127.0.0.1", strconv.Itoa(port)), 10*time.Millisecond)
|
||||||
|
if conn != nil {
|
||||||
|
success = true
|
||||||
|
conn.Close()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if time.Since(startTime) < 10*time.Millisecond {
|
||||||
|
time.Sleep(10*time.Millisecond - time.Since(startTime))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !success {
|
||||||
|
t.Fatalf("Failed waiting for port %d to be UP", port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForPortDown waits up to 5s for a port to come down and fails t if that fails
|
||||||
|
func WaitForPortDown(t *testing.T, port int) {
|
||||||
|
success := false
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
conn, _ := net.DialTimeout("tcp", net.JoinHostPort("", strconv.Itoa(port)), 50*time.Millisecond)
|
||||||
|
if conn == nil {
|
||||||
|
success = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
if !success {
|
||||||
|
t.Fatalf("Failed waiting for port %d to be DOWN", port)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue