164 lines
4.4 KiB
Go
164 lines
4.4 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"math/rand"
|
|
"net"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"sync/atomic"
|
|
"syscall"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"go.uber.org/goleak"
|
|
)
|
|
|
|
func Test_Main(t *testing.T) {
|
|
dir, err := os.MkdirTemp(os.TempDir(), "remark42")
|
|
require.NoError(t, err)
|
|
defer os.RemoveAll(dir)
|
|
|
|
port := chooseRandomUnusedPort()
|
|
os.Args = []string{"test", "server", "--secret=123456", "--store.bolt.path=" + dir, "--backup=/tmp",
|
|
"--avatar.fs.path=" + dir, "--port=" + strconv.Itoa(port), "--url=https://demo.remark42.com", "--dbg", "--notify.type=none"}
|
|
|
|
done := make(chan struct{})
|
|
go func() {
|
|
<-done
|
|
e := syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
|
|
require.NoError(t, e)
|
|
}()
|
|
|
|
finished := make(chan struct{})
|
|
go func() {
|
|
main()
|
|
close(finished)
|
|
}()
|
|
|
|
// defer cleanup because require check below can fail
|
|
defer func() {
|
|
close(done)
|
|
<-finished
|
|
}()
|
|
|
|
waitForHTTPServerStart(port)
|
|
resp, err := http.Get(fmt.Sprintf("http://localhost:%d/api/v1/ping", port))
|
|
require.NoError(t, err)
|
|
defer resp.Body.Close()
|
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
|
body, err := io.ReadAll(resp.Body)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "pong", string(body))
|
|
}
|
|
|
|
func TestMain_WithWebhook(t *testing.T) {
|
|
dir, err := os.MkdirTemp(os.TempDir(), "remark42")
|
|
require.NoError(t, err)
|
|
defer os.RemoveAll(dir)
|
|
|
|
var webhookSent int32
|
|
ts := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
|
|
atomic.StoreInt32(&webhookSent, 1)
|
|
assert.Equal(t, "application/json", r.Header.Get("Content-Type"))
|
|
|
|
b, e := io.ReadAll(r.Body)
|
|
defer r.Body.Close()
|
|
|
|
assert.Nil(t, e)
|
|
assert.Equal(t, "Comment: env test", string(b))
|
|
}))
|
|
defer ts.Close()
|
|
|
|
port := chooseRandomUnusedPort()
|
|
os.Args = []string{"test", "server", "--secret=123456", "--store.bolt.path=" + dir, "--backup=/tmp",
|
|
"--avatar.fs.path=" + dir, "--port=" + strconv.Itoa(port), "--url=https://demo.remark42.com", "--dbg",
|
|
"--admin-passwd=password", "--site=remark", "--notify.admins=webhook"}
|
|
|
|
err = os.Setenv("NOTIFY_WEBHOOK_URL", ts.URL)
|
|
assert.NoError(t, err)
|
|
err = os.Setenv("NOTIFY_WEBHOOK_TEMPLATE", "Comment: {{.Orig}}")
|
|
assert.NoError(t, err)
|
|
err = os.Setenv("NOTIFY_WEBHOOK_HEADERS", "Content-Type:application/json")
|
|
assert.NoError(t, err)
|
|
|
|
done := make(chan struct{})
|
|
go func() {
|
|
<-done
|
|
e := syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
|
|
require.NoError(t, e)
|
|
}()
|
|
|
|
finished := make(chan struct{})
|
|
go func() {
|
|
main()
|
|
assert.Eventually(t, func() bool {
|
|
return atomic.LoadInt32(&webhookSent) == int32(1)
|
|
}, time.Second, 100*time.Millisecond, "webhook was not sent")
|
|
close(finished)
|
|
}()
|
|
|
|
// defer cleanup because require check below can fail
|
|
defer func() {
|
|
close(done)
|
|
<-finished
|
|
}()
|
|
|
|
waitForHTTPServerStart(port)
|
|
|
|
resp, err := http.Post(fmt.Sprintf("http://admin:password@localhost:%d/api/v1/comment", port), "",
|
|
strings.NewReader(`{"text": "env test", "locator":{"url": "https://radio-t.com", "site": "remark"}}`))
|
|
require.NoError(t, err)
|
|
defer resp.Body.Close()
|
|
assert.Equal(t, http.StatusCreated, resp.StatusCode)
|
|
}
|
|
|
|
func TestGetDump(t *testing.T) {
|
|
dump := getDump()
|
|
assert.True(t, strings.Contains(dump, "goroutine"))
|
|
assert.True(t, strings.Contains(dump, "[running]"))
|
|
assert.True(t, strings.Contains(dump, "backend/app/main.go"))
|
|
t.Logf("\n dump: %s", dump)
|
|
}
|
|
|
|
func chooseRandomUnusedPort() (port int) {
|
|
for i := 0; i < 10; i++ {
|
|
port = 40000 + int(rand.Int31n(10000))
|
|
if ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port)); err == nil {
|
|
_ = ln.Close()
|
|
break
|
|
}
|
|
}
|
|
return port
|
|
}
|
|
|
|
func waitForHTTPServerStart(port int) {
|
|
// wait for up to 10 seconds for server to start before returning it
|
|
client := http.Client{Timeout: time.Second}
|
|
defer client.CloseIdleConnections()
|
|
for i := 0; i < 100; i++ {
|
|
time.Sleep(time.Millisecond * 100)
|
|
if resp, err := client.Get(fmt.Sprintf("http://localhost:%d", port)); err == nil {
|
|
_ = resp.Body.Close()
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMain(m *testing.M) {
|
|
// both ignores are for leaks which are detected locally
|
|
goleak.VerifyTestMain(
|
|
m,
|
|
goleak.IgnoreTopFunction("github.com/umputun/remark42/backend/app.init.0.func1"),
|
|
goleak.IgnoreTopFunction("net/http.(*Server).Shutdown"),
|
|
// this will be fixed in https://github.com/hashicorp/golang-lru/issues/159
|
|
goleak.IgnoreTopFunction("github.com/hashicorp/golang-lru/v2/expirable.NewLRU[...].func1"),
|
|
)
|
|
}
|