mirror of
https://github.com/GMWalletApp/epusdt.git
synced 2026-07-07 10:16:15 +00:00
95879e33d4
- keep install-mode root redirect to /install and add tests covering install root redirect and install page serving
- change root backend handler from Any("/") to POST("/") so GET / can consistently serve the SPA after install
Co-authored-by: Copilot <copilot@github.com>
225 lines
6.4 KiB
Go
225 lines
6.4 KiB
Go
package install
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
)
|
|
|
|
func TestInstallDefaults(t *testing.T) {
|
|
d := InstallDefaults()
|
|
if d.AppName != "epusdt" {
|
|
t.Errorf("AppName = %q, want epusdt", d.AppName)
|
|
}
|
|
if d.HttpBindAddr != "127.0.0.1" {
|
|
t.Errorf("HttpBindAddr = %q, want 127.0.0.1", d.HttpBindAddr)
|
|
}
|
|
if d.HttpBindPort != 8000 {
|
|
t.Errorf("HttpBindPort = %d, want 8000", d.HttpBindPort)
|
|
}
|
|
if d.OrderExpirationTime != 10 {
|
|
t.Errorf("OrderExpirationTime = %d, want 10", d.OrderExpirationTime)
|
|
}
|
|
}
|
|
|
|
func TestWriteEnvFile(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, ".env")
|
|
|
|
req := &InstallRequest{
|
|
AppName: "myapp",
|
|
AppURI: "http://1.2.3.4:8000",
|
|
HttpBindAddr: "0.0.0.0",
|
|
HttpBindPort: 9000,
|
|
RuntimeRootPath: "./runtime",
|
|
LogSavePath: "./logs",
|
|
OrderExpirationTime: 15,
|
|
OrderNoticeMaxRetry: 3,
|
|
}
|
|
if err := writeEnvFile(path, req); err != nil {
|
|
t.Fatalf("writeEnvFile: %v", err)
|
|
}
|
|
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
t.Fatalf("read env: %v", err)
|
|
}
|
|
content := string(data)
|
|
|
|
for _, want := range []string{
|
|
"app_name=myapp",
|
|
"app_uri=http://1.2.3.4:8000",
|
|
"http_listen=0.0.0.0:9000",
|
|
"order_expiration_time=15",
|
|
"order_notice_max_retry=3",
|
|
"db_type=sqlite",
|
|
"install=false",
|
|
} {
|
|
if !strings.Contains(content, want) {
|
|
t.Errorf("env file missing %q\ncontent:\n%s", want, content)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestInstallAPIDefaults(t *testing.T) {
|
|
h := &installHandler{done: make(chan struct{})}
|
|
e := echo.New()
|
|
e.GET("/install/defaults", h.GetDefaults)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/install/defaults", nil)
|
|
rec := httptest.NewRecorder()
|
|
e.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("status = %d, want 200", rec.Code)
|
|
}
|
|
var body map[string]interface{}
|
|
if err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil {
|
|
t.Fatalf("decode body: %v", err)
|
|
}
|
|
if body["app_name"] != "epusdt" {
|
|
t.Errorf("app_name = %v, want epusdt", body["app_name"])
|
|
}
|
|
if body["http_bind_addr"] != "127.0.0.1" {
|
|
t.Errorf("http_bind_addr = %v, want 127.0.0.1", body["http_bind_addr"])
|
|
}
|
|
if body["http_bind_port"] != float64(8000) {
|
|
t.Errorf("http_bind_port = %v, want 8000", body["http_bind_port"])
|
|
}
|
|
}
|
|
|
|
func TestInstallServerRootRedirectsToInstall(t *testing.T) {
|
|
dir := t.TempDir()
|
|
wwwRoot := filepath.Join(dir, "www")
|
|
if err := os.MkdirAll(wwwRoot, 0o755); err != nil {
|
|
t.Fatalf("mkdir www root: %v", err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(wwwRoot, "index.html"), []byte("install-ui"), 0o644); err != nil {
|
|
t.Fatalf("write index.html: %v", err)
|
|
}
|
|
|
|
e, _ := newInstallServer(filepath.Join(dir, ".env"), wwwRoot)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
rec := httptest.NewRecorder()
|
|
e.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusFound {
|
|
t.Fatalf("status = %d, want 302; body: %s", rec.Code, rec.Body.String())
|
|
}
|
|
if got := rec.Header().Get("Location"); got != "/install" {
|
|
t.Fatalf("Location = %q, want /install", got)
|
|
}
|
|
}
|
|
|
|
func TestInstallServerServesSPAOnInstallRoute(t *testing.T) {
|
|
dir := t.TempDir()
|
|
wwwRoot := filepath.Join(dir, "www")
|
|
if err := os.MkdirAll(wwwRoot, 0o755); err != nil {
|
|
t.Fatalf("mkdir www root: %v", err)
|
|
}
|
|
const wantBody = "install-ui"
|
|
if err := os.WriteFile(filepath.Join(wwwRoot, "index.html"), []byte(wantBody), 0o644); err != nil {
|
|
t.Fatalf("write index.html: %v", err)
|
|
}
|
|
|
|
e, _ := newInstallServer(filepath.Join(dir, ".env"), wwwRoot)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/install", nil)
|
|
rec := httptest.NewRecorder()
|
|
e.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("status = %d, want 200; body: %s", rec.Code, rec.Body.String())
|
|
}
|
|
if body := rec.Body.String(); body != wantBody {
|
|
t.Fatalf("body = %q, want %q", body, wantBody)
|
|
}
|
|
}
|
|
|
|
func TestInstallAPISubmit(t *testing.T) {
|
|
dir := t.TempDir()
|
|
envPath := filepath.Join(dir, ".env")
|
|
|
|
h := &installHandler{envFilePath: envPath, done: make(chan struct{})}
|
|
e := echo.New()
|
|
e.POST("/install", h.Submit)
|
|
|
|
payload := `{"app_name":"testapp","app_uri":"http://10.0.0.1:8000","http_bind_addr":"0.0.0.0","http_bind_port":8000,"order_expiration_time":10,"order_notice_max_retry":1}`
|
|
req := httptest.NewRequest(http.MethodPost, "/install", strings.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
e.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("status = %d, want 200; body: %s", rec.Code, rec.Body.String())
|
|
}
|
|
// done channel should be closed after successful submit
|
|
select {
|
|
case <-h.done:
|
|
case <-time.After(500 * time.Millisecond):
|
|
t.Fatal("handler did not close done channel within timeout")
|
|
}
|
|
data, err := os.ReadFile(envPath)
|
|
if err != nil {
|
|
t.Fatalf("env file not written: %v", err)
|
|
}
|
|
content := string(data)
|
|
if !strings.Contains(content, "app_uri=http://10.0.0.1:8000") {
|
|
t.Errorf("env file missing app_uri; content:\n%s", content)
|
|
}
|
|
if !strings.Contains(content, "http_listen=0.0.0.0:8000") {
|
|
t.Errorf("env file missing http_listen; content:\n%s", content)
|
|
}
|
|
}
|
|
|
|
func TestInstallAPISubmitMissingURI(t *testing.T) {
|
|
dir := t.TempDir()
|
|
envPath := filepath.Join(dir, ".env")
|
|
|
|
h := &installHandler{envFilePath: envPath, done: make(chan struct{})}
|
|
e := echo.New()
|
|
e.POST("/install", h.Submit)
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/install", strings.NewReader(`{"app_name":"x"}`))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
e.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusBadRequest {
|
|
t.Fatalf("status = %d, want 400", rec.Code)
|
|
}
|
|
if _, err := os.Stat(envPath); err == nil {
|
|
t.Error("env file should not have been written for invalid request")
|
|
}
|
|
}
|
|
|
|
func TestInstallAPISubmitInvalidPort(t *testing.T) {
|
|
dir := t.TempDir()
|
|
envPath := filepath.Join(dir, ".env")
|
|
|
|
h := &installHandler{envFilePath: envPath, done: make(chan struct{})}
|
|
e := echo.New()
|
|
e.POST("/install", h.Submit)
|
|
|
|
payload := `{"app_uri":"http://example.com","http_bind_port":99999}`
|
|
req := httptest.NewRequest(http.MethodPost, "/install", strings.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
e.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusBadRequest {
|
|
t.Fatalf("status = %d, want 400; body: %s", rec.Code, rec.Body.String())
|
|
}
|
|
if _, err := os.Stat(envPath); err == nil {
|
|
t.Error("env file should not have been written for invalid port")
|
|
}
|
|
}
|