Skip to content
Snippets Groups Projects
Commit 40fbce07 authored by Philipp Heckel's avatar Philipp Heckel
Browse files

Test for simple pub sub

parent aa976484
No related branches found
No related tags found
No related merge requests found
...@@ -72,7 +72,7 @@ coverage-upload: ...@@ -72,7 +72,7 @@ coverage-upload:
# Lint/formatting targets # Lint/formatting targets
fmt: fmt:
$(GO) fmt ./... gofmt -s -w .
fmt-check: fmt-check:
test -z $(shell gofmt -l .) test -z $(shell gofmt -l .)
......
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
# ntfy.sh | Send push notifications to your phone or desktop via PUT/POST # ntfy.sh | Send push notifications to your phone or desktop via PUT/POST
[![Release](https://img.shields.io/github/release/binwiederhier/ntfy.svg?color=success&style=flat-square)](https://github.com/binwiederhier/ntfy/releases/latest) [![Release](https://img.shields.io/github/release/binwiederhier/ntfy.svg?color=success&style=flat-square)](https://github.com/binwiederhier/ntfy/releases/latest)
[![Go Reference](https://pkg.go.dev/badge/heckel.io/ntfy.svg)](https://pkg.go.dev/heckel.io/ntfy)
[![Tests](https://github.com/binwiederhier/ntfy/workflows/test/badge.svg)](https://github.com/binwiederhier/ntfy/actions)
[![Go Report Card](https://goreportcard.com/badge/github.com/binwiederhier/ntfy)](https://goreportcard.com/report/github.com/binwiederhier/ntfy)
[![codecov](https://codecov.io/gh/binwiederhier/ntfy/branch/main/graph/badge.svg?token=A597KQ463G)](https://codecov.io/gh/binwiederhier/ntfy)
[![Slack channel](https://img.shields.io/badge/slack-@gophers/binwiederhier-success.svg?logo=slack)](https://gophers.slack.com/archives/C01JMTPGF2Q) [![Slack channel](https://img.shields.io/badge/slack-@gophers/binwiederhier-success.svg?logo=slack)](https://gophers.slack.com/archives/C01JMTPGF2Q)
**ntfy** (pronounce: *notify*) is a simple HTTP-based [pub-sub](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern) notification service. **ntfy** (pronounce: *notify*) is a simple HTTP-based [pub-sub](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern) notification service.
......
...@@ -279,7 +279,7 @@ Here's an **excerpt of emojis** I've found very useful in alert messages: ...@@ -279,7 +279,7 @@ Here's an **excerpt of emojis** I've found very useful in alert messages:
</td> </td>
</tr></table> </tr></table>
You can set tags with the `X-Tags` header (or any of its aliases: `Tags`, or `ta`). Specify multiple tags by separating You can set tags with the `X-Tags` header (or any of its aliases: `Tags`, `tag`, or `ta`). Specify multiple tags by separating
them with a comma, e.g. `tag1,tag2,tag3`. them with a comma, e.g. `tag1,tag2,tag3`.
=== "Command line (curl)" === "Command line (curl)"
......
...@@ -306,17 +306,22 @@ func parseHeaders(header http.Header) (title string, priority int, tags []string ...@@ -306,17 +306,22 @@ func parseHeaders(header http.Header) (title string, priority int, tags []string
priority = 1 priority = 1
case "2", "low": case "2", "low":
priority = 2 priority = 2
case "3", "default":
priority = 3
case "4", "high": case "4", "high":
priority = 4 priority = 4
case "5", "max", "urgent": case "5", "max", "urgent":
priority = 5 priority = 5
default: default:
priority = 3 priority = 0
} }
} }
tagsStr := readHeader(header, "x-tags", "tags", "ta") tagsStr := readHeader(header, "x-tags", "tag", "tags", "ta")
if tagsStr != "" { if tagsStr != "" {
tags = strings.Split(tagsStr, ",") tags = make([]string, 0)
for _, s := range strings.Split(tagsStr, ",") {
tags = append(tags, strings.TrimSpace(s))
}
} }
return title, priority, tags return title, priority, tags
} }
...@@ -325,7 +330,7 @@ func readHeader(header http.Header, names ...string) string { ...@@ -325,7 +330,7 @@ func readHeader(header http.Header, names ...string) string {
for _, name := range names { for _, name := range names {
value := header.Get(name) value := header.Get(name)
if value != "" { if value != "" {
return value return strings.TrimSpace(value)
} }
} }
return "" return ""
......
...@@ -17,18 +17,18 @@ import ( ...@@ -17,18 +17,18 @@ import (
func TestServer_PublishAndPoll(t *testing.T) { func TestServer_PublishAndPoll(t *testing.T) {
s := newTestServer(t, newTestConfig(t)) s := newTestServer(t, newTestConfig(t))
response1 := request(t, s, "PUT", "/mytopic", "my first message") response1 := request(t, s, "PUT", "/mytopic", "my first message", nil)
msg1 := toMessage(t, response1.Body.String()) msg1 := toMessage(t, response1.Body.String())
assert.NotEmpty(t, msg1.ID) assert.NotEmpty(t, msg1.ID)
assert.Equal(t, "my first message", msg1.Message) assert.Equal(t, "my first message", msg1.Message)
response2 := request(t, s, "PUT", "/mytopic", "my second message") response2 := request(t, s, "PUT", "/mytopic", "my second message", nil)
msg2 := toMessage(t, response2.Body.String()) msg2 := toMessage(t, response2.Body.String())
assert.NotEqual(t, msg1.ID, msg2.ID) assert.NotEqual(t, msg1.ID, msg2.ID)
assert.NotEmpty(t, msg2.ID) assert.NotEmpty(t, msg2.ID)
assert.Equal(t, "my second message", msg2.Message) assert.Equal(t, "my second message", msg2.Message)
response := request(t, s, "GET", "/mytopic/json?poll=1", "") response := request(t, s, "GET", "/mytopic/json?poll=1", "", nil)
messages := toMessages(t, response.Body.String()) messages := toMessages(t, response.Body.String())
assert.Equal(t, 2, len(messages)) assert.Equal(t, 2, len(messages))
assert.Equal(t, "my first message", messages[0].Message) assert.Equal(t, "my first message", messages[0].Message)
...@@ -73,6 +73,42 @@ func TestServer_SubscribeOpenAndKeepalive(t *testing.T) { ...@@ -73,6 +73,42 @@ func TestServer_SubscribeOpenAndKeepalive(t *testing.T) {
assert.Nil(t, messages[1].Tags) assert.Nil(t, messages[1].Tags)
} }
func TestServer_PublishAndSubscribe(t *testing.T) {
s := newTestServer(t, newTestConfig(t))
subscribeRR := httptest.NewRecorder()
subscribeCancel := subscribe(t, s, "/mytopic/json", subscribeRR)
publishFirstRR := request(t, s, "PUT", "/mytopic", "my first message", nil)
assert.Equal(t, 200, publishFirstRR.Code)
publishSecondRR := request(t, s, "PUT", "/mytopic", "my other message", map[string]string{
"Title": " This is a title ",
"X-Tags": "tag1,tag 2, tag3",
"p": "1",
})
assert.Equal(t, 200, publishSecondRR.Code)
subscribeCancel()
messages := toMessages(t, subscribeRR.Body.String())
assert.Equal(t, 3, len(messages))
assert.Equal(t, openEvent, messages[0].Event)
assert.Equal(t, messageEvent, messages[1].Event)
assert.Equal(t, "mytopic", messages[1].Topic)
assert.Equal(t, "my first message", messages[1].Message)
assert.Equal(t, "", messages[1].Title)
assert.Equal(t, 0, messages[1].Priority)
assert.Nil(t, messages[1].Tags)
assert.Equal(t, messageEvent, messages[2].Event)
assert.Equal(t, "mytopic", messages[2].Topic)
assert.Equal(t, "my other message", messages[2].Message)
assert.Equal(t, "This is a title", messages[2].Title)
assert.Equal(t, 1, messages[2].Priority)
assert.Equal(t, []string{"tag1", "tag 2", "tag3"}, messages[2].Tags)
}
func newTestConfig(t *testing.T) *config.Config { func newTestConfig(t *testing.T) *config.Config {
conf := config.New(":80") conf := config.New(":80")
conf.CacheFile = filepath.Join(t.TempDir(), "cache.db") conf.CacheFile = filepath.Join(t.TempDir(), "cache.db")
...@@ -87,16 +123,41 @@ func newTestServer(t *testing.T, config *config.Config) *Server { ...@@ -87,16 +123,41 @@ func newTestServer(t *testing.T, config *config.Config) *Server {
return server return server
} }
func request(t *testing.T, s *Server, method, url, body string) *httptest.ResponseRecorder { func request(t *testing.T, s *Server, method, url, body string, headers map[string]string) *httptest.ResponseRecorder {
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
req, err := http.NewRequest(method, url, strings.NewReader(body)) req, err := http.NewRequest(method, url, strings.NewReader(body))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if headers != nil {
for k, v := range headers {
req.Header.Set(k, v)
}
}
s.handle(rr, req) s.handle(rr, req)
return rr return rr
} }
func subscribe(t *testing.T, s *Server, url string, rr *httptest.ResponseRecorder) context.CancelFunc {
ctx, cancel := context.WithCancel(context.Background())
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
t.Fatal(err)
}
done := make(chan bool)
go func() {
s.handle(rr, req)
done <- true
}()
cancelAndWaitForDone := func() {
time.Sleep(100 * time.Millisecond)
cancel()
<-done
}
time.Sleep(100 * time.Millisecond)
return cancelAndWaitForDone
}
func toMessages(t *testing.T, s string) []*message { func toMessages(t *testing.T, s string) []*message {
messages := make([]*message, 0) messages := make([]*message, 0)
scanner := bufio.NewScanner(strings.NewReader(s)) scanner := bufio.NewScanner(strings.NewReader(s))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment