f99010fae1
Desktop Artifacts / Desktop Build (Linux) (push) Waiting to run
Desktop Artifacts / Desktop Build (Windows) (push) Waiting to run
Desktop Artifacts / Desktop Build (Linux (arm64)) (push) Waiting to run
Desktop Artifacts (macOS) / Desktop Build (macOS (aarch64)) (push) Waiting to run
Desktop Artifacts (macOS) / Desktop Build (macOS (x86_64)) (push) Waiting to run
CI / lint (push) Failing after 1s
CI / frontend (push) Failing after 1s
CI / scripts (push) Failing after 1s
CI / Go Test (ubuntu-latest) (push) Failing after 0s
CI / frontend-node-25 (push) Failing after 1s
CI / docs (push) Failing after 0s
CI / coverage (push) Failing after 0s
CI / e2e (push) Failing after 0s
Docker / build-and-push (push) Failing after 1s
CI / integration (push) Failing after 4m43s
CI / Go Test (windows-latest) (push) Has been cancelled
CI / Desktop Unit Tests (Windows) (push) Has been cancelled
206 lines
6.5 KiB
Go
206 lines
6.5 KiB
Go
//go:build pgtest
|
|
|
|
package postgres
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"go.kenn.io/agentsview/internal/db"
|
|
)
|
|
|
|
func TestStoreSessionAndMessageTokenUsage(t *testing.T) {
|
|
pgURL := testPGURL(t)
|
|
ensureStoreSchema(t, pgURL)
|
|
|
|
pg, err := Open(pgURL, testSchema, false)
|
|
require.NoError(t, err, "Open")
|
|
defer pg.Close()
|
|
|
|
_, err = pg.Exec(`
|
|
INSERT INTO sessions (
|
|
id, machine, project, agent,
|
|
message_count, user_message_count,
|
|
total_output_tokens, peak_context_tokens,
|
|
has_total_output_tokens, has_peak_context_tokens
|
|
) VALUES (
|
|
'token-store-001', 'test-machine', 'test-project', 'claude',
|
|
1, 1, 500, 900, TRUE, TRUE
|
|
)
|
|
ON CONFLICT (id) DO UPDATE SET
|
|
total_output_tokens = EXCLUDED.total_output_tokens,
|
|
peak_context_tokens = EXCLUDED.peak_context_tokens,
|
|
has_total_output_tokens = EXCLUDED.has_total_output_tokens,
|
|
has_peak_context_tokens = EXCLUDED.has_peak_context_tokens
|
|
`)
|
|
require.NoError(t, err, "insert session")
|
|
_, err = pg.Exec(`
|
|
INSERT INTO messages (
|
|
session_id, ordinal, role, content,
|
|
content_length, model, token_usage,
|
|
context_tokens, output_tokens,
|
|
has_context_tokens, has_output_tokens
|
|
) VALUES (
|
|
'token-store-001', 0, 'assistant', 'hello',
|
|
5, 'claude-sonnet-4-20250514', '{"output_tokens":200}',
|
|
900, 200, TRUE, TRUE
|
|
)
|
|
ON CONFLICT (session_id, ordinal) DO UPDATE SET
|
|
context_tokens = EXCLUDED.context_tokens,
|
|
output_tokens = EXCLUDED.output_tokens,
|
|
has_context_tokens = EXCLUDED.has_context_tokens,
|
|
has_output_tokens = EXCLUDED.has_output_tokens
|
|
`)
|
|
require.NoError(t, err, "insert message")
|
|
|
|
store, err := NewStore(pgURL, testSchema, true)
|
|
require.NoError(t, err, "NewStore")
|
|
defer store.Close()
|
|
|
|
ctx := context.Background()
|
|
sess, err := store.GetSession(ctx, "token-store-001")
|
|
require.NoError(t, err, "GetSession")
|
|
require.NotNil(t, sess)
|
|
assert.True(t, sess.HasTotalOutputTokens)
|
|
assert.True(t, sess.HasPeakContextTokens)
|
|
assert.Equal(t, 500, sess.TotalOutputTokens)
|
|
|
|
msgs, err := store.GetMessages(ctx, "token-store-001", 0, 10, true)
|
|
require.NoError(t, err, "GetMessages")
|
|
require.Len(t, msgs, 1)
|
|
assert.True(t, msgs[0].HasOutputTokens)
|
|
assert.True(t, msgs[0].HasContextTokens)
|
|
assert.Equal(t, 200, msgs[0].OutputTokens)
|
|
}
|
|
|
|
func TestPushTokenUsageToPostgres(t *testing.T) {
|
|
pgURL := testPGURL(t)
|
|
cleanPGSchema(t, pgURL)
|
|
t.Cleanup(func() { cleanPGSchema(t, pgURL) })
|
|
|
|
local := testDB(t)
|
|
ps, err := New(pgURL, "agentsview", local, "test-machine", true, SyncOptions{})
|
|
require.NoError(t, err, "creating sync")
|
|
defer ps.Close()
|
|
|
|
ctx := context.Background()
|
|
require.NoError(t, ps.EnsureSchema(ctx), "EnsureSchema")
|
|
|
|
sess := db.Session{
|
|
ID: "token-push-001",
|
|
Project: "proj",
|
|
Machine: "local",
|
|
Agent: "claude",
|
|
MessageCount: 1,
|
|
UserMessageCount: 0,
|
|
TotalOutputTokens: 500,
|
|
PeakContextTokens: 900,
|
|
HasTotalOutputTokens: true,
|
|
HasPeakContextTokens: true,
|
|
}
|
|
require.NoError(t, local.UpsertSession(sess), "UpsertSession")
|
|
require.NoError(t, local.InsertMessages([]db.Message{{
|
|
SessionID: "token-push-001",
|
|
Ordinal: 0,
|
|
Role: "assistant",
|
|
Content: "hello",
|
|
ContentLength: 5,
|
|
Model: "claude-sonnet-4-20250514",
|
|
TokenUsage: json.RawMessage(`{"output_tokens":200}`),
|
|
ContextTokens: 900,
|
|
OutputTokens: 200,
|
|
HasContextTokens: true,
|
|
HasOutputTokens: true,
|
|
}}), "InsertMessages")
|
|
|
|
_, err = ps.Push(ctx, false, nil)
|
|
require.NoError(t, err, "Push")
|
|
|
|
store, err := NewStore(pgURL, "agentsview", true)
|
|
require.NoError(t, err, "NewStore")
|
|
defer store.Close()
|
|
|
|
gotSess, err := store.GetSession(ctx, "token-push-001")
|
|
require.NoError(t, err, "GetSession")
|
|
require.NotNil(t, gotSess, "expected pushed session")
|
|
assert.True(t, gotSess.HasTotalOutputTokens)
|
|
assert.True(t, gotSess.HasPeakContextTokens)
|
|
assert.Equal(t, 500, gotSess.TotalOutputTokens)
|
|
|
|
gotMsgs, err := store.GetMessages(ctx, "token-push-001", 0, 10, true)
|
|
require.NoError(t, err, "GetMessages")
|
|
require.Len(t, gotMsgs, 1)
|
|
assert.True(t, gotMsgs[0].HasContextTokens)
|
|
assert.True(t, gotMsgs[0].HasOutputTokens)
|
|
assert.Equal(t, 200, gotMsgs[0].OutputTokens)
|
|
}
|
|
|
|
func TestEnsureSchemaBackfillsTokenCoverageFlags(t *testing.T) {
|
|
pgURL := testPGURL(t)
|
|
cleanPGSchema(t, pgURL)
|
|
t.Cleanup(func() { cleanPGSchema(t, pgURL) })
|
|
|
|
pg, err := Open(pgURL, "agentsview", false)
|
|
require.NoError(t, err, "Open")
|
|
defer pg.Close()
|
|
|
|
ctx := context.Background()
|
|
require.NoError(t, EnsureSchema(ctx, pg, "agentsview"), "EnsureSchema initial")
|
|
|
|
_, err = pg.Exec(`
|
|
INSERT INTO sessions (
|
|
id, machine, project, agent, message_count,
|
|
total_output_tokens, peak_context_tokens,
|
|
has_total_output_tokens, has_peak_context_tokens
|
|
) VALUES
|
|
('pg-legacy-nonzero', 'test-machine', 'proj', 'claude', 0,
|
|
200, 600, FALSE, FALSE),
|
|
('pg-legacy-zero', 'test-machine', 'proj', 'claude', 1,
|
|
0, 0, FALSE, FALSE)
|
|
`)
|
|
require.NoError(t, err, "insert legacy sessions")
|
|
_, err = pg.Exec(`
|
|
INSERT INTO messages (
|
|
session_id, ordinal, role, content, content_length,
|
|
model, token_usage, context_tokens, output_tokens,
|
|
has_context_tokens, has_output_tokens
|
|
) VALUES
|
|
('pg-legacy-zero', 0, 'assistant', 'hi', 2,
|
|
'claude-sonnet-4-20250514',
|
|
'{"input_tokens":0,"output_tokens":0}', 0, 0, FALSE, FALSE)
|
|
`)
|
|
require.NoError(t, err, "insert legacy message")
|
|
|
|
require.NoError(t, EnsureSchema(ctx, pg, "agentsview"), "EnsureSchema backfill")
|
|
|
|
store, err := NewStore(pgURL, "agentsview", true)
|
|
require.NoError(t, err, "NewStore")
|
|
defer store.Close()
|
|
|
|
nonzero, err := store.GetSession(ctx, "pg-legacy-nonzero")
|
|
require.NoError(t, err, "GetSession nonzero")
|
|
require.NotNil(t, nonzero, "pg-legacy-nonzero missing")
|
|
assert.True(t, nonzero.HasTotalOutputTokens,
|
|
"pg-legacy-nonzero HasTotalOutputTokens")
|
|
assert.True(t, nonzero.HasPeakContextTokens,
|
|
"pg-legacy-nonzero HasPeakContextTokens")
|
|
|
|
zero, err := store.GetSession(ctx, "pg-legacy-zero")
|
|
require.NoError(t, err, "GetSession zero")
|
|
require.NotNil(t, zero, "pg-legacy-zero missing")
|
|
assert.True(t, zero.HasTotalOutputTokens,
|
|
"pg-legacy-zero HasTotalOutputTokens")
|
|
assert.True(t, zero.HasPeakContextTokens,
|
|
"pg-legacy-zero HasPeakContextTokens")
|
|
|
|
msgs, err := store.GetMessages(ctx, "pg-legacy-zero", 0, 10, true)
|
|
require.NoError(t, err, "GetMessages zero")
|
|
require.Len(t, msgs, 1)
|
|
assert.True(t, msgs[0].HasContextTokens, "message HasContextTokens")
|
|
assert.True(t, msgs[0].HasOutputTokens, "message HasOutputTokens")
|
|
}
|