Merge remote-tracking branch 'upstream/main' into codex/fix-antigravity-quota

This commit is contained in:
ZheFox
2026-09-03 13:24:39 +08:00
94 changed files with 1926 additions and 3765 deletions
@@ -0,0 +1,3 @@
ALTER TABLE routing_groups
ADD COLUMN sort_order BIGINT NOT NULL DEFAULT 0,
ADD KEY routing_groups_enabled_sort_idx (enabled, sort_order, name, id);
@@ -15,6 +15,7 @@ SELECT
description,
enabled,
is_system_default,
sort_order,
config_json,
version,
created_at,
@@ -61,10 +62,12 @@ impl MysqlRoutingGroupRepository {
#[async_trait]
impl RoutingGroupReadRepository for MysqlRoutingGroupRepository {
async fn list_routing_groups(&self) -> Result<Vec<StoredRoutingGroup>, DataLayerError> {
let rows = sqlx::query(&format!("{ROUTING_GROUP_SELECT} ORDER BY name ASC, id ASC"))
.fetch_all(&self.pool)
.await
.map_sql_err()?;
let rows = sqlx::query(&format!(
"{ROUTING_GROUP_SELECT} ORDER BY enabled DESC, sort_order ASC, name ASC, id ASC"
))
.fetch_all(&self.pool)
.await
.map_sql_err()?;
rows.iter().map(map_group_row).collect()
}
@@ -173,10 +176,10 @@ impl RoutingGroupWriteRepository for MysqlRoutingGroupRepository {
sqlx::query(
r#"
INSERT INTO routing_groups (
id, name, description, enabled, is_system_default, config_json,
id, name, description, enabled, is_system_default, sort_order, config_json,
version, created_at, updated_at, published_at
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
"#,
)
.bind(&group.id)
@@ -184,6 +187,7 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
.bind(&group.description)
.bind(group.enabled)
.bind(group.is_system_default)
.bind(group.sort_order)
.bind(json_to_string(
&group.config_json,
"routing_groups.config_json",
@@ -241,6 +245,7 @@ SET name = ?,
description = ?,
enabled = ?,
is_system_default = ?,
sort_order = ?,
config_json = ?,
version = ?,
updated_at = ?,
@@ -252,6 +257,7 @@ WHERE id = ?
.bind(&group.description)
.bind(group.enabled)
.bind(group.is_system_default)
.bind(group.sort_order)
.bind(json_to_string(
&group.config_json,
"routing_groups.config_json",
@@ -460,6 +466,7 @@ fn map_group_row(row: &MySqlRow) -> Result<StoredRoutingGroup, DataLayerError> {
description: row.try_get("description").map_sql_err()?,
enabled: row.try_get("enabled").map_sql_err()?,
is_system_default: row.try_get("is_system_default").map_sql_err()?,
sort_order: row.try_get("sort_order").map_sql_err()?,
config_json: json_from_string(
row.try_get("config_json").map_sql_err()?,
"routing_groups.config_json",
@@ -79,4 +79,4 @@ BEGIN
END IF;
END $$;
CREATE INDEX IF NOT EXISTS routing_group_versions_group_id_idx
ON public.routing_group_versions USING btree (group_id);
ON public.routing_group_versions USING btree (group_id);
@@ -0,0 +1,5 @@
ALTER TABLE public.routing_groups
ADD COLUMN sort_order bigint NOT NULL DEFAULT 0;
CREATE INDEX IF NOT EXISTS routing_groups_enabled_sort_idx
ON public.routing_groups (enabled DESC, sort_order, name, id);
@@ -22,6 +22,7 @@ SELECT
description,
enabled,
is_system_default,
sort_order,
config_json,
version,
created_at,
@@ -68,7 +69,9 @@ impl PostgresRoutingGroupRepository {
#[async_trait]
impl RoutingGroupReadRepository for PostgresRoutingGroupRepository {
async fn list_routing_groups(&self) -> Result<Vec<StoredRoutingGroup>, DataLayerError> {
let sql = format!("{ROUTING_GROUP_SELECT} ORDER BY name ASC, id ASC");
let sql = format!(
"{ROUTING_GROUP_SELECT} ORDER BY enabled DESC, sort_order ASC, name ASC, id ASC"
);
let mut rows = sqlx::query(&sql).fetch(&self.pool);
let mut groups = Vec::new();
while let Some(row) = rows.try_next().await.map_postgres_err()? {
@@ -178,10 +181,10 @@ impl RoutingGroupWriteRepository for PostgresRoutingGroupRepository {
sqlx::query(
r#"
INSERT INTO routing_groups (
id, name, description, enabled, is_system_default, config_json,
id, name, description, enabled, is_system_default, sort_order, config_json,
version, created_at, updated_at, published_at
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
"#,
)
.bind(&group.id)
@@ -189,6 +192,7 @@ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
.bind(&group.description)
.bind(group.enabled)
.bind(group.is_system_default)
.bind(group.sort_order)
.bind(&group.config_json)
.bind(group.version)
.bind(group.created_at)
@@ -238,10 +242,11 @@ SET name = $2,
description = $3,
enabled = $4,
is_system_default = $5,
config_json = $6,
version = $7,
updated_at = $8,
published_at = $9
sort_order = $6,
config_json = $7,
version = $8,
updated_at = $9,
published_at = $10
WHERE id = $1
"#,
)
@@ -250,6 +255,7 @@ WHERE id = $1
.bind(&group.description)
.bind(group.enabled)
.bind(group.is_system_default)
.bind(group.sort_order)
.bind(&group.config_json)
.bind(group.version)
.bind(group.updated_at)
@@ -441,6 +447,7 @@ fn map_group_row(row: &PgRow) -> Result<StoredRoutingGroup, DataLayerError> {
description: row.try_get("description").map_postgres_err()?,
enabled: row.try_get("enabled").map_postgres_err()?,
is_system_default: row.try_get("is_system_default").map_postgres_err()?,
sort_order: row.try_get("sort_order").map_postgres_err()?,
config_json: row.try_get("config_json").map_postgres_err()?,
version: row.try_get("version").map_postgres_err()?,
created_at: row.try_get("created_at").map_postgres_err()?,
@@ -0,0 +1,4 @@
ALTER TABLE routing_groups ADD COLUMN sort_order INTEGER NOT NULL DEFAULT 0;
CREATE INDEX IF NOT EXISTS routing_groups_enabled_sort_idx
ON routing_groups (enabled, sort_order, name, id);
@@ -15,6 +15,7 @@ SELECT
description,
enabled,
is_system_default,
sort_order,
config_json,
version,
created_at,
@@ -61,10 +62,12 @@ impl SqliteRoutingGroupRepository {
#[async_trait]
impl RoutingGroupReadRepository for SqliteRoutingGroupRepository {
async fn list_routing_groups(&self) -> Result<Vec<StoredRoutingGroup>, DataLayerError> {
let rows = sqlx::query(&format!("{ROUTING_GROUP_SELECT} ORDER BY name ASC, id ASC"))
.fetch_all(&self.pool)
.await
.map_sql_err()?;
let rows = sqlx::query(&format!(
"{ROUTING_GROUP_SELECT} ORDER BY enabled DESC, sort_order ASC, name ASC, id ASC"
))
.fetch_all(&self.pool)
.await
.map_sql_err()?;
rows.iter().map(map_group_row).collect()
}
@@ -168,10 +171,10 @@ impl RoutingGroupWriteRepository for SqliteRoutingGroupRepository {
sqlx::query(
r#"
INSERT INTO routing_groups (
id, name, description, enabled, is_system_default, config_json,
id, name, description, enabled, is_system_default, sort_order, config_json,
version, created_at, updated_at, published_at
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
"#,
)
.bind(&group.id)
@@ -179,6 +182,7 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
.bind(&group.description)
.bind(group.enabled)
.bind(group.is_system_default)
.bind(group.sort_order)
.bind(json_to_string(
&group.config_json,
"routing_groups.config_json",
@@ -229,6 +233,7 @@ SET name = ?,
description = ?,
enabled = ?,
is_system_default = ?,
sort_order = ?,
config_json = ?,
version = ?,
updated_at = ?,
@@ -240,6 +245,7 @@ WHERE id = ?
.bind(&group.description)
.bind(group.enabled)
.bind(group.is_system_default)
.bind(group.sort_order)
.bind(json_to_string(
&group.config_json,
"routing_groups.config_json",
@@ -438,6 +444,7 @@ fn map_group_row(row: &SqliteRow) -> Result<StoredRoutingGroup, DataLayerError>
description: row.try_get("description").map_sql_err()?,
enabled: row.try_get("enabled").map_sql_err()?,
is_system_default: row.try_get("is_system_default").map_sql_err()?,
sort_order: row.try_get("sort_order").map_sql_err()?,
config_json: json_from_string(
row.try_get("config_json").map_sql_err()?,
"routing_groups.config_json",
@@ -514,6 +521,7 @@ mod tests {
description: Some("initial".to_string()),
enabled: true,
is_system_default: true,
sort_order: 0,
config_json: json!({"allowed_models": ["gpt-*"]}),
version: 1,
created_at: 10,
@@ -790,6 +798,7 @@ SET is_default = 1,
description: None,
enabled: true,
is_system_default,
sort_order: 0,
config_json: json!({}),
version: 1,
created_at: 1,
@@ -10,6 +10,9 @@ pub struct StoredRoutingGroup {
pub description: Option<String>,
pub enabled: bool,
pub is_system_default: bool,
/// Stable administrator-defined display order. This is intentionally not
/// consulted by request routing or candidate selection.
pub sort_order: i64,
pub config_json: Value,
pub version: i64,
pub created_at: i64,
@@ -28,6 +31,7 @@ impl StoredRoutingGroup {
description: record.description,
enabled: record.enabled,
is_system_default: record.is_system_default,
sort_order: record.sort_order.max(0),
config_json: record.config_json,
version: record.version.max(1),
created_at: record.created_at,
@@ -44,6 +48,7 @@ pub struct CreateRoutingGroupRecord {
pub description: Option<String>,
pub enabled: bool,
pub is_system_default: bool,
pub sort_order: i64,
pub config_json: Value,
pub version: i64,
pub created_at: i64,
@@ -57,6 +62,7 @@ pub struct UpdateRoutingGroupRecord {
pub description: Option<Option<String>>,
pub enabled: Option<bool>,
pub is_system_default: Option<bool>,
pub sort_order: Option<i64>,
pub config_json: Option<Value>,
pub version: Option<i64>,
pub updated_at: i64,
@@ -255,6 +261,9 @@ pub fn apply_group_patch(
if let Some(is_system_default) = patch.is_system_default {
group.is_system_default = is_system_default;
}
if let Some(sort_order) = patch.sort_order {
group.sort_order = sort_order.max(0);
}
if let Some(config_json) = patch.config_json {
if !config_json.is_object() {
return Err(crate::DataLayerError::InvalidInput(
@@ -4,6 +4,7 @@ CREATE TABLE IF NOT EXISTS public.routing_groups (
description text,
enabled boolean DEFAULT true NOT NULL,
is_system_default boolean DEFAULT false NOT NULL,
sort_order bigint DEFAULT 0 NOT NULL,
config_json jsonb NOT NULL,
version bigint DEFAULT 1 NOT NULL,
created_at bigint NOT NULL,
@@ -31,6 +32,8 @@ CREATE INDEX IF NOT EXISTS routing_groups_system_default_idx
CREATE UNIQUE INDEX IF NOT EXISTS routing_groups_one_system_default_key
ON public.routing_groups (is_system_default)
WHERE is_system_default = TRUE;
CREATE INDEX IF NOT EXISTS routing_groups_enabled_sort_idx
ON public.routing_groups (enabled DESC, sort_order, name, id);
CREATE TABLE IF NOT EXISTS public.routing_group_bindings (
id character varying(64) NOT NULL,
@@ -85,4 +88,4 @@ BEGIN
END IF;
END $$;
CREATE INDEX IF NOT EXISTS routing_group_versions_group_id_idx
ON public.routing_group_versions USING btree (group_id);
ON public.routing_group_versions USING btree (group_id);
@@ -391,6 +391,7 @@ CREATE TABLE IF NOT EXISTS routing_groups (
`description` LONGTEXT,
`enabled` TINYINT(1) NOT NULL DEFAULT 1,
`is_system_default` TINYINT(1) NOT NULL DEFAULT 0,
`sort_order` BIGINT NOT NULL DEFAULT 0,
`config_json` JSON NOT NULL,
`version` BIGINT NOT NULL DEFAULT 1,
`created_at` BIGINT NOT NULL,
@@ -398,7 +399,8 @@ CREATE TABLE IF NOT EXISTS routing_groups (
`published_at` BIGINT,
PRIMARY KEY (`id`),
UNIQUE KEY routing_groups_name_key (`name`),
KEY routing_groups_system_default_idx (`is_system_default`, `enabled`)
KEY routing_groups_system_default_idx (`is_system_default`, `enabled`),
KEY routing_groups_enabled_sort_idx (`enabled`, `sort_order`, `name`, `id`)
);
CREATE TABLE IF NOT EXISTS routing_group_bindings (
@@ -404,6 +404,7 @@ CREATE TABLE IF NOT EXISTS public.routing_groups (
description text,
enabled boolean DEFAULT true NOT NULL,
is_system_default boolean DEFAULT false NOT NULL,
sort_order bigint DEFAULT 0 NOT NULL,
config_json jsonb NOT NULL,
version bigint DEFAULT 1 NOT NULL,
created_at bigint NOT NULL,
@@ -414,6 +415,7 @@ CREATE TABLE IF NOT EXISTS public.routing_groups (
ALTER TABLE ONLY public.routing_groups ADD CONSTRAINT routing_groups_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.routing_groups ADD CONSTRAINT routing_groups_name_key UNIQUE (name);
CREATE INDEX IF NOT EXISTS routing_groups_system_default_idx ON public.routing_groups USING btree (is_system_default, enabled);
CREATE INDEX IF NOT EXISTS routing_groups_enabled_sort_idx ON public.routing_groups USING btree (enabled, sort_order, name, id);
CREATE TABLE IF NOT EXISTS public.routing_group_bindings (
id character varying(64) NOT NULL,
@@ -378,6 +378,7 @@ CREATE TABLE IF NOT EXISTS routing_groups (
description TEXT,
enabled INTEGER NOT NULL DEFAULT 1,
is_system_default INTEGER NOT NULL DEFAULT 0,
sort_order INTEGER NOT NULL DEFAULT 0,
config_json TEXT NOT NULL,
version INTEGER NOT NULL DEFAULT 1,
created_at INTEGER NOT NULL,
@@ -386,6 +387,7 @@ CREATE TABLE IF NOT EXISTS routing_groups (
UNIQUE (name)
);
CREATE INDEX IF NOT EXISTS routing_groups_system_default_idx ON routing_groups (is_system_default, enabled);
CREATE INDEX IF NOT EXISTS routing_groups_enabled_sort_idx ON routing_groups (enabled, sort_order, name, id);
CREATE TABLE IF NOT EXISTS routing_group_bindings (
id TEXT PRIMARY KEY NOT NULL,
@@ -1733,6 +1733,11 @@ name = "is_system_default"
type = "bool"
default = false
[[table.routing_groups.columns]]
name = "sort_order"
type = "int64"
default = 0
[[table.routing_groups.columns]]
name = "config_json"
type = "json"
@@ -1763,6 +1768,10 @@ columns = ["name"]
name = "routing_groups_system_default_idx"
columns = ["is_system_default", "enabled"]
[[table.routing_groups.indexes]]
name = "routing_groups_enabled_sort_idx"
columns = ["enabled", "sort_order", "name", "id"]
[table.routing_group_bindings]
domain = "provider_catalog"
order = 111
@@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet};
use sqlx::{
migrate::{Migrate, MigrateError, Migrator},
query, Connection, MySqlConnection, Row,
query, query_scalar, Connection, MySqlConnection, Row,
};
use tracing::{error, info, warn};
@@ -11,6 +11,7 @@ use crate::driver::mysql::MysqlPool;
static BACKFILL_MIGRATOR: Migrator = sqlx::migrate!("./backfills/mysql");
const SCHEMA_BACKFILLS_TABLE_EXISTS_SQL: &str = "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'schema_backfills'";
const ENSURE_SCHEMA_BACKFILLS_TABLE_SQL: &str = r#"
CREATE TABLE IF NOT EXISTS schema_backfills (
version BIGINT NOT NULL,
@@ -161,12 +162,21 @@ async fn run_backfills_locked(conn: &mut MySqlConnection) -> Result<(), MigrateE
async fn pending_backfills_locked(
conn: &mut MySqlConnection,
) -> Result<Vec<PendingBackfillInfo>, MigrateError> {
ensure_schema_backfills_table(conn).await?;
if !schema_backfills_table_exists(conn).await? {
return Ok(pending_backfills_from_applied(&[]));
}
let applied_backfills = list_applied_backfills(conn).await?;
validate_applied_backfills(&applied_backfills)?;
Ok(pending_backfills_from_applied(&applied_backfills))
}
async fn schema_backfills_table_exists(conn: &mut MySqlConnection) -> Result<bool, MigrateError> {
let total: i64 = query_scalar(SCHEMA_BACKFILLS_TABLE_EXISTS_SQL)
.fetch_one(&mut *conn)
.await?;
Ok(total > 0)
}
async fn ensure_schema_backfills_table(conn: &mut MySqlConnection) -> Result<(), MigrateError> {
query(ENSURE_SCHEMA_BACKFILLS_TABLE_SQL)
.execute(&mut *conn)
@@ -157,17 +157,23 @@ async fn run_backfills_locked(conn: &mut PgConnection) -> Result<(), MigrateErro
async fn pending_backfills_locked(
conn: &mut PgConnection,
) -> Result<Vec<PendingBackfillInfo>, MigrateError> {
ensure_schema_backfills_table(conn).await?;
if !schema_backfills_table_exists(conn).await? {
return Ok(pending_backfills_from_applied(&[]));
}
let applied_backfills = list_applied_backfills(conn).await?;
validate_applied_backfills(&applied_backfills)?;
Ok(pending_backfills_from_applied(&applied_backfills))
}
async fn ensure_schema_backfills_table(conn: &mut PgConnection) -> Result<(), MigrateError> {
let exists: bool = query_scalar(SCHEMA_BACKFILLS_TABLE_EXISTS_SQL)
async fn schema_backfills_table_exists(conn: &mut PgConnection) -> Result<bool, MigrateError> {
query_scalar(SCHEMA_BACKFILLS_TABLE_EXISTS_SQL)
.fetch_one(&mut *conn)
.await?;
if exists {
.await
.map_err(Into::into)
}
async fn ensure_schema_backfills_table(conn: &mut PgConnection) -> Result<(), MigrateError> {
if schema_backfills_table_exists(conn).await? {
return Ok(());
}
query(ENSURE_SCHEMA_BACKFILLS_TABLE_SQL)
@@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet};
use sqlx::{
migrate::{Migrate, MigrateError, Migrator},
query, Connection, Row, SqliteConnection,
query, query_scalar, Connection, Row, SqliteConnection,
};
use tracing::{error, info, warn};
@@ -11,6 +11,8 @@ use crate::driver::sqlite::SqlitePool;
static BACKFILL_MIGRATOR: Migrator = sqlx::migrate!("./backfills/sqlite");
const SCHEMA_BACKFILLS_TABLE_EXISTS_SQL: &str =
"SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name = 'schema_backfills'";
const ENSURE_SCHEMA_BACKFILLS_TABLE_SQL: &str = r#"
CREATE TABLE IF NOT EXISTS schema_backfills (
version INTEGER NOT NULL PRIMARY KEY,
@@ -162,12 +164,21 @@ async fn run_backfills_locked(conn: &mut SqliteConnection) -> Result<(), Migrate
async fn pending_backfills_locked(
conn: &mut SqliteConnection,
) -> Result<Vec<PendingBackfillInfo>, MigrateError> {
ensure_schema_backfills_table(conn).await?;
if !schema_backfills_table_exists(conn).await? {
return Ok(pending_backfills_from_applied(&[]));
}
let applied_backfills = list_applied_backfills(conn).await?;
validate_applied_backfills(&applied_backfills)?;
Ok(pending_backfills_from_applied(&applied_backfills))
}
async fn schema_backfills_table_exists(conn: &mut SqliteConnection) -> Result<bool, MigrateError> {
let total: i64 = query_scalar(SCHEMA_BACKFILLS_TABLE_EXISTS_SQL)
.fetch_one(&mut *conn)
.await?;
Ok(total > 0)
}
async fn ensure_schema_backfills_table(conn: &mut SqliteConnection) -> Result<(), MigrateError> {
query(ENSURE_SCHEMA_BACKFILLS_TABLE_SQL)
.execute(&mut *conn)
@@ -310,6 +310,31 @@ INSERT INTO usage_settlement_snapshots (
}
}
#[tokio::test]
async fn pending_sqlite_backfills_does_not_create_tracking_table() {
let pool = sqlx::sqlite::SqlitePoolOptions::new()
.max_connections(1)
.connect("sqlite::memory:")
.await
.expect("sqlite backfill status pool should connect");
run_sqlite_migrations(&pool)
.await
.expect("sqlite schema should migrate");
let pending = pending_sqlite_backfills(&pool)
.await
.expect("sqlite pending backfills should load");
assert!(!pending.is_empty());
let tracking_tables: i64 = query_scalar(
"SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name = 'schema_backfills'",
)
.fetch_one(&pool)
.await
.expect("sqlite tracking table state should load");
assert_eq!(tracking_tables, 0);
}
#[tokio::test]
async fn sqlite_backfills_apply_portable_repairs_and_record_versions() {
let pool = sqlx::sqlite::SqlitePoolOptions::new()
@@ -7,7 +7,7 @@ use tracing::info;
// Generated by build.rs from schema/bootstrap/postgres.
pub(crate) static EMPTY_DATABASE_SNAPSHOT_SQL: &str =
include_str!(concat!(env!("OUT_DIR"), "/empty_database_snapshot.sql"));
pub(crate) const EMPTY_DATABASE_SNAPSHOT_CUTOFF_VERSION: i64 = 20260821000000;
pub(crate) const EMPTY_DATABASE_SNAPSHOT_CUTOFF_VERSION: i64 = 20260903000000;
const PUBLIC_BASE_TABLE_COUNT_SQL: &str = r#"
SELECT COUNT(*)::BIGINT
@@ -412,6 +412,7 @@ fn empty_database_snapshot_covers_current_cutoff_versions() {
20260727000000,
20260731000000,
20260821000000,
20260903000000,
]
);
}
@@ -1066,6 +1067,7 @@ fn mysql_and_sqlite_migrations_include_enabled_incrementals() {
20260727000000,
20260731000000,
20260821000000,
20260903000000,
]
);
assert_eq!(
@@ -1101,6 +1103,7 @@ fn mysql_and_sqlite_migrations_include_enabled_incrementals() {
20260727000000,
20260731000000,
20260821000000,
20260903000000,
]
);
}
@@ -2208,6 +2211,7 @@ fn pending_migrations_from_applied_skips_versions_already_applied() {
20260727000000,
20260731000000,
20260821000000,
20260903000000,
]
);
}
@@ -59,7 +59,14 @@ impl RoutingGroupReadRepository for InMemoryRoutingGroupRepository {
.values()
.cloned()
.collect::<Vec<_>>();
groups.sort_by(|left, right| left.name.cmp(&right.name).then(left.id.cmp(&right.id)));
groups.sort_by(|left, right| {
right
.enabled
.cmp(&left.enabled)
.then(left.sort_order.cmp(&right.sort_order))
.then(left.name.cmp(&right.name))
.then(left.id.cmp(&right.id))
});
Ok(groups)
}
@@ -273,6 +280,7 @@ mod tests {
description: None,
enabled: true,
is_system_default: true,
sort_order: 0,
config_json: json!({}),
version: 1,
created_at: 1,
@@ -320,6 +328,49 @@ mod tests {
);
}
#[tokio::test]
async fn lists_enabled_groups_first_and_respects_sort_order() {
let repository = InMemoryRoutingGroupRepository::default();
for (id, enabled, sort_order) in [
("disabled-first", false, 0),
("enabled-second", true, 20),
("enabled-first", true, 10),
] {
repository
.create_routing_group(CreateRoutingGroupRecord {
id: id.to_string(),
name: id.to_string(),
description: None,
enabled,
is_system_default: false,
sort_order,
config_json: json!({}),
version: 1,
created_at: 1,
updated_at: 1,
published_at: None,
})
.await
.expect("group should store");
}
let ids = repository
.list_routing_groups()
.await
.expect("groups should list")
.into_iter()
.map(|group| group.id)
.collect::<Vec<_>>();
assert_eq!(
ids,
vec![
"enabled-first".to_string(),
"enabled-second".to_string(),
"disabled-first".to_string(),
]
);
}
#[tokio::test]
async fn keeps_system_and_subject_defaults_unique() {
let repository = InMemoryRoutingGroupRepository::default();
@@ -414,6 +465,7 @@ mod tests {
description: None,
enabled: true,
is_system_default,
sort_order: 0,
config_json: json!({}),
version: 1,
created_at: 1,