| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- package admin
- import (
- "context"
- "database/sql"
- "encoding/json"
- "net/http"
- "net/http/httptest"
- "strings"
- "testing"
- "github.com/Wei-Shaw/sub2api/internal/service"
- "github.com/gin-gonic/gin"
- "github.com/stretchr/testify/require"
- )
- type stubGlobalPricingRepo struct {
- rows []service.GlobalModelPrice
- next int64
- }
- func (s *stubGlobalPricingRepo) ListEnabled(context.Context) ([]service.GlobalModelPrice, error) {
- out := make([]service.GlobalModelPrice, 0)
- for _, r := range s.rows {
- if r.Enabled {
- out = append(out, r)
- }
- }
- return out, nil
- }
- func (s *stubGlobalPricingRepo) ListAll(context.Context) ([]service.GlobalModelPrice, error) {
- return append([]service.GlobalModelPrice(nil), s.rows...), nil
- }
- func (s *stubGlobalPricingRepo) Create(_ context.Context, in service.GlobalModelPriceInput) (*service.GlobalModelPrice, error) {
- s.next++
- out := service.GlobalModelPrice{ID: s.next, ModelPattern: in.ModelPattern, BillingMode: in.BillingMode,
- InputPrice: in.InputPrice, OutputPrice: in.OutputPrice, Enabled: true}
- s.rows = append(s.rows, out)
- return &out, nil
- }
- func (s *stubGlobalPricingRepo) GetByID(_ context.Context, id int64) (*service.GlobalModelPrice, error) {
- for i := range s.rows {
- if s.rows[i].ID == id {
- cp := s.rows[i]
- return &cp, nil
- }
- }
- return nil, sql.ErrNoRows
- }
- func (s *stubGlobalPricingRepo) Update(_ context.Context, id int64, in service.GlobalModelPriceInput) (*service.GlobalModelPrice, error) {
- for i := range s.rows {
- if s.rows[i].ID == id {
- s.rows[i].ModelPattern = in.ModelPattern
- s.rows[i].Enabled = in.Enabled
- cp := s.rows[i]
- return &cp, nil
- }
- }
- return nil, sql.ErrNoRows
- }
- func (s *stubGlobalPricingRepo) Delete(_ context.Context, id int64) error {
- for i := range s.rows {
- if s.rows[i].ID == id {
- s.rows = append(s.rows[:i], s.rows[i+1:]...)
- return nil
- }
- }
- return sql.ErrNoRows
- }
- func (s *stubGlobalPricingRepo) SetEnabled(_ context.Context, id int64, enabled bool) error {
- for i := range s.rows {
- if s.rows[i].ID == id {
- s.rows[i].Enabled = enabled
- return nil
- }
- }
- return sql.ErrNoRows
- }
- func newGlobalPricingTestHandler() *GlobalPricingHandler {
- return NewGlobalPricingHandler(service.NewGlobalModelPricingService(&stubGlobalPricingRepo{}))
- }
- func serveGlobalPricing(h *GlobalPricingHandler, method, target, body string, params gin.Params) *httptest.ResponseRecorder {
- gin.SetMode(gin.TestMode)
- rec := httptest.NewRecorder()
- c, _ := gin.CreateTestContext(rec)
- var reader *strings.Reader
- if body == "" {
- reader = strings.NewReader("")
- } else {
- reader = strings.NewReader(body)
- }
- c.Request = httptest.NewRequest(method, target, reader)
- c.Request.Header.Set("Content-Type", "application/json")
- c.Params = params
- switch {
- case method == http.MethodGet:
- h.List(c)
- case method == http.MethodPost && strings.HasSuffix(target, "/enable"):
- h.SetEnabled(c)
- case method == http.MethodPost:
- h.Create(c)
- case method == http.MethodPut:
- h.Update(c)
- case method == http.MethodDelete:
- h.Delete(c)
- }
- return rec
- }
- func TestGlobalPricingHandlerListEmpty(t *testing.T) {
- rec := serveGlobalPricing(newGlobalPricingTestHandler(), http.MethodGet, "/api/v1/admin/global-pricing", "", nil)
- require.Equal(t, http.StatusOK, rec.Code)
- var resp struct {
- Code int `json:"code"`
- Data struct {
- Count int `json:"count"`
- } `json:"data"`
- }
- require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &resp))
- require.Equal(t, 0, resp.Code)
- require.Equal(t, 0, resp.Data.Count)
- }
- func TestGlobalPricingHandlerCreateAndToggle(t *testing.T) {
- h := newGlobalPricingTestHandler()
- rec := serveGlobalPricing(h, http.MethodPost, "/api/v1/admin/global-pricing",
- `{"model_pattern":"gpt-5","billing_mode":"token","input_price":0.000001}`, nil)
- require.Equal(t, http.StatusOK, rec.Code)
- rec = serveGlobalPricing(h, http.MethodPost, "/api/v1/admin/global-pricing/1/enable",
- `{"enabled":false}`, gin.Params{{Key: "id", Value: "1"}})
- require.Equal(t, http.StatusOK, rec.Code)
- rec = serveGlobalPricing(h, http.MethodGet, "/api/v1/admin/global-pricing", "", nil)
- require.Equal(t, http.StatusOK, rec.Code)
- }
- func TestGlobalPricingHandlerRejectsInvalid(t *testing.T) {
- h := newGlobalPricingTestHandler()
- rec := serveGlobalPricing(h, http.MethodPost, "/api/v1/admin/global-pricing",
- `{"model_pattern":"*foo","billing_mode":"token"}`, nil)
- require.NotEqual(t, http.StatusOK, rec.Code)
- }
- func TestGlobalPricingHandlerSetEnabledRequiresFlag(t *testing.T) {
- h := newGlobalPricingTestHandler()
- rec := serveGlobalPricing(h, http.MethodPost, "/api/v1/admin/global-pricing/1/enable",
- `{}`, gin.Params{{Key: "id", Value: "1"}})
- require.Equal(t, http.StatusBadRequest, rec.Code)
- }
- func TestGlobalPricingHandlerNotFound(t *testing.T) {
- h := newGlobalPricingTestHandler()
- params := gin.Params{{Key: "id", Value: "999"}}
- rec := serveGlobalPricing(h, http.MethodPut, "/api/v1/admin/global-pricing/999",
- `{"model_pattern":"gpt-5"}`, params)
- require.Equal(t, http.StatusNotFound, rec.Code)
- rec = serveGlobalPricing(h, http.MethodDelete, "/api/v1/admin/global-pricing/999", "", params)
- require.Equal(t, http.StatusNotFound, rec.Code)
- }
|