mirror of
https://github.com/tiennm99/miti99bot.git
synced 2026-10-04 04:13:33 +00:00
The bot now takes the renderer's base URL and appends each /api/<name> route itself, instead of taking the full /api/gif endpoint and swapping its last path segment for /gacha and /genshin. The client, its files, and its errors are named after the renderer rather than wheelofnames; the /wheelofnames command keeps its name. BREAKING CHANGE: WHEELOFNAMES_API_URL is replaced by RENDERER_URL, which holds the base URL (e.g. http://renderer:3000) rather than the /api/gif endpoint. compose.yml sets it, so Coolify needs no value.
225 lines
7.2 KiB
Go
225 lines
7.2 KiB
Go
package random
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/tiennm99/miti99bot/internal/testutil"
|
|
)
|
|
|
|
var mp4Bytes = []byte("\x00\x00\x00\x18ftypisom-remote")
|
|
|
|
func TestParseGachaOptions(t *testing.T) {
|
|
got := parseGachaOptions(" Pizza, 4* Pho , 3*Rice, 3 * Bun, 5* Cake, 5*, , 7* Tea, a*b, Pho 4* ")
|
|
want := []gachaOption{
|
|
{Label: "Pizza", Rarity: 5},
|
|
{Label: "Pho", Rarity: 4},
|
|
{Label: "Rice", Rarity: 3},
|
|
{Label: "Bun", Rarity: 3},
|
|
{Label: "Cake", Rarity: 5},
|
|
{Label: "7* Tea", Rarity: 5},
|
|
{Label: "a*b", Rarity: 5},
|
|
{Label: "Pho 4*", Rarity: 5},
|
|
}
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Fatalf("parseGachaOptions() = %#v, want %#v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestGacha_EmptyArgsRepliesUsage(t *testing.T) {
|
|
for _, text := range []string{"/gacha", "/gacha , ,", "/gacha 5*"} {
|
|
t.Run(text, func(t *testing.T) {
|
|
rb := installRandom(t, 999)
|
|
rb.Bot.ProcessUpdate(context.Background(), testutil.NewPrivateMessage(7, text))
|
|
|
|
if got := rb.LastSent().Text(); got != gachaUsage {
|
|
t.Errorf("gacha reply = %q, want usage %q", got, gachaUsage)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGacha_NotConfiguredRepliesWithStars(t *testing.T) {
|
|
rb := installRandom(t, 999)
|
|
rb.Bot.ProcessUpdate(context.Background(), testutil.NewPrivateMessage(7, "/gacha Pizza"))
|
|
|
|
calls := rb.Sent()
|
|
if len(calls) != 1 || calls[0].Method != "sendMessage" || calls[0].Text() != "★★★★★ Pizza" {
|
|
t.Fatalf("calls = %+v, want a single ★★★★★ Pizza reply", calls)
|
|
}
|
|
}
|
|
|
|
func TestGacha_UsesRemoteAPIWhenConfigured(t *testing.T) {
|
|
var got gachaRenderRequest
|
|
var gotPath, gotAuthorization string
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
gotPath = r.URL.Path
|
|
gotAuthorization = r.Header.Get("Authorization")
|
|
if err := json.NewDecoder(r.Body).Decode(&got); err != nil {
|
|
t.Errorf("Decode request body: %v", err)
|
|
}
|
|
w.Header().Set("Content-Type", "video/mp4")
|
|
_, _ = w.Write(mp4Bytes)
|
|
}))
|
|
defer server.Close()
|
|
t.Setenv(rendererURLEnv, server.URL)
|
|
|
|
rb := installRandom(t, 999)
|
|
rb.Bot.ProcessUpdate(context.Background(), testutil.NewPrivateMessage(7, "/gacha 4* Pho"))
|
|
|
|
if gotPath != "/api/gacha" {
|
|
t.Fatalf("path = %q, want /api/gacha", gotPath)
|
|
}
|
|
if gotAuthorization != "" {
|
|
t.Fatalf("Authorization = %q, want none", gotAuthorization)
|
|
}
|
|
want := gachaRenderRequest{Label: "Pho", Rarity: 4, FPS: gachaRemoteFPS, Width: gachaRemoteWidth}
|
|
if got != want {
|
|
t.Fatalf("request = %+v, want %+v", got, want)
|
|
}
|
|
|
|
sent := rb.Sent()
|
|
if len(sent) != 3 {
|
|
t.Fatalf("calls = %+v, want placeholder, sendAnimation, deleteMessage", sent)
|
|
}
|
|
if sent[0].Method != "sendMessage" || sent[0].Text() != gachaPlaceholder {
|
|
t.Fatalf("first call = %+v, want placeholder %q", sent[0], gachaPlaceholder)
|
|
}
|
|
if sent[2].Method != "deleteMessage" || sent[2].Form["message_id"] != "1" {
|
|
t.Fatalf("last call = %+v, want deleteMessage of the placeholder", sent[2])
|
|
}
|
|
call := sent[1]
|
|
if call.Method != "sendAnimation" {
|
|
t.Fatalf("method = %q, want sendAnimation", call.Method)
|
|
}
|
|
if want := `Result: <span class="tg-spoiler">★★★★ Pho</span>`; call.Form["caption"] != want {
|
|
t.Fatalf("caption = %q, want %q", call.Form["caption"], want)
|
|
}
|
|
for field, want := range map[string]string{"parse_mode": "HTML", "duration": "6", "width": "360", "height": "640"} {
|
|
if got := call.Form[field]; got != want {
|
|
t.Fatalf("%s = %q, want %q", field, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGacha_RemoteFailureFallsBackToText(t *testing.T) {
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
http.Error(w, "no", http.StatusInternalServerError)
|
|
}))
|
|
defer server.Close()
|
|
t.Setenv(rendererURLEnv, server.URL)
|
|
|
|
rb := installRandom(t, 999)
|
|
rb.Bot.ProcessUpdate(context.Background(), testutil.NewPrivateMessage(7, "/gacha 3* Rice"))
|
|
|
|
sent := rb.Sent()
|
|
if len(sent) != 2 {
|
|
t.Fatalf("calls = %+v, want placeholder then in-place edit", sent)
|
|
}
|
|
if sent[1].Method != "editMessageText" || sent[1].Text() != "★★★ Rice" {
|
|
t.Fatalf("fallback call = %+v, want editMessageText ★★★ Rice", sent[1])
|
|
}
|
|
}
|
|
|
|
func TestGacha_SendAnimationFailureFallsBackToText(t *testing.T) {
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
w.Header().Set("Content-Type", "video/mp4")
|
|
_, _ = w.Write(mp4Bytes)
|
|
}))
|
|
defer server.Close()
|
|
t.Setenv(rendererURLEnv, server.URL)
|
|
|
|
rb := installRandom(t, 999)
|
|
rb.FailMethod("sendAnimation", http.StatusInternalServerError, "")
|
|
rb.Bot.ProcessUpdate(context.Background(), testutil.NewPrivateMessage(7, "/gacha 3* Rice"))
|
|
|
|
call := rb.LastSent()
|
|
if call.Method != "editMessageText" || call.Text() != "★★★ Rice" {
|
|
t.Fatalf("fallback call = %+v, want editMessageText ★★★ Rice", call)
|
|
}
|
|
}
|
|
|
|
func TestGacha_ForwardsMessageThreadID(t *testing.T) {
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
w.Header().Set("Content-Type", "video/mp4")
|
|
_, _ = w.Write(mp4Bytes)
|
|
}))
|
|
defer server.Close()
|
|
t.Setenv(rendererURLEnv, server.URL)
|
|
|
|
rb := installRandom(t, 999)
|
|
update := testutil.NewSupergroupMessage(-100, 7, "/gacha 3* Rice")
|
|
update.Message.MessageThreadID = 42
|
|
rb.Bot.ProcessUpdate(context.Background(), update)
|
|
|
|
animations := 0
|
|
for _, call := range rb.Sent() {
|
|
switch call.Method {
|
|
case "sendMessage", "sendAnimation":
|
|
if got := call.Form["message_thread_id"]; got != "42" {
|
|
t.Fatalf("%s message_thread_id = %q, want 42", call.Method, got)
|
|
}
|
|
if call.Method == "sendAnimation" {
|
|
animations++
|
|
}
|
|
}
|
|
}
|
|
if animations != 1 {
|
|
t.Fatalf("sendAnimation calls = %d, want 1", animations)
|
|
}
|
|
}
|
|
|
|
func TestGenshin_UsesGenshinRendererAndAnyoneCanRunIt(t *testing.T) {
|
|
var gotPath string
|
|
var got gachaRenderRequest
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
gotPath = r.URL.Path
|
|
if err := json.NewDecoder(r.Body).Decode(&got); err != nil {
|
|
t.Errorf("Decode request body: %v", err)
|
|
}
|
|
w.Header().Set("Content-Type", "video/mp4")
|
|
_, _ = w.Write(mp4Bytes)
|
|
}))
|
|
defer server.Close()
|
|
t.Setenv(rendererURLEnv, server.URL)
|
|
|
|
// 7 is neither the owner (999) nor an admin.
|
|
rb := installRandom(t, 999)
|
|
rb.Bot.ProcessUpdate(context.Background(), testutil.NewPrivateMessage(7, "/genshin Bún bò"))
|
|
|
|
if gotPath != "/api/genshin" {
|
|
t.Fatalf("path = %q, want /api/genshin", gotPath)
|
|
}
|
|
if want := (gachaRenderRequest{Label: "Bún bò", Rarity: 5, FPS: gachaRemoteFPS, Width: gachaRemoteWidth}); got != want {
|
|
t.Fatalf("request = %+v, want %+v", got, want)
|
|
}
|
|
var animation *testutil.SentCall
|
|
sent := rb.Sent()
|
|
for i := range sent {
|
|
if sent[i].Method == "sendAnimation" {
|
|
animation = &sent[i]
|
|
}
|
|
}
|
|
if animation == nil {
|
|
t.Fatalf("calls = %+v, want a sendAnimation", rb.Sent())
|
|
}
|
|
for field, want := range map[string]string{"duration": "7", "width": "640", "height": "360"} {
|
|
if got := animation.Form[field]; got != want {
|
|
t.Fatalf("%s = %q, want %s", field, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGenshin_EmptyArgsRepliesGenshinUsage(t *testing.T) {
|
|
rb := installRandom(t, 999)
|
|
rb.Bot.ProcessUpdate(context.Background(), testutil.NewPrivateMessage(7, "/genshin"))
|
|
|
|
if got := rb.LastSent().Text(); got != genshinUsage {
|
|
t.Errorf("genshin reply = %q, want usage %q", got, genshinUsage)
|
|
}
|
|
}
|