2021-12-19 23:32:16 +00:00
package cmd
import (
2021-12-24 14:01:29 +00:00
"fmt"
2021-12-19 23:32:16 +00:00
"github.com/stretchr/testify/require"
2023-11-17 01:54:58 +00:00
"heckel.io/ntfy/v2/test"
"heckel.io/ntfy/v2/util"
2023-03-06 05:57:51 +00:00
"net/http"
"net/http/httptest"
2022-06-21 15:18:35 +00:00
"os"
"os/exec"
2023-03-06 05:57:51 +00:00
"path/filepath"
2022-06-21 15:18:35 +00:00
"strconv"
2023-02-07 17:02:25 +00:00
"strings"
2021-12-19 23:32:16 +00:00
"testing"
2022-06-21 15:18:35 +00:00
"time"
2021-12-19 23:32:16 +00:00
)
2021-12-20 02:01:49 +00:00
func TestCLI_Publish_Subscribe_Poll_Real_Server ( t * testing . T ) {
2021-12-19 23:32:16 +00:00
testMessage := util . RandomString ( 10 )
app , _ , _ , _ := newTestApp ( )
require . Nil ( t , app . Run ( [ ] string { "ntfy" , "publish" , "ntfytest" , "ntfy unit test " + testMessage } ) )
2023-02-07 17:02:25 +00:00
_ , 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 )
2021-12-19 23:32:16 +00:00
}
2021-12-24 14:01:29 +00:00
func TestCLI_Publish_Subscribe_Poll ( 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 )
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 )
}
2022-01-16 03:33:35 +00:00
func TestCLI_Publish_All_The_Things ( 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 )
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" ,
2022-07-16 19:31:03 +00:00
"--icon" , "https://ntfy.sh/static/img/ntfy.png" ,
2022-01-16 03:33:35 +00:00
"--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 )
2022-07-17 21:40:24 +00:00
require . Equal ( t , "https://ntfy.sh/static/img/ntfy.png" , m . Icon )
2022-01-16 03:33:35 +00:00
}
2022-06-21 15:18:35 +00:00
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 ////
2023-03-06 05:57:51 +00:00
t . Setenv ( "NTFY_TOPIC" , topic )
2022-06-21 15:18:35 +00:00
// Test: Successful command with NTFY_TOPIC
app , _ , stdout , _ = newTestApp ( )
2023-02-28 16:57:49 +00:00
require . Nil ( t , app . Run ( [ ] string { "ntfy" , "publish" , "--cmd" , "echo" , "hi there" } ) )
2022-06-21 15:18:35 +00:00
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 ( )
2023-02-28 16:57:49 +00:00
require . Nil ( t , app . Run ( [ ] string { "ntfy" , "publish" , "--wait-pid" , strconv . Itoa ( sleep . Process . Pid ) } ) )
2022-06-21 15:18:35 +00:00
m = toMessage ( t , stdout . String ( ) )
require . Regexp ( t , ` Process with PID \d+ exited after .+ms ` , m . Message )
}
2023-03-06 05:57:51 +00:00
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 ( ) )
}