Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 105 additions & 2 deletions coderd/aibridge/prices/prices_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package prices_test

import (
"fmt"
"testing"

"github.com/prometheus/client_golang/prometheus"
Expand Down Expand Up @@ -58,6 +59,7 @@ func TestSeedFromBytes(t *testing.T) {
require.Equal(t, int64(25_000_000), opus.OutputPrice.Int64)
require.Equal(t, int64(500_000), opus.CacheReadPrice.Int64)
require.Equal(t, int64(6_250_000), opus.CacheWritePrice.Int64)
require.Equal(t, opus.CreatedAt, opus.UpdatedAt)

// Spot-check a row where the seed has a NULL price (OpenAI does not
// publish a cache_write_price). The column should land as SQL NULL.
Expand Down Expand Up @@ -90,11 +92,11 @@ func TestSeedFromBytes(t *testing.T) {
})
require.NoError(t, err)

// Prices must be identical across runs and CreatedAt must be
// preserved (only updated_at moves on a no-op upsert).
// A re-seed that changes nothing must not touch the row at all.
require.Equal(t, first.InputPrice, second.InputPrice)
require.Equal(t, first.OutputPrice, second.OutputPrice)
require.Equal(t, first.CreatedAt, second.CreatedAt)
require.Equal(t, first.UpdatedAt, second.UpdatedAt)
})

t.Run("OverwritesExistingPrices", func(t *testing.T) {
Expand All @@ -114,6 +116,10 @@ func TestSeedFromBytes(t *testing.T) {
"cache_read_price": 3,
"cache_write_price": 4
}]`)))
before, err := db.GetAIModelPriceByProviderModel(ctx, database.GetAIModelPriceByProviderModelParams{
Provider: "openai", Model: "gpt-4o",
})
require.NoError(t, err)

require.NoError(t, prices.SeedFromBytes(ctx, db, []byte(testSeedJSON)))

Expand All @@ -126,6 +132,8 @@ func TestSeedFromBytes(t *testing.T) {
require.Equal(t, int64(1_250_000), got.CacheReadPrice.Int64)
require.False(t, got.CacheWritePrice.Valid)
require.Zero(t, got.CacheWritePrice.Int64)
require.Equal(t, before.CreatedAt, got.CreatedAt)
require.True(t, got.UpdatedAt.After(before.UpdatedAt))
})

t.Run("LeavesOrphanRowsUntouched", func(t *testing.T) {
Expand Down Expand Up @@ -174,6 +182,101 @@ func TestSeedFromBytes(t *testing.T) {
require.True(t, got.InputPrice.Valid)
require.Equal(t, int64(2_500_000), got.InputPrice.Int64)
})

// Every price column counts toward the comparison, and a NULL on either
// side counts as a difference.
t.Run("UpdatedAtTracksPriceChanges", func(t *testing.T) {
t.Parallel()

key := database.GetAIModelPriceByProviderModelParams{Provider: "openai", Model: "gpt-4o"}
seed := func(priceFields string) []byte {
return fmt.Appendf(nil, `[{"provider": %q, "model": %q, %s}]`, key.Provider, key.Model, priceFields)
}

tests := []struct {
name string
initial, updated string
}{
{
name: "InputPriceChanged",
initial: `"input_price": 100, "output_price": 200, "cache_read_price": 300, "cache_write_price": 400`,
updated: `"input_price": 111, "output_price": 200, "cache_read_price": 300, "cache_write_price": 400`,
},
{
name: "InputPriceSetFromNull",
initial: `"input_price": null, "output_price": 200, "cache_read_price": 300, "cache_write_price": 400`,
updated: `"input_price": 100, "output_price": 200, "cache_read_price": 300, "cache_write_price": 400`,
},
{
name: "InputPriceClearedToNull",
initial: `"input_price": 100, "output_price": 200, "cache_read_price": 300, "cache_write_price": 400`,
updated: `"input_price": null, "output_price": 200, "cache_read_price": 300, "cache_write_price": 400`,
},
{
name: "OutputPriceChanged",
initial: `"input_price": 100, "output_price": 200, "cache_read_price": 300, "cache_write_price": 400`,
updated: `"input_price": 100, "output_price": 222, "cache_read_price": 300, "cache_write_price": 400`,
},
{
name: "OutputPriceSetFromNull",
initial: `"input_price": 100, "output_price": null, "cache_read_price": 300, "cache_write_price": 400`,
updated: `"input_price": 100, "output_price": 200, "cache_read_price": 300, "cache_write_price": 400`,
},
{
name: "OutputPriceClearedToNull",
initial: `"input_price": 100, "output_price": 200, "cache_read_price": 300, "cache_write_price": 400`,
updated: `"input_price": 100, "output_price": null, "cache_read_price": 300, "cache_write_price": 400`,
},
{
name: "CacheReadPriceChanged",
initial: `"input_price": 100, "output_price": 200, "cache_read_price": 300, "cache_write_price": 400`,
updated: `"input_price": 100, "output_price": 200, "cache_read_price": 333, "cache_write_price": 400`,
},
{
name: "CacheReadPriceSetFromNull",
initial: `"input_price": 100, "output_price": 200, "cache_read_price": null, "cache_write_price": 400`,
updated: `"input_price": 100, "output_price": 200, "cache_read_price": 300, "cache_write_price": 400`,
},
{
name: "CacheReadPriceClearedToNull",
initial: `"input_price": 100, "output_price": 200, "cache_read_price": 300, "cache_write_price": 400`,
updated: `"input_price": 100, "output_price": 200, "cache_read_price": null, "cache_write_price": 400`,
},
{
name: "CacheWritePriceChanged",
initial: `"input_price": 100, "output_price": 200, "cache_read_price": 300, "cache_write_price": 400`,
updated: `"input_price": 100, "output_price": 200, "cache_read_price": 300, "cache_write_price": 444`,
},
{
name: "CacheWritePriceSetFromNull",
initial: `"input_price": 100, "output_price": 200, "cache_read_price": 300, "cache_write_price": null`,
updated: `"input_price": 100, "output_price": 200, "cache_read_price": 300, "cache_write_price": 400`,
},
{
name: "CacheWritePriceClearedToNull",
initial: `"input_price": 100, "output_price": 200, "cache_read_price": 300, "cache_write_price": 400`,
updated: `"input_price": 100, "output_price": 200, "cache_read_price": 300, "cache_write_price": null`,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
ctx := testutil.Context(t, testutil.WaitShort)
db, _ := dbtestutil.NewDB(t)

require.NoError(t, prices.SeedFromBytes(ctx, db, seed(tt.initial)))
before, err := db.GetAIModelPriceByProviderModel(ctx, key)
require.NoError(t, err)

require.NoError(t, prices.SeedFromBytes(ctx, db, seed(tt.updated)))
after, err := db.GetAIModelPriceByProviderModel(ctx, key)
require.NoError(t, err)

require.True(t, after.UpdatedAt.After(before.UpdatedAt), "updated_at should advance when a price changes")
})
}
})
}

// TestSeed exercises the real embedded prices.json so we catch a corrupted,
Expand Down
3 changes: 3 additions & 0 deletions coderd/database/querier.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions coderd/database/queries.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 15 additions & 1 deletion coderd/database/queries/aicostcontrol.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
-- Upsert a batch of (provider, model) rows from a JSON array. Each element
-- must have provider, model, and the four price fields; null prices are
-- written as SQL NULL.
-- A conflicting row is only rewritten when a price differs, so updated_at
-- records when a price last changed. Prices are nullable and a NULL on
-- either side counts as a difference.
INSERT INTO ai_model_prices (
provider, model, input_price, output_price, cache_read_price, cache_write_price
)
Expand All @@ -18,7 +21,18 @@ ON CONFLICT (provider, model) DO UPDATE SET
output_price = EXCLUDED.output_price,
cache_read_price = EXCLUDED.cache_read_price,
cache_write_price = EXCLUDED.cache_write_price,
updated_at = NOW();
updated_at = NOW()
WHERE (
ai_model_prices.input_price,
ai_model_prices.output_price,
ai_model_prices.cache_read_price,
ai_model_prices.cache_write_price
) IS DISTINCT FROM (
EXCLUDED.input_price,
EXCLUDED.output_price,
EXCLUDED.cache_read_price,
EXCLUDED.cache_write_price
);

-- name: GetAIModelPriceByProviderModel :one
SELECT *
Expand Down
Loading