Files
dobotai-platform/internal/store/postgres/feedback_test.go

104 lines
3.6 KiB
Go

package postgres
import (
"os"
"strings"
"testing"
"gitea.zheromiku.top/Weknora/dobotai-platform/internal/feedback"
)
func TestFeedbackAnswerLookupRequiresExactDeliveredCard(t *testing.T) {
sql := strings.ToUpper(findFeedbackAnswerSQL)
for _, fragment := range []string{
"FROM MESSAGES M", "JOIN TURNS T", "T.TENANT_KEY=M.TENANT_KEY", "T.CHANNEL=M.CHANNEL",
"T.ANSWER_MESSAGE_ID=M.ID", "M.TENANT_KEY=$1", "M.CHANNEL=$2", "M.PROVIDER_MESSAGE_ID=$3",
"M.DIRECTION='OUTBOUND'", "M.ROLE='ASSISTANT'", "M.STATUS='SENT'", "M.DELIVERY_METHOD='CARD'",
"T.STATUS='SUCCEEDED'",
} {
if !strings.Contains(sql, fragment) {
t.Errorf("answer lookup missing %q", fragment)
}
}
}
func TestFeedbackActorAndStateSQLAreTenantChannelSafe(t *testing.T) {
actor := strings.ToUpper(upsertFeedbackActorSQL)
for _, fragment := range []string{
"INSERT INTO CHANNEL_ACTORS", "TENANT_KEY", "CHANNEL", "EXTERNAL_ACTOR_ID",
"ON CONFLICT (TENANT_KEY,CHANNEL,EXTERNAL_ACTOR_ID)", "RETURNING ID",
} {
if !strings.Contains(actor, fragment) {
t.Errorf("actor upsert missing %q", fragment)
}
}
lookup := strings.ToUpper(findFeedbackStateSQL)
for _, fragment := range []string{"TENANT_KEY=$1", "CHANNEL=$2", "ANSWER_MESSAGE_ID=$3", "ACTOR_ID=$4", "FOR UPDATE"} {
if !strings.Contains(lookup, fragment) {
t.Errorf("feedback lookup missing %q", fragment)
}
}
update := strings.ToUpper(updateFeedbackStateSQL)
for _, fragment := range []string{"VALUE=$1", "REASON_CODE=$2", "SOURCE=$3", "UPDATED_AT=NOW()", "ID=$4", "TENANT_KEY=$5", "CHANNEL=$6", "ANSWER_MESSAGE_ID=$7", "ACTOR_ID=$8"} {
if !strings.Contains(update, fragment) {
t.Errorf("feedback update missing %q", fragment)
}
}
}
func TestFeedbackStoreUsesShortSerializedTransaction(t *testing.T) {
data, err := os.ReadFile("feedback.go")
if err != nil {
t.Fatal(err)
}
source := strings.ToUpper(string(data))
for _, fragment := range []string{"BEGINTX", "PG_ADVISORY_XACT_LOCK", "ROLLBACK", "COMMIT"} {
if !strings.Contains(source, fragment) {
t.Errorf("feedback store missing transaction fragment %q", fragment)
}
}
for _, forbidden := range []string{"SESSIONWEBHOOK", "ACCESS_TOKEN", "RAW_CALLBACK", "RAW_PAYLOAD", "CORP_ID", "EXTENSION"} {
if strings.Contains(source, forbidden) {
t.Errorf("feedback store contains forbidden %q", forbidden)
}
}
}
func TestSameFeedbackState(t *testing.T) {
if !sameFeedbackState(feedback.ValueDown, feedback.ReasonUnclear, feedback.ValueDown, feedback.ReasonUnclear) {
t.Fatal("identical feedback must be replayed")
}
if sameFeedbackState(feedback.ValueDown, feedback.ReasonUnclear, feedback.ValueDown, feedback.ReasonOther) {
t.Fatal("reason change must be a state change")
}
if sameFeedbackState(feedback.ValueDown, "", feedback.ValueUp, "") {
t.Fatal("value change must be a state change")
}
}
func TestFeedbackDownvoteEnsuresIdempotentSupportCaseInsideTransaction(t *testing.T) {
data, err := os.ReadFile("feedback.go")
if err != nil {
t.Fatal(err)
}
source := strings.ToUpper(string(data))
for _, required := range []string{
"ENSUREFEEDBACKSUPPORTCASE",
"SELECT ID FROM COVERAGE_DECISIONS",
"TENANT_KEY=$1 AND CHANNEL=$2 AND TURN_ID=$3",
"INSERT INTO SUPPORT_CASES",
"TRIGGER_TYPE",
"TRIGGER_FEEDBACK_ID",
"'FEEDBACK_DOWN'",
"ON CONFLICT (TENANT_KEY,CHANNEL,TURN_ID) DO NOTHING",
"FAQEXPORTSTATUS(S.FAQEXPORTENABLED)",
} {
if !strings.Contains(source, required) {
t.Errorf("feedback support wiring missing %q", required)
}
}
if strings.Count(source, "ENSUREFEEDBACKSUPPORTCASE") < 4 {
t.Fatal("create, replay, and changed-down paths must all ensure the same idempotent support case")
}
}