Білінг: запит читав старі імена колонок usage_now
Агент свідомо перейменував вихідні колонки функції на devices_used, maps_used, agents_used, users_used — щоб `devices` поруч із таблицею inv.devices не давало неоднозначності. Запит у Go лишився на старих іменах. Код збирався, локальні тести були зелені (пропускались без NETPULSE_TEST_DSN), а перше ж звернення до бази падало з «column "devices" does not exist». Сторінка білінгу не показала б нічого. Знайдено пісочницею: установка зі свіжого клону, 63 міграції на чистій базі, потім тести з живою БД. Це той самий клас, що ловився весь день — зелена перевірка доводить рівно те, що перевіряє, а тест, який мовчки пропускається, не перевіряє нічого. Заодно записано в шапці api_test.go умову, якої той набір вимагає: база має бути порожньою. Користувачі в продукті глобальні, і на вже поставленій системі seedUser натрапляє на власника admin.
This commit is contained in:
parent
ca143a616b
commit
c8b9d08c0b
2 changed files with 26 additions and 1 deletions
|
|
@ -1,6 +1,24 @@
|
||||||
// Наскрізний тест API: справжня БД, справжній HTTP, справжній WebSocket.
|
// Наскрізний тест API: справжня БД, справжній HTTP, справжній WebSocket.
|
||||||
//
|
//
|
||||||
// NETPULSE_TEST_DSN="postgres://netpulse:netpulse@localhost/netpulse_it" go test ./...
|
// NETPULSE_TEST_DSN="postgres://netpulse:netpulse@localhost/netpulse_it" go test ./...
|
||||||
|
//
|
||||||
|
// БАЗА МАЄ БУТИ ПОРОЖНЬОЮ — лише зі схемою, без даних.
|
||||||
|
//
|
||||||
|
// Кабінети тут унікальні (slug із наносекундами), а от КОРИСТУВАЧІ в
|
||||||
|
// цьому продукті глобальні: одна людина може працювати в кількох
|
||||||
|
// кабінетах, тому `core.users.username` унікальний наскрізно, і
|
||||||
|
// CreateUser при зіткненні свідомо підхоплює наявного, НЕ переписуючи
|
||||||
|
// пароль (users.go, і це правильно: інакше адмін одного кабінету міняв
|
||||||
|
// би пароль людини в чужому).
|
||||||
|
//
|
||||||
|
// Наслідок для тестів: на базі, де вже стоїть робоча інсталяція,
|
||||||
|
// seedUser("admin@example.com") натрапляє на власника з ім'ям `admin`,
|
||||||
|
// пароль лишається чужим, вхід не вдається — і тест падає на 401 у
|
||||||
|
// зовсім іншому місці. Це не поломка продукту, а невиконана умова.
|
||||||
|
//
|
||||||
|
// Так знайшлось: набір прогнали проти пісочниці установника, тобто
|
||||||
|
// проти ВЖЕ поставленої системи. CI і `./netpulse sandbox once` дають
|
||||||
|
// чисту базу, тому там усе зелене.
|
||||||
package httpapi_test
|
package httpapi_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -298,7 +298,14 @@ func (s *Store) TenantUsage(ctx context.Context, tenantID string) (Usage, error)
|
||||||
var u Usage
|
var u Usage
|
||||||
err := s.InTenantTx(ctx, tenantID, func(tx pgx.Tx) error {
|
err := s.InTenantTx(ctx, tenantID, func(tx pgx.Tx) error {
|
||||||
return tx.QueryRow(ctx,
|
return tx.QueryRow(ctx,
|
||||||
`SELECT devices, maps, agents, users FROM bill.usage_now($1)`, tenantID).
|
// Суфікс `_used` — не косметика: функція повертає колонки з
|
||||||
|
// цими іменами саме тому, що `devices` поруч із таблицею
|
||||||
|
// inv.devices дає неоднозначність (пояснення в 0069). Тут
|
||||||
|
// імена спершу лишились старими, і це знайшлось лише в
|
||||||
|
// пісочниці: код збирався, а перший же запит до бази падав
|
||||||
|
// з «column "devices" does not exist».
|
||||||
|
`SELECT devices_used, maps_used, agents_used, users_used
|
||||||
|
FROM bill.usage_now($1)`, tenantID).
|
||||||
Scan(&u.Devices, &u.Maps, &u.Agents, &u.Users)
|
Scan(&u.Devices, &u.Maps, &u.Agents, &u.Users)
|
||||||
})
|
})
|
||||||
return u, err
|
return u, err
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue