Restructure the monorepo into clear top-level directories: - backend/: Go module root (cmd, internal, pkg, configs, migrations, docs/swagger, scripts, tests, go.mod, Makefile, .air.toml) - deploy/: Docker (Dockerfile, docker-compose*), quickstart, fluentd - docs/: project documentation + reports/ (moved from repo root) - AGENTS.md: new AI coding-agent guide at repo root Update all references to the new layout: - Dockerfile: COPY backend/go.mod, COPY backend/ (context = repo root) - docker-compose files: context ../.., dockerfile deploy/docker/Dockerfile, env_file ../../.env, volume mounts ../../backend:/app - deploy/quickstart/compose.yaml: dockerfile deploy/docker/Dockerfile - CI: working-directory: backend for go commands, file deploy/docker/Dockerfile, coverage path backend/coverage.out, health_check backend/scripts/ - backend/Makefile: docker target uses -f ../deploy/docker/Dockerfile ../ - README: architecture tree, quickstart, config paths updated Move root stray scripts (rename_models.*, run_m11_tests.sh, verify_build.sh, gorm_bool_main.go) to backend/scripts/legacy/. All moves via git mv to preserve history. Build, vet, SQLite tests, and docker compose config verified.
94 lines
3.4 KiB
Go
94 lines
3.4 KiB
Go
package provider
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/go-resty/resty/v2"
|
|
"github.com/gochat/gochat/internal/channel"
|
|
"github.com/gochat/gochat/internal/model"
|
|
)
|
|
|
|
func TestTelegramProvider_CreateChannelReturnsWebhookSetupFailure(t *testing.T) {
|
|
provider := NewTelegramProvider()
|
|
provider.client = fakeTelegramRestyClient(t, map[string]string{
|
|
"/bot123:token/getMe": `{"ok":true,"result":{"id":42,"first_name":"Support Bot","username":"support_bot"}}`,
|
|
"/bot123:token/deleteWebhook": `{"ok":true,"result":true}`,
|
|
"/bot123:token/setWebhook": `{"ok":false,"description":"webhook URL is invalid"}`,
|
|
})
|
|
|
|
_, err := provider.CreateChannel(context.Background(), 1, channel.ChannelConfig{"bot_token": "123:token"})
|
|
if err == nil || !strings.Contains(err.Error(), "telegram webhook setup failed") || !strings.Contains(err.Error(), "webhook URL is invalid") {
|
|
t.Fatalf("expected webhook setup failure, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestTelegramProvider_OnCreateFlagsReauthorizationOnWebhookFailure(t *testing.T) {
|
|
provider := NewTelegramProvider()
|
|
provider.client = fakeTelegramRestyClient(t, map[string]string{
|
|
"/bot123:token/deleteWebhook": `{"ok":true,"result":true}`,
|
|
"/bot123:token/setWebhook": `{"ok":false,"description":"webhook URL is invalid"}`,
|
|
})
|
|
|
|
config, err := provider.OnCreate(context.Background(), &model.Inbox{ChannelType: "telegram"}, channel.ChannelConfig{"bot_token": "123:token"})
|
|
if err != nil {
|
|
t.Fatalf("expected OnCreate to keep inbox creation non-fatal, got %v", err)
|
|
}
|
|
if config["reauthorization_required"] != true {
|
|
t.Fatalf("expected reauthorization_required=true, got %#v", config)
|
|
}
|
|
if _, ok := config["webhook_url"]; ok {
|
|
t.Fatalf("expected webhook_url to be omitted on setup failure, got %#v", config["webhook_url"])
|
|
}
|
|
}
|
|
|
|
func TestTelegramProvider_OnCreateStoresWebhookURLOnSuccess(t *testing.T) {
|
|
t.Setenv("FRONTEND_URL", "https://app.example.test")
|
|
provider := NewTelegramProvider()
|
|
provider.client = fakeTelegramRestyClient(t, map[string]string{
|
|
"/bot123:token/deleteWebhook": `{"ok":true,"result":true}`,
|
|
"/bot123:token/setWebhook": `{"ok":true,"result":true}`,
|
|
})
|
|
|
|
config, err := provider.OnCreate(context.Background(), &model.Inbox{ChannelType: "telegram"}, channel.ChannelConfig{"bot_token": "123:token"})
|
|
if err != nil {
|
|
t.Fatalf("expected successful OnCreate, got %v", err)
|
|
}
|
|
if config["reauthorization_required"] != false {
|
|
t.Fatalf("expected reauthorization_required=false, got %#v", config)
|
|
}
|
|
if config["webhook_url"] != "https://app.example.test/webhooks/telegram/123:token" {
|
|
t.Fatalf("unexpected webhook_url: %#v", config["webhook_url"])
|
|
}
|
|
}
|
|
|
|
func fakeTelegramRestyClient(t *testing.T, responses map[string]string) *resty.Client {
|
|
t.Helper()
|
|
client := resty.New()
|
|
client.SetTimeout(2 * time.Second)
|
|
client.SetRetryCount(0)
|
|
client.SetTransport(roundTripFunc(func(req *http.Request) (*http.Response, error) {
|
|
body, ok := responses[req.URL.Path]
|
|
if !ok {
|
|
t.Fatalf("unexpected telegram API request: %s %s", req.Method, req.URL.Path)
|
|
}
|
|
return &http.Response{
|
|
StatusCode: http.StatusOK,
|
|
Header: http.Header{"Content-Type": []string{"application/json"}},
|
|
Body: io.NopCloser(strings.NewReader(body)),
|
|
Request: req,
|
|
}, nil
|
|
}))
|
|
return client
|
|
}
|
|
|
|
type roundTripFunc func(*http.Request) (*http.Response, error)
|
|
|
|
func (fn roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
return fn(req)
|
|
}
|