123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- package cmd
- import (
- "fmt"
- "github.com/stretchr/testify/require"
- "heckel.io/ntfy/v2/test"
- "heckel.io/ntfy/v2/util"
- "net/http"
- "net/http/httptest"
- "os"
- "os/exec"
- "path/filepath"
- "strconv"
- "strings"
- "testing"
- "time"
- )
- func TestCLI_Publish_Subscribe_Poll_Real_Server(t *testing.T) {
- t.Parallel()
- testMessage := util.RandomString(10)
- app, _, _, _ := newTestApp()
- require.Nil(t, app.Run([]string{"ntfy", "publish", "ntfytest", "ntfy unit test " + testMessage}))
- _, err := util.Retry(func() (*int, error) {
- app2, _, stdout, _ := newTestApp()
- if err := app2.Run([]string{"ntfy", "subscribe", "--poll", "ntfytest"}); err != nil {
- return nil, err
- }
- if !strings.Contains(stdout.String(), testMessage) {
- return nil, fmt.Errorf("test message %s not found in topic", testMessage)
- }
- return util.Int(1), nil
- }, time.Second, 2*time.Second, 5*time.Second) // Since #502, ntfy.sh writes messages to the cache asynchronously, after a timeout of ~1.5s
- require.Nil(t, err)
- }
- func TestCLI_Publish_Subscribe_Poll(t *testing.T) {
- t.Parallel()
- s, port := test.StartServer(t)
- defer test.StopServer(t, s, port)
- topic := fmt.Sprintf("http://127.0.0.1:%d/mytopic", port)
- app, _, stdout, _ := newTestApp()
- require.Nil(t, app.Run([]string{"ntfy", "publish", topic, "some message"}))
- m := toMessage(t, stdout.String())
- require.Equal(t, "some message", m.Message)
- app2, _, stdout, _ := newTestApp()
- require.Nil(t, app2.Run([]string{"ntfy", "subscribe", "--poll", topic}))
- m = toMessage(t, stdout.String())
- require.Equal(t, "some message", m.Message)
- }
- func TestCLI_Publish_All_The_Things(t *testing.T) {
- t.Parallel()
- s, port := test.StartServer(t)
- defer test.StopServer(t, s, port)
- topic := fmt.Sprintf("http://127.0.0.1:%d/mytopic", port)
- app, _, stdout, _ := newTestApp()
- require.Nil(t, app.Run([]string{
- "ntfy", "publish",
- "--title", "this is a title",
- "--priority", "high",
- "--tags", "tag1,tag2",
- // No --delay, --email
- "--click", "https://ntfy.sh",
- "--icon", "https://ntfy.sh/static/img/ntfy.png",
- "--attach", "https://f-droid.org/F-Droid.apk",
- "--filename", "fdroid.apk",
- "--no-cache",
- "--no-firebase",
- topic,
- "some message",
- }))
- m := toMessage(t, stdout.String())
- require.Equal(t, "message", m.Event)
- require.Equal(t, "mytopic", m.Topic)
- require.Equal(t, "some message", m.Message)
- require.Equal(t, "this is a title", m.Title)
- require.Equal(t, 4, m.Priority)
- require.Equal(t, []string{"tag1", "tag2"}, m.Tags)
- require.Equal(t, "https://ntfy.sh", m.Click)
- require.Equal(t, "https://f-droid.org/F-Droid.apk", m.Attachment.URL)
- require.Equal(t, "fdroid.apk", m.Attachment.Name)
- require.Equal(t, int64(0), m.Attachment.Size)
- require.Equal(t, "", m.Attachment.Owner)
- require.Equal(t, int64(0), m.Attachment.Expires)
- require.Equal(t, "", m.Attachment.Type)
- require.Equal(t, "https://ntfy.sh/static/img/ntfy.png", m.Icon)
- }
- func TestCLI_Publish_Wait_PID_And_Cmd(t *testing.T) {
- s, port := test.StartServer(t)
- defer test.StopServer(t, s, port)
- topic := fmt.Sprintf("http://127.0.0.1:%d/mytopic", port)
- // Test: sleep 0.5
- sleep := exec.Command("sleep", "0.5")
- require.Nil(t, sleep.Start())
- go sleep.Wait() // Must be called to release resources
- start := time.Now()
- app, _, stdout, _ := newTestApp()
- require.Nil(t, app.Run([]string{"ntfy", "publish", "--wait-pid", strconv.Itoa(sleep.Process.Pid), topic}))
- m := toMessage(t, stdout.String())
- require.True(t, time.Since(start) >= 500*time.Millisecond)
- require.Regexp(t, `Process with PID \d+ exited after `, m.Message)
- // Test: PID does not exist
- app, _, _, _ = newTestApp()
- err := app.Run([]string{"ntfy", "publish", "--wait-pid", "1234567", topic})
- require.Error(t, err)
- require.Equal(t, "process with PID 1234567 not running", err.Error())
- // Test: Successful command (exit 0)
- start = time.Now()
- app, _, stdout, _ = newTestApp()
- require.Nil(t, app.Run([]string{"ntfy", "publish", "--wait-cmd", topic, "sleep", "0.5"}))
- m = toMessage(t, stdout.String())
- require.True(t, time.Since(start) >= 500*time.Millisecond)
- require.Contains(t, m.Message, `Command succeeded after `)
- require.Contains(t, m.Message, `: sleep 0.5`)
- // Test: Failing command (exit 1)
- app, _, stdout, _ = newTestApp()
- require.Nil(t, app.Run([]string{"ntfy", "publish", "--wait-cmd", topic, "/bin/false", "false doesn't care about its args"}))
- m = toMessage(t, stdout.String())
- require.Contains(t, m.Message, `Command failed after `)
- require.Contains(t, m.Message, `(exit code 1): /bin/false "false doesn't care about its args"`, m.Message)
- // Test: Non-existing command (hard fail!)
- app, _, _, _ = newTestApp()
- err = app.Run([]string{"ntfy", "publish", "--wait-cmd", topic, "does-not-exist-no-really", "really though"})
- require.Error(t, err)
- require.Equal(t, `command failed: does-not-exist-no-really "really though", error: exec: "does-not-exist-no-really": executable file not found in $PATH`, err.Error())
- // Tests with NTFY_TOPIC set ////
- t.Setenv("NTFY_TOPIC", topic)
- // Test: Successful command with NTFY_TOPIC
- app, _, stdout, _ = newTestApp()
- require.Nil(t, app.Run([]string{"ntfy", "publish", "--cmd", "echo", "hi there"}))
- m = toMessage(t, stdout.String())
- require.Equal(t, "mytopic", m.Topic)
- // Test: Successful --wait-pid with NTFY_TOPIC
- sleep = exec.Command("sleep", "0.2")
- require.Nil(t, sleep.Start())
- go sleep.Wait() // Must be called to release resources
- app, _, stdout, _ = newTestApp()
- require.Nil(t, app.Run([]string{"ntfy", "publish", "--wait-pid", strconv.Itoa(sleep.Process.Pid)}))
- m = toMessage(t, stdout.String())
- require.Regexp(t, `Process with PID \d+ exited after .+ms`, m.Message)
- }
- func TestCLI_Publish_Default_UserPass(t *testing.T) {
- message := `{"id":"RXIQBFaieLVr","time":124,"expires":1124,"event":"message","topic":"mytopic","message":"triggered"}`
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- require.Equal(t, "/mytopic", r.URL.Path)
- require.Equal(t, "Basic cGhpbGlwcDpteXBhc3M=", r.Header.Get("Authorization"))
- w.WriteHeader(http.StatusOK)
- w.Write([]byte(message))
- }))
- defer server.Close()
- filename := filepath.Join(t.TempDir(), "client.yml")
- require.Nil(t, os.WriteFile(filename, []byte(fmt.Sprintf(`
- default-host: %s
- default-user: philipp
- default-password: mypass
- `, server.URL)), 0600))
- app, _, stdout, _ := newTestApp()
- require.Nil(t, app.Run([]string{"ntfy", "publish", "--config=" + filename, "mytopic", "triggered"}))
- m := toMessage(t, stdout.String())
- require.Equal(t, "triggered", m.Message)
- }
- func TestCLI_Publish_Default_Token(t *testing.T) {
- message := `{"id":"RXIQBFaieLVr","time":124,"expires":1124,"event":"message","topic":"mytopic","message":"triggered"}`
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- require.Equal(t, "/mytopic", r.URL.Path)
- require.Equal(t, "Bearer tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2", r.Header.Get("Authorization"))
- w.WriteHeader(http.StatusOK)
- w.Write([]byte(message))
- }))
- defer server.Close()
- filename := filepath.Join(t.TempDir(), "client.yml")
- require.Nil(t, os.WriteFile(filename, []byte(fmt.Sprintf(`
- default-host: %s
- default-token: tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2
- `, server.URL)), 0600))
- app, _, stdout, _ := newTestApp()
- require.Nil(t, app.Run([]string{"ntfy", "publish", "--config=" + filename, "mytopic", "triggered"}))
- m := toMessage(t, stdout.String())
- require.Equal(t, "triggered", m.Message)
- }
- func TestCLI_Publish_Default_UserPass_CLI_Token(t *testing.T) {
- message := `{"id":"RXIQBFaieLVr","time":124,"expires":1124,"event":"message","topic":"mytopic","message":"triggered"}`
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- require.Equal(t, "/mytopic", r.URL.Path)
- require.Equal(t, "Bearer tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2", r.Header.Get("Authorization"))
- w.WriteHeader(http.StatusOK)
- w.Write([]byte(message))
- }))
- defer server.Close()
- filename := filepath.Join(t.TempDir(), "client.yml")
- require.Nil(t, os.WriteFile(filename, []byte(fmt.Sprintf(`
- default-host: %s
- default-user: philipp
- default-password: mypass
- `, server.URL)), 0600))
- app, _, stdout, _ := newTestApp()
- require.Nil(t, app.Run([]string{"ntfy", "publish", "--config=" + filename, "--token", "tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2", "mytopic", "triggered"}))
- m := toMessage(t, stdout.String())
- require.Equal(t, "triggered", m.Message)
- }
- func TestCLI_Publish_Default_Token_CLI_UserPass(t *testing.T) {
- message := `{"id":"RXIQBFaieLVr","time":124,"expires":1124,"event":"message","topic":"mytopic","message":"triggered"}`
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- require.Equal(t, "/mytopic", r.URL.Path)
- require.Equal(t, "Basic cGhpbGlwcDpteXBhc3M=", r.Header.Get("Authorization"))
- w.WriteHeader(http.StatusOK)
- w.Write([]byte(message))
- }))
- defer server.Close()
- filename := filepath.Join(t.TempDir(), "client.yml")
- require.Nil(t, os.WriteFile(filename, []byte(fmt.Sprintf(`
- default-host: %s
- default-token: tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2
- `, server.URL)), 0600))
- app, _, stdout, _ := newTestApp()
- require.Nil(t, app.Run([]string{"ntfy", "publish", "--config=" + filename, "--user", "philipp:mypass", "mytopic", "triggered"}))
- m := toMessage(t, stdout.String())
- require.Equal(t, "triggered", m.Message)
- }
- func TestCLI_Publish_Default_Token_CLI_Token(t *testing.T) {
- message := `{"id":"RXIQBFaieLVr","time":124,"expires":1124,"event":"message","topic":"mytopic","message":"triggered"}`
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- require.Equal(t, "/mytopic", r.URL.Path)
- require.Equal(t, "Bearer tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2", r.Header.Get("Authorization"))
- w.WriteHeader(http.StatusOK)
- w.Write([]byte(message))
- }))
- defer server.Close()
- filename := filepath.Join(t.TempDir(), "client.yml")
- require.Nil(t, os.WriteFile(filename, []byte(fmt.Sprintf(`
- default-host: %s
- default-token: tk_FAKETOKEN01234567890FAKETOKEN
- `, server.URL)), 0600))
- app, _, stdout, _ := newTestApp()
- require.Nil(t, app.Run([]string{"ntfy", "publish", "--config=" + filename, "--token", "tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2", "mytopic", "triggered"}))
- m := toMessage(t, stdout.String())
- require.Equal(t, "triggered", m.Message)
- }
- func TestCLI_Publish_Default_UserPass_CLI_UserPass(t *testing.T) {
- message := `{"id":"RXIQBFaieLVr","time":124,"expires":1124,"event":"message","topic":"mytopic","message":"triggered"}`
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- require.Equal(t, "/mytopic", r.URL.Path)
- require.Equal(t, "Basic cGhpbGlwcDpteXBhc3M=", r.Header.Get("Authorization"))
- w.WriteHeader(http.StatusOK)
- w.Write([]byte(message))
- }))
- defer server.Close()
- filename := filepath.Join(t.TempDir(), "client.yml")
- require.Nil(t, os.WriteFile(filename, []byte(fmt.Sprintf(`
- default-host: %s
- default-user: philipp
- default-password: fakepass
- `, server.URL)), 0600))
- app, _, stdout, _ := newTestApp()
- require.Nil(t, app.Run([]string{"ntfy", "publish", "--config=" + filename, "--user", "philipp:mypass", "mytopic", "triggered"}))
- m := toMessage(t, stdout.String())
- require.Equal(t, "triggered", m.Message)
- }
- func TestCLI_Publish_Token_And_UserPass(t *testing.T) {
- app, _, _, _ := newTestApp()
- err := app.Run([]string{"ntfy", "publish", "--token", "tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2", "--user", "philipp:mypass", "mytopic", "triggered"})
- require.Error(t, err)
- require.Equal(t, "cannot set both --user and --token", err.Error())
- }
|