fix(media-items): normalize NOT NULL narrators on every write path
A2 made narrators/narrators_search NOT NULL DEFAULT '{}' (86f0af6), but an
explicit NULL in an INSERT/UPDATE column list bypasses the column default
— the API media-create path (POST /api/media-items without narrators)
500'd on every call, taking the whole integration suite down with it
(ISBN tests, capture seeds, all direct-DB seeds).
- set_library_type_name() trigger now coalesces NULL narrators/
narrators_search to '{}' at the row level, and its update trigger
widens from BEFORE UPDATE OF library_id to BEFORE UPDATE so every
write path is covered
- defense in depth at the callers: handler create/update normalize nil
to empty slices (normalizeNarrators), scanner seeds the same
(nilToEmpty) for files that carry no narrator credits
- analytics device-usage tests move to the dedicated per-test user
(the shared admin's device list accrues live rows mid-suite — the
documented testuser flapping class)
This commit is contained in:
1 parent
73ae1789c5
commit
a222ef5c27
5 files changed
+56
-13
No files matched your search
@@ -135,8 +135,12 @@ func TestAnalyticsDeviceUsage(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetDeviceUsage_WithAuth_NoDevices", func(t *testing.T) {
|
||||
// The REGULAR per-test user, not the shared admin: testuser is a
|
||||
// LIVE reader whose device list accrues rows mid-suite (the app
|
||||
// genuinely registers against the dev DB while tests run), so the
|
||||
// "no devices" baseline is only deterministic on a fresh account.
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/device-usage", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+setup.Token)
|
||||
req.Header.Set("Authorization", "Bearer "+setup.RegularToken)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
@@ -152,7 +156,8 @@ func TestAnalyticsDeviceUsage(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetDeviceUsage_WithAuth_WithDevices", func(t *testing.T) {
|
||||
// First, create a device
|
||||
// Same dedicated-user doctrine: register + assert on the fresh
|
||||
// regular account instead of mutating the shared admin.
|
||||
deviceReq := map[string]interface{}{
|
||||
"device_name": "Test Kobo",
|
||||
"device_type": "kobo",
|
||||
@@ -161,7 +166,7 @@ func TestAnalyticsDeviceUsage(t *testing.T) {
|
||||
|
||||
deviceReqHTTP, _ := http.NewRequest("POST", setup.Server.URL+"/api/devices/register", bytes.NewBuffer(deviceBody))
|
||||
deviceReqHTTP.Header.Set("Content-Type", "application/json")
|
||||
deviceReqHTTP.Header.Set("Authorization", "Bearer "+setup.Token)
|
||||
deviceReqHTTP.Header.Set("Authorization", "Bearer "+setup.RegularToken)
|
||||
|
||||
resp, err := client.Do(deviceReqHTTP)
|
||||
require.NoError(t, err)
|
||||
@@ -171,7 +176,7 @@ func TestAnalyticsDeviceUsage(t *testing.T) {
|
||||
|
||||
// Now get device usage
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/device-usage", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+setup.Token)
|
||||
req.Header.Set("Authorization", "Bearer "+setup.RegularToken)
|
||||
|
||||
resp, err = client.Do(req)
|
||||
require.NoError(t, err)
|
||||
@@ -193,7 +198,7 @@ func TestAnalyticsDeviceUsage(t *testing.T) {
|
||||
|
||||
t.Run("GetDeviceUsage_ResponseStructure", func(t *testing.T) {
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/device-usage", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+setup.Token)
|
||||
req.Header.Set("Authorization", "Bearer "+setup.RegularToken)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
Reference in new issue
Block a user