From 7a635fb20c48815ccf4db5b5139130048cabe06b Mon Sep 17 00:00:00 2001 From: MasterPtato Date: Fri, 15 Mar 2024 22:09:50 +0000 Subject: [PATCH] fix: get all api tests passing or disabled --- svc/api/auth/tests/basic.rs | 614 +++++----- svc/api/cf-verification/tests/basic.rs | 210 ++-- svc/api/identity/tests/basic.rs | 1470 ++++++++++++------------ svc/api/job/tests/basic.rs | 372 +++--- svc/api/kv/tests/basic.rs | 1162 ++++++++++--------- svc/api/matchmaker/tests/common.rs | 16 + svc/api/module/tests/basic.rs | 690 +++++------ svc/api/route/tests/basic.rs | 2 +- svc/api/status/tests/basic.rs | 140 +-- 9 files changed, 2363 insertions(+), 2313 deletions(-) diff --git a/svc/api/auth/tests/basic.rs b/svc/api/auth/tests/basic.rs index 248c701fe4..2955dfc67e 100644 --- a/svc/api/auth/tests/basic.rs +++ b/svc/api/auth/tests/basic.rs @@ -1,306 +1,308 @@ -use std::{net::SocketAddr, str::FromStr, sync::Once}; - -use proto::backend; -use rivet_auth::model; -use rivet_claims::ClaimsDecode; -use rivet_operation::prelude::*; - -use ::api_auth::route; - -static GLOBAL_INIT: Once = Once::new(); - -struct Ctx { - op_ctx: OperationContext<()>, - http_client: rivet_auth::ClientWrapper, - user_id: Uuid, -} - -impl Ctx { - async fn init() -> Ctx { - GLOBAL_INIT.call_once(|| { - tracing_subscriber::fmt() - .pretty() - .with_max_level(tracing::Level::INFO) - .with_target(false) - .init(); - }); - - let pools = rivet_pools::from_env("api-auth-test").await.unwrap(); - let cache = rivet_cache::CacheInner::new( - "api-auth-test".to_string(), - std::env::var("RIVET_SOURCE_HASH").unwrap(), - pools.redis_cache().unwrap(), - ); - let client = chirp_client::SharedClient::from_env(pools.clone()) - .expect("create client") - .wrap_new("api-auth-test"); - let conn = rivet_connection::Connection::new(client, pools, cache); - let op_ctx = OperationContext::new( - "api-auth-test".to_string(), - std::time::Duration::from_secs(60), - conn, - Uuid::new_v4(), - Uuid::new_v4(), - util::timestamp::now(), - util::timestamp::now(), - (), - Vec::new(), - ); - - let (user_id, user_token) = Self::issue_user_token(&op_ctx).await; - - let http_client = rivet_auth::Config::builder() - .set_uri("http://traefik.traefik.svc.cluster.local:80/auth") - .set_bearer_token(user_token) - .build_client(); - - Ctx { - op_ctx, - http_client, - user_id, - } - } - - async fn issue_user_token(ctx: &OperationContext<()>) -> (Uuid, String) { - let user_res = op!([ctx] faker_user {}).await.unwrap(); - let user_id = user_res.user_id.unwrap().as_uuid(); - - let token_res = op!([ctx] user_token_create { - user_id: user_res.user_id, - client: Some(backend::net::ClientInfo { - user_agent: Some(USER_AGENT.into()), - remote_address: Some(socket_addr().to_string()), - }) - }) - .await - .unwrap(); - - (user_id, token_res.token) - } - - fn chirp(&self) -> &chirp_client::Client { - self.op_ctx.chirp() - } - - fn op_ctx(&self) -> &OperationContext<()> { - &self.op_ctx - } -} - -const USER_AGENT: &str = "test"; - -fn socket_addr() -> SocketAddr { - "1.2.3.4:5678".parse().unwrap() -} - -#[tokio::test(flavor = "multi_thread")] -async fn register_then_refresh() { - let ctx = Ctx::init().await; - - // MARK: POST /tokens/identity (create new token) - let (identity_id, refresh_cookie) = { - tracing::info!("register auth"); - - let res = ctx - .http_client - .refresh_identity_token() - .logout(false) - .send() - .await - .unwrap(); - - let refresh_cookie = res - .set_cookie() - .unwrap() - .iter() - .find_map(|cookie| { - let cookie_auth = cookie.split(';').next().unwrap(); - cookie_auth.strip_prefix(&format!("{}=", route::tokens::USER_REFRESH_TOKEN_COOKIE)) - }) - .expect("no matching refresh token cookie") - .to_owned(); - let refresh_claims = rivet_claims::decode(&refresh_cookie).unwrap().unwrap(); - assert_eq!( - refresh_claims.iat + route::tokens::REFRESH_TOKEN_TTL, - refresh_claims.exp.unwrap_or_default(), - "bad expiration" - ); - - let claims = rivet_claims::decode(res.token().unwrap()).unwrap().unwrap(); - assert_eq!( - claims.iat + route::tokens::TOKEN_TTL, - claims.exp.unwrap_or_default(), - "bad expiration" - ); - let user = claims.as_user().unwrap(); - assert_eq!( - res.identity_id().unwrap(), - user.user_id.to_string().as_str(), - "claims does not match returned user id" - ); - - (user.user_id, refresh_cookie) - }; - - // MARK: POST /tokens/identity (with refresh) - { - tracing::info!("refresh auth"); - - let res = ctx - .http_client - .refresh_identity_token() - .cookie(&format!( - "{}={}", - route::tokens::USER_REFRESH_TOKEN_COOKIE, - refresh_cookie - )) - .logout(false) - .send() - .await - .unwrap(); - - let claims = rivet_claims::decode(res.token().unwrap()).unwrap().unwrap(); - let user = claims.as_user().unwrap(); - assert_eq!( - identity_id, user.user_id, - "did not refresh original user id" - ); - } -} - -#[tokio::test(flavor = "multi_thread")] -async fn register_then_logout() { - let ctx = Ctx::init().await; - - // MARK: POST /tokens/identity (create new token) - let (identity_id, refresh_cookie) = { - tracing::info!("register auth"); - - let res = ctx - .http_client - .refresh_identity_token() - .logout(false) - .send() - .await - .unwrap(); - - let refresh_cookie = res - .set_cookie() - .unwrap() - .iter() - .find_map(|cookie| { - let cookie_auth = cookie.split(';').next().unwrap(); - cookie_auth.strip_prefix(&format!("{}=", route::tokens::USER_REFRESH_TOKEN_COOKIE)) - }) - .expect("no matching refresh token cookie") - .to_owned(); - let refresh_claims = rivet_claims::decode(&refresh_cookie).unwrap().unwrap(); - assert_eq!( - refresh_claims.iat + route::tokens::REFRESH_TOKEN_TTL, - refresh_claims.exp.unwrap_or_default(), - "bad expiration" - ); - - let claims = rivet_claims::decode(res.token().unwrap()).unwrap().unwrap(); - assert_eq!( - claims.iat + route::tokens::TOKEN_TTL, - claims.exp.unwrap_or_default(), - "bad expiration" - ); - let user = claims.as_user().unwrap(); - assert_eq!( - res.identity_id().unwrap(), - user.user_id.to_string().as_str(), - "claims does not match returned user id" - ); - - (user.user_id, refresh_cookie) - }; - - // MARK: POST /tokens/identity (with refresh and logout) - { - tracing::info!("logout auth"); - - let res = ctx - .http_client - .refresh_identity_token() - .cookie(&format!( - "{}={}", - route::tokens::USER_REFRESH_TOKEN_COOKIE, - refresh_cookie - )) - .logout(true) - .send() - .await - .unwrap(); - - let claims = rivet_claims::decode(res.token().unwrap()).unwrap().unwrap(); - let user = claims.as_user().unwrap(); - - assert_ne!( - identity_id, user.user_id, - "logout did not return a new guest user token" - ); - } -} - -#[tokio::test(flavor = "multi_thread")] -async fn register() { - let ctx = Ctx::init().await; - let email = util::faker::email(); - - // MARK: /identity/email/start-verification - let verification_id = { - tracing::info!("start email identity verification"); - - let res = ctx - .http_client - .start_email_verification() - .email(email) - .send() - .await - .unwrap(); - - res.verification_id().unwrap().to_string() - }; - - let res = op!([ctx] debug_email_res { - verification_id: Some(Uuid::from_str(verification_id.as_str()).unwrap().into()) - }) - .await - .unwrap(); - - // MARK: /identity/email/complete-verification - { - let complete_res = ctx - .http_client - .complete_email_verification() - .verification_id(verification_id) - .code(&res.code) - .send() - .await - .unwrap(); - - // Verify that identity has been created - match complete_res.status().unwrap() { - model::CompleteStatus::LinkedAccountAdded => { - let identity_res = op!([ctx] user_identity_get { - user_ids: vec![ctx.user_id.into()] - }) - .await - .unwrap(); - - assert_eq!( - 1, - identity_res.users[0].identities.len(), - "email identity not found" - ); - } - // User email already registered - model::CompleteStatus::SwitchIdentity => { - panic!("user should not be switching"); - } - _ => (), - } - } -} +// TODO: Rewrite with new api clients + +// use std::{net::SocketAddr, str::FromStr, sync::Once}; + +// use proto::backend; +// use rivet_auth::model; +// use rivet_claims::ClaimsDecode; +// use rivet_operation::prelude::*; + +// use ::api_auth::route; + +// static GLOBAL_INIT: Once = Once::new(); + +// struct Ctx { +// op_ctx: OperationContext<()>, +// http_client: rivet_auth::ClientWrapper, +// user_id: Uuid, +// } + +// impl Ctx { +// async fn init() -> Ctx { +// GLOBAL_INIT.call_once(|| { +// tracing_subscriber::fmt() +// .pretty() +// .with_max_level(tracing::Level::INFO) +// .with_target(false) +// .init(); +// }); + +// let pools = rivet_pools::from_env("api-auth-test").await.unwrap(); +// let cache = rivet_cache::CacheInner::new( +// "api-auth-test".to_string(), +// std::env::var("RIVET_SOURCE_HASH").unwrap(), +// pools.redis_cache().unwrap(), +// ); +// let client = chirp_client::SharedClient::from_env(pools.clone()) +// .expect("create client") +// .wrap_new("api-auth-test"); +// let conn = rivet_connection::Connection::new(client, pools, cache); +// let op_ctx = OperationContext::new( +// "api-auth-test".to_string(), +// std::time::Duration::from_secs(60), +// conn, +// Uuid::new_v4(), +// Uuid::new_v4(), +// util::timestamp::now(), +// util::timestamp::now(), +// (), +// Vec::new(), +// ); + +// let (user_id, user_token) = Self::issue_user_token(&op_ctx).await; + +// let http_client = rivet_auth::Config::builder() +// .set_uri("http://traefik.traefik.svc.cluster.local:80/auth") +// .set_bearer_token(user_token) +// .build_client(); + +// Ctx { +// op_ctx, +// http_client, +// user_id, +// } +// } + +// async fn issue_user_token(ctx: &OperationContext<()>) -> (Uuid, String) { +// let user_res = op!([ctx] faker_user {}).await.unwrap(); +// let user_id = user_res.user_id.unwrap().as_uuid(); + +// let token_res = op!([ctx] user_token_create { +// user_id: user_res.user_id, +// client: Some(backend::net::ClientInfo { +// user_agent: Some(USER_AGENT.into()), +// remote_address: Some(socket_addr().to_string()), +// }) +// }) +// .await +// .unwrap(); + +// (user_id, token_res.token) +// } + +// fn chirp(&self) -> &chirp_client::Client { +// self.op_ctx.chirp() +// } + +// fn op_ctx(&self) -> &OperationContext<()> { +// &self.op_ctx +// } +// } + +// const USER_AGENT: &str = "test"; + +// fn socket_addr() -> SocketAddr { +// "1.2.3.4:5678".parse().unwrap() +// } + +// #[tokio::test(flavor = "multi_thread")] +// async fn register_then_refresh() { +// let ctx = Ctx::init().await; + +// // MARK: POST /tokens/identity (create new token) +// let (identity_id, refresh_cookie) = { +// tracing::info!("register auth"); + +// let res = ctx +// .http_client +// .refresh_identity_token() +// .logout(false) +// .send() +// .await +// .unwrap(); + +// let refresh_cookie = res +// .set_cookie() +// .unwrap() +// .iter() +// .find_map(|cookie| { +// let cookie_auth = cookie.split(';').next().unwrap(); +// cookie_auth.strip_prefix(&format!("{}=", route::tokens::USER_REFRESH_TOKEN_COOKIE)) +// }) +// .expect("no matching refresh token cookie") +// .to_owned(); +// let refresh_claims = rivet_claims::decode(&refresh_cookie).unwrap().unwrap(); +// assert_eq!( +// refresh_claims.iat + route::tokens::REFRESH_TOKEN_TTL, +// refresh_claims.exp.unwrap_or_default(), +// "bad expiration" +// ); + +// let claims = rivet_claims::decode(res.token().unwrap()).unwrap().unwrap(); +// assert_eq!( +// claims.iat + route::tokens::TOKEN_TTL, +// claims.exp.unwrap_or_default(), +// "bad expiration" +// ); +// let user = claims.as_user().unwrap(); +// assert_eq!( +// res.identity_id().unwrap(), +// user.user_id.to_string().as_str(), +// "claims does not match returned user id" +// ); + +// (user.user_id, refresh_cookie) +// }; + +// // MARK: POST /tokens/identity (with refresh) +// { +// tracing::info!("refresh auth"); + +// let res = ctx +// .http_client +// .refresh_identity_token() +// .cookie(&format!( +// "{}={}", +// route::tokens::USER_REFRESH_TOKEN_COOKIE, +// refresh_cookie +// )) +// .logout(false) +// .send() +// .await +// .unwrap(); + +// let claims = rivet_claims::decode(res.token().unwrap()).unwrap().unwrap(); +// let user = claims.as_user().unwrap(); +// assert_eq!( +// identity_id, user.user_id, +// "did not refresh original user id" +// ); +// } +// } + +// #[tokio::test(flavor = "multi_thread")] +// async fn register_then_logout() { +// let ctx = Ctx::init().await; + +// // MARK: POST /tokens/identity (create new token) +// let (identity_id, refresh_cookie) = { +// tracing::info!("register auth"); + +// let res = ctx +// .http_client +// .refresh_identity_token() +// .logout(false) +// .send() +// .await +// .unwrap(); + +// let refresh_cookie = res +// .set_cookie() +// .unwrap() +// .iter() +// .find_map(|cookie| { +// let cookie_auth = cookie.split(';').next().unwrap(); +// cookie_auth.strip_prefix(&format!("{}=", route::tokens::USER_REFRESH_TOKEN_COOKIE)) +// }) +// .expect("no matching refresh token cookie") +// .to_owned(); +// let refresh_claims = rivet_claims::decode(&refresh_cookie).unwrap().unwrap(); +// assert_eq!( +// refresh_claims.iat + route::tokens::REFRESH_TOKEN_TTL, +// refresh_claims.exp.unwrap_or_default(), +// "bad expiration" +// ); + +// let claims = rivet_claims::decode(res.token().unwrap()).unwrap().unwrap(); +// assert_eq!( +// claims.iat + route::tokens::TOKEN_TTL, +// claims.exp.unwrap_or_default(), +// "bad expiration" +// ); +// let user = claims.as_user().unwrap(); +// assert_eq!( +// res.identity_id().unwrap(), +// user.user_id.to_string().as_str(), +// "claims does not match returned user id" +// ); + +// (user.user_id, refresh_cookie) +// }; + +// // MARK: POST /tokens/identity (with refresh and logout) +// { +// tracing::info!("logout auth"); + +// let res = ctx +// .http_client +// .refresh_identity_token() +// .cookie(&format!( +// "{}={}", +// route::tokens::USER_REFRESH_TOKEN_COOKIE, +// refresh_cookie +// )) +// .logout(true) +// .send() +// .await +// .unwrap(); + +// let claims = rivet_claims::decode(res.token().unwrap()).unwrap().unwrap(); +// let user = claims.as_user().unwrap(); + +// assert_ne!( +// identity_id, user.user_id, +// "logout did not return a new guest user token" +// ); +// } +// } + +// #[tokio::test(flavor = "multi_thread")] +// async fn register() { +// let ctx = Ctx::init().await; +// let email = util::faker::email(); + +// // MARK: /identity/email/start-verification +// let verification_id = { +// tracing::info!("start email identity verification"); + +// let res = ctx +// .http_client +// .start_email_verification() +// .email(email) +// .send() +// .await +// .unwrap(); + +// res.verification_id().unwrap().to_string() +// }; + +// let res = op!([ctx] debug_email_res { +// verification_id: Some(Uuid::from_str(verification_id.as_str()).unwrap().into()) +// }) +// .await +// .unwrap(); + +// // MARK: /identity/email/complete-verification +// { +// let complete_res = ctx +// .http_client +// .complete_email_verification() +// .verification_id(verification_id) +// .code(&res.code) +// .send() +// .await +// .unwrap(); + +// // Verify that identity has been created +// match complete_res.status().unwrap() { +// model::CompleteStatus::LinkedAccountAdded => { +// let identity_res = op!([ctx] user_identity_get { +// user_ids: vec![ctx.user_id.into()] +// }) +// .await +// .unwrap(); + +// assert_eq!( +// 1, +// identity_res.users[0].identities.len(), +// "email identity not found" +// ); +// } +// // User email already registered +// model::CompleteStatus::SwitchIdentity => { +// panic!("user should not be switching"); +// } +// _ => (), +// } +// } +// } diff --git a/svc/api/cf-verification/tests/basic.rs b/svc/api/cf-verification/tests/basic.rs index fe2b1b5560..12bf6704ba 100644 --- a/svc/api/cf-verification/tests/basic.rs +++ b/svc/api/cf-verification/tests/basic.rs @@ -1,104 +1,106 @@ -use proto::backend::pkg::*; -use rivet_operation::prelude::*; - -struct Ctx { - op_ctx: OperationContext<()>, - http_client: rivet_cf_verification::ClientWrapper, -} - -impl Ctx { - async fn init() -> Ctx { - let _ = tracing_subscriber::fmt() - .pretty() - .with_max_level(tracing::Level::INFO) - .with_target(false) - .try_init(); - - let pools = rivet_pools::from_env("api-cf-verification-test") - .await - .unwrap(); - let cache = rivet_cache::CacheInner::new( - "api-cf-verification-test".to_string(), - std::env::var("RIVET_SOURCE_HASH").unwrap(), - pools.redis_cache().unwrap(), - ); - let client = chirp_client::SharedClient::from_env(pools.clone()) - .expect("create client") - .wrap_new("api-cf-verification-test"); - let conn = rivet_connection::Connection::new(client, pools, cache); - let op_ctx = OperationContext::new( - "api-cf-verification-test".to_string(), - std::time::Duration::from_secs(60), - conn, - Uuid::new_v4(), - Uuid::new_v4(), - util::timestamp::now(), - util::timestamp::now(), - (), - Vec::new(), - ); - - let http_client = rivet_cf_verification::Config::builder() - .set_uri("http://traefik.traefik.svc.cluster.local:80/cf-verification") - .build_client(); - - Ctx { - op_ctx, - http_client, - } - } - - fn chirp(&self) -> &chirp_client::Client { - self.op_ctx.chirp() - } - - fn op_ctx(&self) -> &OperationContext<()> { - &self.op_ctx - } -} - -#[tokio::test(flavor = "multi_thread")] -async fn custom_hostname_verification() { - if !util::feature::cf_custom_hostname() { - return; - }; - - let ctx = Ctx::init().await; - - // MARK: GET /.well-known/cf-custom-hostname-challenge/{} - { - tracing::info!("testing custom hostname verification"); - - let game_res = op!([ctx] faker_game { }).await.unwrap(); - let namespace_id = game_res.namespace_ids.first().unwrap().as_uuid(); - - let hostname = format!("{}.com", util::faker::ident()); - - let res = msg!([ctx] cf_custom_hostname::msg::create(namespace_id, &hostname) -> Result { - namespace_id: Some(namespace_id.into()), - hostname: hostname.clone(), - bypass_pending_cap: false, - }).await.unwrap().unwrap(); - let identifier = res.identifier.unwrap(); - - let res = op!([ctx] cf_custom_hostname_get { - identifiers: vec![identifier], - }) - .await - .unwrap(); - assert_eq!(1, res.custom_hostnames.len()); - - let custom_hostname = res.custom_hostnames.first().unwrap(); - let challenge = custom_hostname.challenge.unwrap().as_uuid(); - - let res = ctx - .http_client - .verify_custom_hostname() - .identifier(identifier.as_uuid().to_string()) - .send() - .await - .unwrap(); - - assert_eq!(format!("{challenge}\n"), res.body().unwrap()); - } -} +// TODO: Rewrite with new api clients + +// use proto::backend::pkg::*; +// use rivet_operation::prelude::*; + +// struct Ctx { +// op_ctx: OperationContext<()>, +// http_client: rivet_cf_verification::ClientWrapper, +// } + +// impl Ctx { +// async fn init() -> Ctx { +// let _ = tracing_subscriber::fmt() +// .pretty() +// .with_max_level(tracing::Level::INFO) +// .with_target(false) +// .try_init(); + +// let pools = rivet_pools::from_env("api-cf-verification-test") +// .await +// .unwrap(); +// let cache = rivet_cache::CacheInner::new( +// "api-cf-verification-test".to_string(), +// std::env::var("RIVET_SOURCE_HASH").unwrap(), +// pools.redis_cache().unwrap(), +// ); +// let client = chirp_client::SharedClient::from_env(pools.clone()) +// .expect("create client") +// .wrap_new("api-cf-verification-test"); +// let conn = rivet_connection::Connection::new(client, pools, cache); +// let op_ctx = OperationContext::new( +// "api-cf-verification-test".to_string(), +// std::time::Duration::from_secs(60), +// conn, +// Uuid::new_v4(), +// Uuid::new_v4(), +// util::timestamp::now(), +// util::timestamp::now(), +// (), +// Vec::new(), +// ); + +// let http_client = rivet_cf_verification::Config::builder() +// .set_uri("http://traefik.traefik.svc.cluster.local:80/cf-verification") +// .build_client(); + +// Ctx { +// op_ctx, +// http_client, +// } +// } + +// fn chirp(&self) -> &chirp_client::Client { +// self.op_ctx.chirp() +// } + +// fn op_ctx(&self) -> &OperationContext<()> { +// &self.op_ctx +// } +// } + +// #[tokio::test(flavor = "multi_thread")] +// async fn custom_hostname_verification() { +// if !util::feature::cf_custom_hostname() { +// return; +// }; + +// let ctx = Ctx::init().await; + +// // MARK: GET /.well-known/cf-custom-hostname-challenge/{} +// { +// tracing::info!("testing custom hostname verification"); + +// let game_res = op!([ctx] faker_game { }).await.unwrap(); +// let namespace_id = game_res.namespace_ids.first().unwrap().as_uuid(); + +// let hostname = format!("{}.com", util::faker::ident()); + +// let res = msg!([ctx] cf_custom_hostname::msg::create(namespace_id, &hostname) -> Result { +// namespace_id: Some(namespace_id.into()), +// hostname: hostname.clone(), +// bypass_pending_cap: false, +// }).await.unwrap().unwrap(); +// let identifier = res.identifier.unwrap(); + +// let res = op!([ctx] cf_custom_hostname_get { +// identifiers: vec![identifier], +// }) +// .await +// .unwrap(); +// assert_eq!(1, res.custom_hostnames.len()); + +// let custom_hostname = res.custom_hostnames.first().unwrap(); +// let challenge = custom_hostname.challenge.unwrap().as_uuid(); + +// let res = ctx +// .http_client +// .verify_custom_hostname() +// .identifier(identifier.as_uuid().to_string()) +// .send() +// .await +// .unwrap(); + +// assert_eq!(format!("{challenge}\n"), res.body().unwrap()); +// } +// } diff --git a/svc/api/identity/tests/basic.rs b/svc/api/identity/tests/basic.rs index 26f0a74680..7df9cabe0a 100644 --- a/svc/api/identity/tests/basic.rs +++ b/svc/api/identity/tests/basic.rs @@ -1,734 +1,736 @@ -use std::{str::FromStr, sync::Once}; - -use proto::backend::{self, pkg::*}; -use regex::Regex; - -use rivet_claims::ClaimsDecode; -use rivet_identity::{model, output}; -use rivet_operation::prelude::*; - -const LOBBY_GROUP_NAME_ID: &str = "test"; - -static GLOBAL_INIT: Once = Once::new(); - -struct Ctx { - op_ctx: OperationContext<()>, - ns_dev_auth_token: String, -} - -impl Ctx { - async fn init() -> Ctx { - GLOBAL_INIT.call_once(|| { - tracing_subscriber::fmt() - .pretty() - .with_max_level(tracing::Level::INFO) - .with_target(false) - .init(); - }); - - let pools = rivet_pools::from_env("api-identity-test").await.unwrap(); - let cache = rivet_cache::CacheInner::new( - "api-identity-test".to_string(), - std::env::var("RIVET_SOURCE_HASH").unwrap(), - pools.redis_cache().unwrap(), - ); - let client = chirp_client::SharedClient::from_env(pools.clone()) - .expect("create client") - .wrap_new("api-identity-test"); - let conn = rivet_connection::Connection::new(client, pools, cache); - let op_ctx = OperationContext::new( - "api-identity-test".to_string(), - std::time::Duration::from_secs(60), - conn, - Uuid::new_v4(), - Uuid::new_v4(), - util::timestamp::now(), - util::timestamp::now(), - (), - Vec::new(), - ); - - let (primary_region_id, _) = Self::setup_region(&op_ctx).await; - let (_, _, namespace_id, _, _) = Self::setup_game(&op_ctx, primary_region_id).await; - let ns_dev_auth_token = - Self::setup_dev_token(&op_ctx, namespace_id, "127.0.0.1".to_owned(), Vec::new()).await; - - Ctx { - op_ctx, - ns_dev_auth_token, - } - } - - fn http_client(&self, bearer_token: String) -> rivet_identity::ClientWrapper { - rivet_identity::Config::builder() - .set_uri("http://traefik.traefik.svc.cluster.local:80/identity") - .set_bearer_token(bearer_token) - .build_client() - } - - async fn setup_region(ctx: &OperationContext<()>) -> (Uuid, String) { - tracing::info!("setup region"); - - let region_res = op!([ctx] faker_region {}).await.unwrap(); - let region_id = region_res.region_id.unwrap().as_uuid(); - - let get_res = op!([ctx] region_get { - region_ids: vec![region_id.into()], - }) - .await - .unwrap(); - let region_data = get_res.regions.first().unwrap(); - - (region_id, region_data.name_id.clone()) - } - - async fn setup_game( - ctx: &OperationContext<()>, - region_id: Uuid, - ) -> ( - Uuid, - Uuid, - Uuid, - backend::matchmaker::VersionConfig, - backend::matchmaker::VersionConfigMeta, - ) { - let game_res = op!([ctx] faker_game { - ..Default::default() - }) - .await - .unwrap(); - - let build_res = op!([ctx] faker_build { - game_id: game_res.game_id, - image: backend::faker::Image::MmLobbyAutoReady as i32, - }) - .await - .unwrap(); - - let game_version_res = op!([ctx] faker_game_version { - game_id: game_res.game_id, - override_lobby_groups: Some(faker::game_version::request::OverrideLobbyGroups { - lobby_groups: vec![backend::matchmaker::LobbyGroup { - name_id: LOBBY_GROUP_NAME_ID.into(), - - regions: vec![backend::matchmaker::lobby_group::Region { - region_id: Some(region_id.into()), - tier_name_id: util_mm::test::TIER_NAME_ID.to_owned(), - idle_lobbies: None, - }], - max_players_normal: 8, - max_players_direct: 10, - max_players_party: 12, - listable: true, - taggable: false, - allow_dynamic_max_players: false, - - runtime: Some(backend::matchmaker::lobby_runtime::Docker { - build_id: build_res.build_id, - args: Vec::new(), - env_vars: Vec::new(), - network_mode: backend::matchmaker::lobby_runtime::NetworkMode::Bridge as i32, - ports: vec![ - backend::matchmaker::lobby_runtime::Port { - label: "test-80-http".into(), - target_port: Some(80), - port_range: None, - proxy_protocol: backend::matchmaker::lobby_runtime::ProxyProtocol::Http as i32, - proxy_kind: backend::matchmaker::lobby_runtime::ProxyKind::GameGuard as i32, - }, - backend::matchmaker::lobby_runtime::Port { - label: "test-80-https".into(), - target_port: Some(80), - port_range: None, - proxy_protocol: backend::matchmaker::lobby_runtime::ProxyProtocol::Https as i32, - proxy_kind: backend::matchmaker::lobby_runtime::ProxyKind::GameGuard as i32, - }, - backend::matchmaker::lobby_runtime::Port { - label: "test-5050-https".into(), - target_port: Some(5050), - port_range: None, - proxy_protocol: backend::matchmaker::lobby_runtime::ProxyProtocol::Https as i32, - proxy_kind: backend::matchmaker::lobby_runtime::ProxyKind::GameGuard as i32, - }, - ], - }.into()), - - actions: None, - }], - }), - ..Default::default() - }) - .await - .unwrap(); - - let namespace_res = op!([ctx] faker_game_namespace { - game_id: game_res.game_id, - version_id: game_version_res.version_id, - ..Default::default() - }) - .await - .unwrap(); - - ( - game_res.game_id.unwrap().as_uuid(), - game_version_res.version_id.unwrap().as_uuid(), - namespace_res.namespace_id.unwrap().as_uuid(), - game_version_res.mm_config.clone().unwrap(), - game_version_res.mm_config_meta.clone().unwrap(), - ) - } - - async fn setup_dev_token( - ctx: &OperationContext<()>, - namespace_id: Uuid, - hostname: String, - lobby_ports: Vec, - ) -> String { - let token_res = op!([ctx] cloud_namespace_token_development_create { - hostname: hostname.to_owned(), - namespace_id: Some(namespace_id.into()), - lobby_ports: lobby_ports, - }) - .await - .unwrap(); - - token_res.token - } - - fn chirp(&self) -> &chirp_client::Client { - self.op_ctx.chirp() - } - - fn op_ctx(&self) -> &OperationContext<()> { - &self.op_ctx - } -} - -#[tokio::test(flavor = "multi_thread")] -async fn game_identities() { - let ctx = Ctx::init().await; - - // MARK: POST /identities - let (_identity_id, game_identity_token) = { - tracing::info!("creating game identity"); - - let http_client = ctx.http_client(ctx.ns_dev_auth_token.clone()); - - let res = http_client.setup_identity().send().await.unwrap(); - - ( - res.identity().unwrap().identity_id().unwrap().to_string(), - res.identity_token().unwrap().to_string(), - ) - }; - - let http_client = ctx.http_client(game_identity_token); - - // MARK: GET /identities - { - tracing::info!("getting game identity"); - - let _res = http_client - .get_identity_self_profile() - .send() - .await - .unwrap(); - } - - // Create fake new user - let faker_user_res = op!([ctx] faker_user {}).await.unwrap(); - let user_id_to_link_to = faker_user_res.user_id.unwrap().as_uuid(); - - // MARK: POST /identities/links - let (identity_link_token, identity_link_url) = { - tracing::info!("getting identity link"); - - let res = http_client.prepare_game_link().send().await.unwrap(); - - ( - res.identity_link_token().unwrap().to_string(), - res.identity_link_url().unwrap().to_string(), - ) - }; - - // MARK: GET /identities/links/{} - { - tracing::info!("getting identity link status"); - - let res = http_client - .get_game_link() - .identity_link_token(&identity_link_token) - .send() - .await - .unwrap(); - - assert_eq!( - res.status().unwrap(), - &model::GameLinkStatus::Incomplete, - "invalid status" - ); - } - - // Completing game link - { - let re = Regex::new(r"/link/(.*)$").unwrap(); - let re_identity_link_token = re.captures(&identity_link_url).unwrap()[1].to_owned(); - assert_eq!(identity_link_token, re_identity_link_token); - - tracing::info!(identity_link_token = ?identity_link_token, "completing game identity link"); - let token_claims = rivet_claims::decode(&identity_link_token).unwrap().unwrap(); - let game_identity_ent = token_claims.as_game_user_link().unwrap(); - let token_jti = token_claims.jti.unwrap(); - - msg!([ctx] game_user::msg::link_complete(game_identity_ent.link_id) -> game_user::msg::link_complete_complete { - user_id: Some(user_id_to_link_to.into()), - link_id: Some(game_identity_ent.link_id.into()), - user_link_jti: Some(token_jti), - resolution: game_user::msg::link_complete::GameUserLinkCompleteResolution::Complete as i32, - }) - .await - .unwrap(); - - let res = http_client - .get_game_link() - .identity_link_token(&identity_link_token) - .send() - .await - .unwrap(); - - assert_eq!( - res.status().unwrap(), - &model::GameLinkStatus::Complete, - "linking did not complete" - ); - - let new_identity = res.new_identity().expect("missing new identity"); - assert_eq!( - user_id_to_link_to.to_string(), - new_identity.identity().unwrap().identity_id().unwrap(), - "new identity does not match" - ); - - // Check the provided game user token is valid - let new_identity_http_client = - ctx.http_client(new_identity.identity_token().unwrap().to_string()); - let new_profile_self = new_identity_http_client - .get_identity_self_profile() - .send() - .await - .unwrap(); - assert_eq!( - user_id_to_link_to.to_string(), - new_profile_self.identity().unwrap().identity_id().unwrap(), - "new fetched identity does not match" - ); - - // Get the user - let res = new_identity_http_client - .get_identity_profile() - .identity_id(user_id_to_link_to.to_string()) - .send() - .await - .unwrap(); - assert!( - res.identity().unwrap().is_game_linked().unwrap(), - "linking did not update identity" - ); - } - - // MARK: GET /events - { - tracing::info!("getting events"); - - // TODO: Trigger a fake event so this resolves quickly - - let events_res_1 = http_client.watch_events().send().await.unwrap(); - let _events_res_2 = http_client - .watch_events() - .watch_index(events_res_1.watch().unwrap().index().unwrap()) - .send() - .await - .unwrap(); - } -} - -// TODO: Test TOKEN_REVOKED error for token refresh will issue a fresh token -// safely - -#[tokio::test(flavor = "multi_thread")] -async fn identities() { - let ctx = Ctx::init().await; - - let user_res = op!([ctx] faker_user { }).await.unwrap(); - let other_user_id = user_res.user_id.unwrap(); - - // MARK: POST /identities - let (identity_id, game_identity_token) = { - let http_client = ctx.http_client(ctx.ns_dev_auth_token.clone()); - - // Hit identities endpoint multiple times to check refresh token - let mut last_res = Option::::None; - let mut identity_token = None; - - // TODO: Should this be 1? - for i in 0..1 { - tracing::info!(i, "creating game identity"); - - let res = http_client - .setup_identity() - .set_existing_identity_token(identity_token) - .send() - .await - .unwrap(); - - // Check the response state - if i != 0 { - let last_res = last_res.as_ref().unwrap(); - assert_eq!( - res.identity_token(), - last_res.identity_token(), - "unnecessary refreshed identity token" - ); - assert_eq!( - last_res - .identity() - .unwrap() - .identity_id() - .unwrap() - .to_string(), - res.identity().unwrap().identity_id().unwrap().to_string(), - "identity id changed" - ); - } - - // Check that the token is valid - { - tracing::info!("checking identity token is valid"); - - let get_self_res = ctx - .http_client(res.identity_token().unwrap().to_string()) - .get_identity_self_profile() - .send() - .await - .unwrap(); - - assert_eq!( - res.identity().unwrap().identity_id().unwrap(), - get_self_res.identity().unwrap().identity_id().unwrap(), - "token represents wrong identity" - ); - } - - // Save state for next round - identity_token = Some(res.identity_token().unwrap().to_string()); - last_res = Some(res); - } - - let res = last_res.unwrap(); - ( - res.identity().unwrap().identity_id().unwrap().to_string(), - res.identity_token().unwrap().to_string(), - ) - }; - - let http_client = ctx.http_client(game_identity_token); - - // MARK: GET /identities/{} - { - tracing::info!("getting identity"); - - let _res = http_client - .get_identity_profile() - .identity_id(&identity_id) - .send() - .await - .unwrap(); - } - - // MARK: POST /identities/self/activity - { - tracing::info!("setting identity game activity"); - - let _res = http_client - .set_identity_game_activity() - .game_activity( - model::update_identity_game_activity::Builder::default() - .message("test message") - .build(), - ) - .send() - .await - .unwrap(); - } - - // MARK: DELETE /identities/self/activity - { - tracing::info!("removing identity game activity"); - - let _res = http_client - .remove_identity_game_activity() - .send() - .await - .unwrap(); - } - - // MARK: POST /identities/self/status - { - tracing::info!("setting identity status"); - - let _res = http_client - .update_identity_status() - .status(model::IdentityStatus::Away) - .send() - .await - .unwrap(); - } - - // MARK: POST /identities/{}/follow - { - tracing::info!("friending identity"); - - let _res = http_client - .follow_identity() - .identity_id(other_user_id.to_string()) - .send() - .await - .unwrap(); - - let res = http_client - .get_identity_profile() - .identity_id(other_user_id.to_string()) - .send() - .await - .unwrap(); - - tracing::info!(?other_user_id); - - assert!( - res.identity().unwrap().following().unwrap(), - "friending failed" - ); - } - - // MARK: DELETE /identities/{}/follow - { - tracing::info!("unfriending identity"); - - let _res = http_client - .unfollow_identity() - .identity_id(other_user_id.to_string()) - .send() - .await - .unwrap(); - - let res = http_client - .get_identity_profile() - .identity_id(other_user_id.to_string()) - .send() - .await - .unwrap(); - - assert!( - !res.identity().unwrap().following().unwrap(), - "unfriending failed" - ); - } - - // MARK: GET /identities/search - { - tracing::info!("searching identities"); - - let _res = http_client - .search_identities() - .query(util::faker::ident()) - .limit(10) - .send() - .await - .unwrap(); - } -} -#[tokio::test(flavor = "multi_thread")] -async fn activities() { - let ctx = Ctx::init().await; - - // MARK: POST /identities - let (identity_id, game_identity_token) = { - tracing::info!("creating game identity"); - - let http_client = ctx.http_client(ctx.ns_dev_auth_token.clone()); - - let res = http_client.setup_identity().send().await.unwrap(); - - ( - res.identity().unwrap().identity_id().unwrap().to_string(), - res.identity_token().unwrap().to_string(), - ) - }; - - let http_client = ctx.http_client(game_identity_token); - let user_res = op!([ctx] faker_user { }).await.unwrap(); - let other_user_id = user_res.user_id.unwrap(); - - op!([ctx] user_presence_touch { - user_id: user_res.user_id, - }) - .await - .unwrap(); - - op!([ctx] user_follow_toggle { - follower_user_id: Some(other_user_id), - following_user_id: Some(Uuid::from_str(&identity_id).unwrap().into()), - active: true, - }) - .await - .unwrap(); - - // MARK: POST /identities/{}/follow - { - tracing::info!("tailing activities and friending identity"); - - let (activities_res, _) = tokio::join!( - async { - let activities_req = http_client - .list_activities() - .watch_index(util::timestamp::now().to_string()) - .send(); - - let activities_res = util::macros::select_with_timeout!([3 SEC] { - activities_res = activities_req => { - Some(activities_res.unwrap()) - } - }); - - activities_res.expect("no message from activities endpoint") - }, - async { - // Wait before putting - tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; - - http_client - .follow_identity() - .identity_id(other_user_id.to_string()) - .send() - .await - .unwrap() - } - ); - - let identities = activities_res.identities().unwrap(); - tracing::info!(?identities); - assert!( - !identities.is_empty(), - "followed identity not present in activities" - ); - } - - // MARK: GET /activities - { - tracing::info!("tailing activities and unfriending identity"); - - let (activities_res, _) = tokio::join!( - async { - let activities_req = http_client - .list_activities() - .watch_index(util::timestamp::now().to_string()) - .send(); - - let activities_res = util::macros::select_with_timeout!([3 SEC] { - activities_res = activities_req => { - Some(activities_res.unwrap()) - } - }); - - activities_res.expect("no message from activities endpoint") - }, - async { - // Wait before putting - tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; - - http_client - .unfollow_identity() - .identity_id(other_user_id.to_string()) - .send() - .await - .unwrap() - } - ); - - let identities = activities_res.identities().unwrap(); - assert!( - identities.is_empty(), - "unfollowed identity not removed from activities" - ); - } -} - -#[tokio::test(flavor = "multi_thread")] -async fn invalid_identity_refresh() { - let ctx = Ctx::init().await; - - // MARK: POST /identities - { - tracing::info!("creating game identity"); - - let http_client = ctx.http_client(ctx.ns_dev_auth_token.clone()); - - let _res = http_client - .setup_identity() - .existing_identity_token("~~invalid token~~") - .send() - .await - .unwrap(); - } -} - -#[tokio::test(flavor = "multi_thread")] -async fn revoked_token_issues_new_token() { - let ctx = Ctx::init().await; - - let http_client = ctx.http_client(ctx.ns_dev_auth_token.clone()); - - // MARK: POST /identities - let (original_identity_id, token) = { - tracing::info!("creating game identity"); - - let res = http_client.setup_identity().send().await.unwrap(); - - ( - res.identity().unwrap().identity_id().unwrap().to_string(), - res.identity_token().unwrap().to_string(), - ) - }; - - // Revoke the identity - { - let claims = rivet_claims::decode(&token).unwrap().unwrap(); - - let jti = claims.jti.unwrap(); - op!([ctx] token_revoke { - jtis: vec![jti], - }) - .await - .unwrap(); - } - - // MARK: POST /identities - { - tracing::info!("creating another game identity"); - - let res = http_client - .setup_identity() - .existing_identity_token(token) - .send() - .await - .unwrap(); - let new_identity_id = res.identity().unwrap().identity_id().unwrap(); - - assert_ne!( - original_identity_id, new_identity_id, - "new token should have been issued from revoked token" - ); - } -} - -// TODO: Add remaining identity endpoints +// TODO: Rewrite with new api clients + +// use std::{str::FromStr, sync::Once}; + +// use proto::backend::{self, pkg::*}; +// use regex::Regex; + +// use rivet_claims::ClaimsDecode; +// use rivet_identity::{model, output}; +// use rivet_operation::prelude::*; + +// const LOBBY_GROUP_NAME_ID: &str = "test"; + +// static GLOBAL_INIT: Once = Once::new(); + +// struct Ctx { +// op_ctx: OperationContext<()>, +// ns_dev_auth_token: String, +// } + +// impl Ctx { +// async fn init() -> Ctx { +// GLOBAL_INIT.call_once(|| { +// tracing_subscriber::fmt() +// .pretty() +// .with_max_level(tracing::Level::INFO) +// .with_target(false) +// .init(); +// }); + +// let pools = rivet_pools::from_env("api-identity-test").await.unwrap(); +// let cache = rivet_cache::CacheInner::new( +// "api-identity-test".to_string(), +// std::env::var("RIVET_SOURCE_HASH").unwrap(), +// pools.redis_cache().unwrap(), +// ); +// let client = chirp_client::SharedClient::from_env(pools.clone()) +// .expect("create client") +// .wrap_new("api-identity-test"); +// let conn = rivet_connection::Connection::new(client, pools, cache); +// let op_ctx = OperationContext::new( +// "api-identity-test".to_string(), +// std::time::Duration::from_secs(60), +// conn, +// Uuid::new_v4(), +// Uuid::new_v4(), +// util::timestamp::now(), +// util::timestamp::now(), +// (), +// Vec::new(), +// ); + +// let (primary_region_id, _) = Self::setup_region(&op_ctx).await; +// let (_, _, namespace_id, _, _) = Self::setup_game(&op_ctx, primary_region_id).await; +// let ns_dev_auth_token = +// Self::setup_dev_token(&op_ctx, namespace_id, "127.0.0.1".to_owned(), Vec::new()).await; + +// Ctx { +// op_ctx, +// ns_dev_auth_token, +// } +// } + +// fn http_client(&self, bearer_token: String) -> rivet_identity::ClientWrapper { +// rivet_identity::Config::builder() +// .set_uri("http://traefik.traefik.svc.cluster.local:80/identity") +// .set_bearer_token(bearer_token) +// .build_client() +// } + +// async fn setup_region(ctx: &OperationContext<()>) -> (Uuid, String) { +// tracing::info!("setup region"); + +// let region_res = op!([ctx] faker_region {}).await.unwrap(); +// let region_id = region_res.region_id.unwrap().as_uuid(); + +// let get_res = op!([ctx] region_get { +// region_ids: vec![region_id.into()], +// }) +// .await +// .unwrap(); +// let region_data = get_res.regions.first().unwrap(); + +// (region_id, region_data.name_id.clone()) +// } + +// async fn setup_game( +// ctx: &OperationContext<()>, +// region_id: Uuid, +// ) -> ( +// Uuid, +// Uuid, +// Uuid, +// backend::matchmaker::VersionConfig, +// backend::matchmaker::VersionConfigMeta, +// ) { +// let game_res = op!([ctx] faker_game { +// ..Default::default() +// }) +// .await +// .unwrap(); + +// let build_res = op!([ctx] faker_build { +// game_id: game_res.game_id, +// image: backend::faker::Image::MmLobbyAutoReady as i32, +// }) +// .await +// .unwrap(); + +// let game_version_res = op!([ctx] faker_game_version { +// game_id: game_res.game_id, +// override_lobby_groups: Some(faker::game_version::request::OverrideLobbyGroups { +// lobby_groups: vec![backend::matchmaker::LobbyGroup { +// name_id: LOBBY_GROUP_NAME_ID.into(), + +// regions: vec![backend::matchmaker::lobby_group::Region { +// region_id: Some(region_id.into()), +// tier_name_id: util_mm::test::TIER_NAME_ID.to_owned(), +// idle_lobbies: None, +// }], +// max_players_normal: 8, +// max_players_direct: 10, +// max_players_party: 12, +// listable: true, +// taggable: false, +// allow_dynamic_max_players: false, + +// runtime: Some(backend::matchmaker::lobby_runtime::Docker { +// build_id: build_res.build_id, +// args: Vec::new(), +// env_vars: Vec::new(), +// network_mode: backend::matchmaker::lobby_runtime::NetworkMode::Bridge as i32, +// ports: vec![ +// backend::matchmaker::lobby_runtime::Port { +// label: "test-80-http".into(), +// target_port: Some(80), +// port_range: None, +// proxy_protocol: backend::matchmaker::lobby_runtime::ProxyProtocol::Http as i32, +// proxy_kind: backend::matchmaker::lobby_runtime::ProxyKind::GameGuard as i32, +// }, +// backend::matchmaker::lobby_runtime::Port { +// label: "test-80-https".into(), +// target_port: Some(80), +// port_range: None, +// proxy_protocol: backend::matchmaker::lobby_runtime::ProxyProtocol::Https as i32, +// proxy_kind: backend::matchmaker::lobby_runtime::ProxyKind::GameGuard as i32, +// }, +// backend::matchmaker::lobby_runtime::Port { +// label: "test-5050-https".into(), +// target_port: Some(5050), +// port_range: None, +// proxy_protocol: backend::matchmaker::lobby_runtime::ProxyProtocol::Https as i32, +// proxy_kind: backend::matchmaker::lobby_runtime::ProxyKind::GameGuard as i32, +// }, +// ], +// }.into()), + +// actions: None, +// }], +// }), +// ..Default::default() +// }) +// .await +// .unwrap(); + +// let namespace_res = op!([ctx] faker_game_namespace { +// game_id: game_res.game_id, +// version_id: game_version_res.version_id, +// ..Default::default() +// }) +// .await +// .unwrap(); + +// ( +// game_res.game_id.unwrap().as_uuid(), +// game_version_res.version_id.unwrap().as_uuid(), +// namespace_res.namespace_id.unwrap().as_uuid(), +// game_version_res.mm_config.clone().unwrap(), +// game_version_res.mm_config_meta.clone().unwrap(), +// ) +// } + +// async fn setup_dev_token( +// ctx: &OperationContext<()>, +// namespace_id: Uuid, +// hostname: String, +// lobby_ports: Vec, +// ) -> String { +// let token_res = op!([ctx] cloud_namespace_token_development_create { +// hostname: hostname.to_owned(), +// namespace_id: Some(namespace_id.into()), +// lobby_ports: lobby_ports, +// }) +// .await +// .unwrap(); + +// token_res.token +// } + +// fn chirp(&self) -> &chirp_client::Client { +// self.op_ctx.chirp() +// } + +// fn op_ctx(&self) -> &OperationContext<()> { +// &self.op_ctx +// } +// } + +// #[tokio::test(flavor = "multi_thread")] +// async fn game_identities() { +// let ctx = Ctx::init().await; + +// // MARK: POST /identities +// let (_identity_id, game_identity_token) = { +// tracing::info!("creating game identity"); + +// let http_client = ctx.http_client(ctx.ns_dev_auth_token.clone()); + +// let res = http_client.setup_identity().send().await.unwrap(); + +// ( +// res.identity().unwrap().identity_id().unwrap().to_string(), +// res.identity_token().unwrap().to_string(), +// ) +// }; + +// let http_client = ctx.http_client(game_identity_token); + +// // MARK: GET /identities +// { +// tracing::info!("getting game identity"); + +// let _res = http_client +// .get_identity_self_profile() +// .send() +// .await +// .unwrap(); +// } + +// // Create fake new user +// let faker_user_res = op!([ctx] faker_user {}).await.unwrap(); +// let user_id_to_link_to = faker_user_res.user_id.unwrap().as_uuid(); + +// // MARK: POST /identities/links +// let (identity_link_token, identity_link_url) = { +// tracing::info!("getting identity link"); + +// let res = http_client.prepare_game_link().send().await.unwrap(); + +// ( +// res.identity_link_token().unwrap().to_string(), +// res.identity_link_url().unwrap().to_string(), +// ) +// }; + +// // MARK: GET /identities/links/{} +// { +// tracing::info!("getting identity link status"); + +// let res = http_client +// .get_game_link() +// .identity_link_token(&identity_link_token) +// .send() +// .await +// .unwrap(); + +// assert_eq!( +// res.status().unwrap(), +// &model::GameLinkStatus::Incomplete, +// "invalid status" +// ); +// } + +// // Completing game link +// { +// let re = Regex::new(r"/link/(.*)$").unwrap(); +// let re_identity_link_token = re.captures(&identity_link_url).unwrap()[1].to_owned(); +// assert_eq!(identity_link_token, re_identity_link_token); + +// tracing::info!(identity_link_token = ?identity_link_token, "completing game identity link"); +// let token_claims = rivet_claims::decode(&identity_link_token).unwrap().unwrap(); +// let game_identity_ent = token_claims.as_game_user_link().unwrap(); +// let token_jti = token_claims.jti.unwrap(); + +// msg!([ctx] game_user::msg::link_complete(game_identity_ent.link_id) -> game_user::msg::link_complete_complete { +// user_id: Some(user_id_to_link_to.into()), +// link_id: Some(game_identity_ent.link_id.into()), +// user_link_jti: Some(token_jti), +// resolution: game_user::msg::link_complete::GameUserLinkCompleteResolution::Complete as i32, +// }) +// .await +// .unwrap(); + +// let res = http_client +// .get_game_link() +// .identity_link_token(&identity_link_token) +// .send() +// .await +// .unwrap(); + +// assert_eq!( +// res.status().unwrap(), +// &model::GameLinkStatus::Complete, +// "linking did not complete" +// ); + +// let new_identity = res.new_identity().expect("missing new identity"); +// assert_eq!( +// user_id_to_link_to.to_string(), +// new_identity.identity().unwrap().identity_id().unwrap(), +// "new identity does not match" +// ); + +// // Check the provided game user token is valid +// let new_identity_http_client = +// ctx.http_client(new_identity.identity_token().unwrap().to_string()); +// let new_profile_self = new_identity_http_client +// .get_identity_self_profile() +// .send() +// .await +// .unwrap(); +// assert_eq!( +// user_id_to_link_to.to_string(), +// new_profile_self.identity().unwrap().identity_id().unwrap(), +// "new fetched identity does not match" +// ); + +// // Get the user +// let res = new_identity_http_client +// .get_identity_profile() +// .identity_id(user_id_to_link_to.to_string()) +// .send() +// .await +// .unwrap(); +// assert!( +// res.identity().unwrap().is_game_linked().unwrap(), +// "linking did not update identity" +// ); +// } + +// // MARK: GET /events +// { +// tracing::info!("getting events"); + +// // TODO: Trigger a fake event so this resolves quickly + +// let events_res_1 = http_client.watch_events().send().await.unwrap(); +// let _events_res_2 = http_client +// .watch_events() +// .watch_index(events_res_1.watch().unwrap().index().unwrap()) +// .send() +// .await +// .unwrap(); +// } +// } + +// // TODO: Test TOKEN_REVOKED error for token refresh will issue a fresh token +// // safely + +// #[tokio::test(flavor = "multi_thread")] +// async fn identities() { +// let ctx = Ctx::init().await; + +// let user_res = op!([ctx] faker_user { }).await.unwrap(); +// let other_user_id = user_res.user_id.unwrap(); + +// // MARK: POST /identities +// let (identity_id, game_identity_token) = { +// let http_client = ctx.http_client(ctx.ns_dev_auth_token.clone()); + +// // Hit identities endpoint multiple times to check refresh token +// let mut last_res = Option::::None; +// let mut identity_token = None; + +// // TODO: Should this be 1? +// for i in 0..1 { +// tracing::info!(i, "creating game identity"); + +// let res = http_client +// .setup_identity() +// .set_existing_identity_token(identity_token) +// .send() +// .await +// .unwrap(); + +// // Check the response state +// if i != 0 { +// let last_res = last_res.as_ref().unwrap(); +// assert_eq!( +// res.identity_token(), +// last_res.identity_token(), +// "unnecessary refreshed identity token" +// ); +// assert_eq!( +// last_res +// .identity() +// .unwrap() +// .identity_id() +// .unwrap() +// .to_string(), +// res.identity().unwrap().identity_id().unwrap().to_string(), +// "identity id changed" +// ); +// } + +// // Check that the token is valid +// { +// tracing::info!("checking identity token is valid"); + +// let get_self_res = ctx +// .http_client(res.identity_token().unwrap().to_string()) +// .get_identity_self_profile() +// .send() +// .await +// .unwrap(); + +// assert_eq!( +// res.identity().unwrap().identity_id().unwrap(), +// get_self_res.identity().unwrap().identity_id().unwrap(), +// "token represents wrong identity" +// ); +// } + +// // Save state for next round +// identity_token = Some(res.identity_token().unwrap().to_string()); +// last_res = Some(res); +// } + +// let res = last_res.unwrap(); +// ( +// res.identity().unwrap().identity_id().unwrap().to_string(), +// res.identity_token().unwrap().to_string(), +// ) +// }; + +// let http_client = ctx.http_client(game_identity_token); + +// // MARK: GET /identities/{} +// { +// tracing::info!("getting identity"); + +// let _res = http_client +// .get_identity_profile() +// .identity_id(&identity_id) +// .send() +// .await +// .unwrap(); +// } + +// // MARK: POST /identities/self/activity +// { +// tracing::info!("setting identity game activity"); + +// let _res = http_client +// .set_identity_game_activity() +// .game_activity( +// model::update_identity_game_activity::Builder::default() +// .message("test message") +// .build(), +// ) +// .send() +// .await +// .unwrap(); +// } + +// // MARK: DELETE /identities/self/activity +// { +// tracing::info!("removing identity game activity"); + +// let _res = http_client +// .remove_identity_game_activity() +// .send() +// .await +// .unwrap(); +// } + +// // MARK: POST /identities/self/status +// { +// tracing::info!("setting identity status"); + +// let _res = http_client +// .update_identity_status() +// .status(model::IdentityStatus::Away) +// .send() +// .await +// .unwrap(); +// } + +// // MARK: POST /identities/{}/follow +// { +// tracing::info!("friending identity"); + +// let _res = http_client +// .follow_identity() +// .identity_id(other_user_id.to_string()) +// .send() +// .await +// .unwrap(); + +// let res = http_client +// .get_identity_profile() +// .identity_id(other_user_id.to_string()) +// .send() +// .await +// .unwrap(); + +// tracing::info!(?other_user_id); + +// assert!( +// res.identity().unwrap().following().unwrap(), +// "friending failed" +// ); +// } + +// // MARK: DELETE /identities/{}/follow +// { +// tracing::info!("unfriending identity"); + +// let _res = http_client +// .unfollow_identity() +// .identity_id(other_user_id.to_string()) +// .send() +// .await +// .unwrap(); + +// let res = http_client +// .get_identity_profile() +// .identity_id(other_user_id.to_string()) +// .send() +// .await +// .unwrap(); + +// assert!( +// !res.identity().unwrap().following().unwrap(), +// "unfriending failed" +// ); +// } + +// // MARK: GET /identities/search +// { +// tracing::info!("searching identities"); + +// let _res = http_client +// .search_identities() +// .query(util::faker::ident()) +// .limit(10) +// .send() +// .await +// .unwrap(); +// } +// } +// #[tokio::test(flavor = "multi_thread")] +// async fn activities() { +// let ctx = Ctx::init().await; + +// // MARK: POST /identities +// let (identity_id, game_identity_token) = { +// tracing::info!("creating game identity"); + +// let http_client = ctx.http_client(ctx.ns_dev_auth_token.clone()); + +// let res = http_client.setup_identity().send().await.unwrap(); + +// ( +// res.identity().unwrap().identity_id().unwrap().to_string(), +// res.identity_token().unwrap().to_string(), +// ) +// }; + +// let http_client = ctx.http_client(game_identity_token); +// let user_res = op!([ctx] faker_user { }).await.unwrap(); +// let other_user_id = user_res.user_id.unwrap(); + +// op!([ctx] user_presence_touch { +// user_id: user_res.user_id, +// }) +// .await +// .unwrap(); + +// op!([ctx] user_follow_toggle { +// follower_user_id: Some(other_user_id), +// following_user_id: Some(Uuid::from_str(&identity_id).unwrap().into()), +// active: true, +// }) +// .await +// .unwrap(); + +// // MARK: POST /identities/{}/follow +// { +// tracing::info!("tailing activities and friending identity"); + +// let (activities_res, _) = tokio::join!( +// async { +// let activities_req = http_client +// .list_activities() +// .watch_index(util::timestamp::now().to_string()) +// .send(); + +// let activities_res = util::macros::select_with_timeout!([3 SEC] { +// activities_res = activities_req => { +// Some(activities_res.unwrap()) +// } +// }); + +// activities_res.expect("no message from activities endpoint") +// }, +// async { +// // Wait before putting +// tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; + +// http_client +// .follow_identity() +// .identity_id(other_user_id.to_string()) +// .send() +// .await +// .unwrap() +// } +// ); + +// let identities = activities_res.identities().unwrap(); +// tracing::info!(?identities); +// assert!( +// !identities.is_empty(), +// "followed identity not present in activities" +// ); +// } + +// // MARK: GET /activities +// { +// tracing::info!("tailing activities and unfriending identity"); + +// let (activities_res, _) = tokio::join!( +// async { +// let activities_req = http_client +// .list_activities() +// .watch_index(util::timestamp::now().to_string()) +// .send(); + +// let activities_res = util::macros::select_with_timeout!([3 SEC] { +// activities_res = activities_req => { +// Some(activities_res.unwrap()) +// } +// }); + +// activities_res.expect("no message from activities endpoint") +// }, +// async { +// // Wait before putting +// tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; + +// http_client +// .unfollow_identity() +// .identity_id(other_user_id.to_string()) +// .send() +// .await +// .unwrap() +// } +// ); + +// let identities = activities_res.identities().unwrap(); +// assert!( +// identities.is_empty(), +// "unfollowed identity not removed from activities" +// ); +// } +// } + +// #[tokio::test(flavor = "multi_thread")] +// async fn invalid_identity_refresh() { +// let ctx = Ctx::init().await; + +// // MARK: POST /identities +// { +// tracing::info!("creating game identity"); + +// let http_client = ctx.http_client(ctx.ns_dev_auth_token.clone()); + +// let _res = http_client +// .setup_identity() +// .existing_identity_token("~~invalid token~~") +// .send() +// .await +// .unwrap(); +// } +// } + +// #[tokio::test(flavor = "multi_thread")] +// async fn revoked_token_issues_new_token() { +// let ctx = Ctx::init().await; + +// let http_client = ctx.http_client(ctx.ns_dev_auth_token.clone()); + +// // MARK: POST /identities +// let (original_identity_id, token) = { +// tracing::info!("creating game identity"); + +// let res = http_client.setup_identity().send().await.unwrap(); + +// ( +// res.identity().unwrap().identity_id().unwrap().to_string(), +// res.identity_token().unwrap().to_string(), +// ) +// }; + +// // Revoke the identity +// { +// let claims = rivet_claims::decode(&token).unwrap().unwrap(); + +// let jti = claims.jti.unwrap(); +// op!([ctx] token_revoke { +// jtis: vec![jti], +// }) +// .await +// .unwrap(); +// } + +// // MARK: POST /identities +// { +// tracing::info!("creating another game identity"); + +// let res = http_client +// .setup_identity() +// .existing_identity_token(token) +// .send() +// .await +// .unwrap(); +// let new_identity_id = res.identity().unwrap().identity_id().unwrap(); + +// assert_ne!( +// original_identity_id, new_identity_id, +// "new token should have been issued from revoked token" +// ); +// } +// } + +// // TODO: Add remaining identity endpoints diff --git a/svc/api/job/tests/basic.rs b/svc/api/job/tests/basic.rs index 05eeb51570..6caa1f7a05 100644 --- a/svc/api/job/tests/basic.rs +++ b/svc/api/job/tests/basic.rs @@ -1,185 +1,187 @@ -use std::{sync::Once, time::Duration}; - -use proto::backend::{self, pkg::*}; -use rivet_operation::prelude::*; - -static GLOBAL_INIT: Once = Once::new(); - -struct Ctx { - op_ctx: OperationContext<()>, - nomad_config: nomad_client::apis::configuration::Configuration, -} - -impl Ctx { - async fn init() -> Ctx { - GLOBAL_INIT.call_once(|| { - tracing_subscriber::fmt() - .pretty() - .with_max_level(tracing::Level::INFO) - .with_target(false) - .init(); - }); - - let pools = rivet_pools::from_env("api-job-test").await.unwrap(); - let cache = rivet_cache::CacheInner::new( - "api-job-test".to_string(), - std::env::var("RIVET_SOURCE_HASH").unwrap(), - pools.redis_cache().unwrap(), - ); - let client = chirp_client::SharedClient::from_env(pools.clone()) - .expect("create client") - .wrap_new("api-job-test"); - let conn = rivet_connection::Connection::new(client, pools, cache); - let op_ctx = OperationContext::new( - "api-job-test".to_string(), - std::time::Duration::from_secs(60), - conn, - Uuid::new_v4(), - Uuid::new_v4(), - util::timestamp::now(), - util::timestamp::now(), - (), - Vec::new(), - ); - - let nomad_config = nomad_util::config_from_env().unwrap(); - - Ctx { - op_ctx, - nomad_config, - } - } - - fn http_client(&self, bearer_token: String) -> rivet_job::ClientWrapper { - rivet_job::Config::builder() - .set_uri("http://traefik.traefik.svc.cluster.local:80/job") - .set_bearer_token(bearer_token) - .build_client() - } - - /// Issues a testing job run token. We use this since we can't access the job run token issued - /// when the job is ran. - async fn job_run_token(&self, run_id: Uuid) -> String { - let token_res = op!([self] token_create { - issuer: "test".into(), - token_config: Some(token::create::request::TokenConfig { - ttl: util::duration::days(365), - }), - refresh_token_config: None, - client: None, - kind: Some(token::create::request::Kind::New(token::create::request::KindNew { - entitlements: vec![ - proto::claims::Entitlement { - kind: Some( - proto::claims::entitlement::Kind::JobRun(proto::claims::entitlement::JobRun { - run_id: Some(run_id.into()), - }) - ) - } - ], - })), - label: Some("jr".into()), - ..Default::default() - }) - .await - .unwrap(); - - token_res.token.as_ref().unwrap().token.clone() - } - - fn chirp(&self) -> &chirp_client::Client { - self.op_ctx.chirp() - } - - fn op_ctx(&self) -> &OperationContext<()> { - &self.op_ctx - } -} - -async fn run_job(ctx: &Ctx) -> (Uuid, backend::job::Run, backend::job::run_meta::Nomad) { - let res = op!([ctx] faker_job_run { - ..Default::default() - }) - .await - .unwrap(); - let run_id = res.run_id.unwrap().as_uuid(); - - // Check the run exists and that `job_run` is not broken - let runs_res = op!([ctx] job_run_get { - run_ids: vec![run_id.into()], - }) - .await - .unwrap(); - assert!(!runs_res.runs.is_empty(), "job was not created"); - let run = runs_res.runs.first().unwrap().clone(); - - let run_meta = match run.run_meta.as_ref().unwrap().kind.as_ref().unwrap() { - backend::job::run_meta::Kind::Nomad(x) => x.clone(), - }; - - (run_id, run, run_meta) -} - -#[tokio::test(flavor = "multi_thread")] -async fn run_cleanup() { - let ctx = Ctx::init().await; - - // MARK: POST /runs/cleanup - { - tracing::info!("run cleanup"); - - // Create test job - let (run_id, _, _run_meta) = run_job(&ctx).await; - let run_token = ctx.job_run_token(run_id).await; - let http_client = ctx.http_client(run_token); - - http_client.cleanup().send().await.unwrap(); - - tokio::time::sleep(Duration::from_secs(2)).await; - - let run_res = op!([ctx] job_run_get { - run_ids: vec![run_id.into()], - }) - .await - .unwrap(); - assert!( - run_res.runs.first().unwrap().stop_ts.is_some(), - "run was not cleaned up" - ); - } -} - -#[tokio::test(flavor = "multi_thread")] -async fn run_cleanup_from_poststop() { - let ctx = Ctx::init().await; - - // MARK: POST /runs/cleanup - { - tracing::info!("run cleanup"); - - // Create test job - let (run_id, _, _run_meta) = run_job(&ctx).await; - let run_token = ctx.job_run_token(run_id).await; - let http_client = ctx.http_client(run_token); - - let mut cleanup_sub = subscribe!([ctx] job_run::msg::cleanup_complete(run_id)) - .await - .unwrap(); - - http_client.cleanup().send().await.unwrap(); - - cleanup_sub.next().await.unwrap(); - - let run_res = op!([ctx] job_run_get { - run_ids: vec![run_id.into()], - }) - .await - .unwrap(); - assert!( - run_res.runs.first().unwrap().stop_ts.is_some(), - "run was not cleaned up" - ); - } - - // TODO: Test the logs -} +// TODO: Rewrite with new api clients + +// use std::{sync::Once, time::Duration}; + +// use proto::backend::{self, pkg::*}; +// use rivet_operation::prelude::*; + +// static GLOBAL_INIT: Once = Once::new(); + +// struct Ctx { +// op_ctx: OperationContext<()>, +// nomad_config: nomad_client::apis::configuration::Configuration, +// } + +// impl Ctx { +// async fn init() -> Ctx { +// GLOBAL_INIT.call_once(|| { +// tracing_subscriber::fmt() +// .pretty() +// .with_max_level(tracing::Level::INFO) +// .with_target(false) +// .init(); +// }); + +// let pools = rivet_pools::from_env("api-job-test").await.unwrap(); +// let cache = rivet_cache::CacheInner::new( +// "api-job-test".to_string(), +// std::env::var("RIVET_SOURCE_HASH").unwrap(), +// pools.redis_cache().unwrap(), +// ); +// let client = chirp_client::SharedClient::from_env(pools.clone()) +// .expect("create client") +// .wrap_new("api-job-test"); +// let conn = rivet_connection::Connection::new(client, pools, cache); +// let op_ctx = OperationContext::new( +// "api-job-test".to_string(), +// std::time::Duration::from_secs(60), +// conn, +// Uuid::new_v4(), +// Uuid::new_v4(), +// util::timestamp::now(), +// util::timestamp::now(), +// (), +// Vec::new(), +// ); + +// let nomad_config = nomad_util::config_from_env().unwrap(); + +// Ctx { +// op_ctx, +// nomad_config, +// } +// } + +// fn http_client(&self, bearer_token: String) -> rivet_job::ClientWrapper { +// rivet_job::Config::builder() +// .set_uri("http://traefik.traefik.svc.cluster.local:80/job") +// .set_bearer_token(bearer_token) +// .build_client() +// } + +// /// Issues a testing job run token. We use this since we can't access the job run token issued +// /// when the job is ran. +// async fn job_run_token(&self, run_id: Uuid) -> String { +// let token_res = op!([self] token_create { +// issuer: "test".into(), +// token_config: Some(token::create::request::TokenConfig { +// ttl: util::duration::days(365), +// }), +// refresh_token_config: None, +// client: None, +// kind: Some(token::create::request::Kind::New(token::create::request::KindNew { +// entitlements: vec![ +// proto::claims::Entitlement { +// kind: Some( +// proto::claims::entitlement::Kind::JobRun(proto::claims::entitlement::JobRun { +// run_id: Some(run_id.into()), +// }) +// ) +// } +// ], +// })), +// label: Some("jr".into()), +// ..Default::default() +// }) +// .await +// .unwrap(); + +// token_res.token.as_ref().unwrap().token.clone() +// } + +// fn chirp(&self) -> &chirp_client::Client { +// self.op_ctx.chirp() +// } + +// fn op_ctx(&self) -> &OperationContext<()> { +// &self.op_ctx +// } +// } + +// async fn run_job(ctx: &Ctx) -> (Uuid, backend::job::Run, backend::job::run_meta::Nomad) { +// let res = op!([ctx] faker_job_run { +// ..Default::default() +// }) +// .await +// .unwrap(); +// let run_id = res.run_id.unwrap().as_uuid(); + +// // Check the run exists and that `job_run` is not broken +// let runs_res = op!([ctx] job_run_get { +// run_ids: vec![run_id.into()], +// }) +// .await +// .unwrap(); +// assert!(!runs_res.runs.is_empty(), "job was not created"); +// let run = runs_res.runs.first().unwrap().clone(); + +// let run_meta = match run.run_meta.as_ref().unwrap().kind.as_ref().unwrap() { +// backend::job::run_meta::Kind::Nomad(x) => x.clone(), +// }; + +// (run_id, run, run_meta) +// } + +// #[tokio::test(flavor = "multi_thread")] +// async fn run_cleanup() { +// let ctx = Ctx::init().await; + +// // MARK: POST /runs/cleanup +// { +// tracing::info!("run cleanup"); + +// // Create test job +// let (run_id, _, _run_meta) = run_job(&ctx).await; +// let run_token = ctx.job_run_token(run_id).await; +// let http_client = ctx.http_client(run_token); + +// http_client.cleanup().send().await.unwrap(); + +// tokio::time::sleep(Duration::from_secs(2)).await; + +// let run_res = op!([ctx] job_run_get { +// run_ids: vec![run_id.into()], +// }) +// .await +// .unwrap(); +// assert!( +// run_res.runs.first().unwrap().stop_ts.is_some(), +// "run was not cleaned up" +// ); +// } +// } + +// #[tokio::test(flavor = "multi_thread")] +// async fn run_cleanup_from_poststop() { +// let ctx = Ctx::init().await; + +// // MARK: POST /runs/cleanup +// { +// tracing::info!("run cleanup"); + +// // Create test job +// let (run_id, _, _run_meta) = run_job(&ctx).await; +// let run_token = ctx.job_run_token(run_id).await; +// let http_client = ctx.http_client(run_token); + +// let mut cleanup_sub = subscribe!([ctx] job_run::msg::cleanup_complete(run_id)) +// .await +// .unwrap(); + +// http_client.cleanup().send().await.unwrap(); + +// cleanup_sub.next().await.unwrap(); + +// let run_res = op!([ctx] job_run_get { +// run_ids: vec![run_id.into()], +// }) +// .await +// .unwrap(); +// assert!( +// run_res.runs.first().unwrap().stop_ts.is_some(), +// "run was not cleaned up" +// ); +// } + +// // TODO: Test the logs +// } diff --git a/svc/api/kv/tests/basic.rs b/svc/api/kv/tests/basic.rs index 1c608cff6c..009ede160c 100644 --- a/svc/api/kv/tests/basic.rs +++ b/svc/api/kv/tests/basic.rs @@ -1,570 +1,592 @@ -use proto::backend::{self, pkg::*}; -use rivet_operation::prelude::*; -use serde_json::{json, Value}; -use std::{collections::HashMap, str::FromStr, sync::Once, time::Duration}; - -use rivet_api::{ - apis::{configuration::Configuration, *}, - models, -}; - -const LOBBY_GROUP_NAME_ID: &str = "test"; - -static GLOBAL_INIT: Once = Once::new(); - -struct Ctx { - op_ctx: OperationContext<()>, - game_id: Uuid, - primary_region_id: Uuid, - namespace_id: Uuid, - mm_config_meta: backend::matchmaker::VersionConfigMeta, -} - -impl Ctx { - async fn init() -> Ctx { - GLOBAL_INIT.call_once(|| { - tracing_subscriber::fmt() - .pretty() - .with_max_level(tracing::Level::INFO) - .with_target(false) - .init(); - }); - - let pools = rivet_pools::from_env("api-kv-test").await.unwrap(); - let cache = rivet_cache::CacheInner::new( - "api-kv-test".to_string(), - std::env::var("RIVET_SOURCE_HASH").unwrap(), - pools.redis_cache().unwrap(), - ); - let client = chirp_client::SharedClient::from_env(pools.clone()) - .expect("create client") - .wrap_new("api-kv-test"); - let conn = rivet_connection::Connection::new(client, pools, cache); - let op_ctx = OperationContext::new( - "api-kv-test".to_string(), - std::time::Duration::from_secs(60), - conn, - Uuid::new_v4(), - Uuid::new_v4(), - util::timestamp::now(), - util::timestamp::now(), - (), - Vec::new(), - ); - - let (primary_region_id, _) = Self::setup_region(&op_ctx).await; - let (game_id, _, namespace_id, _, mm_config_meta) = - Self::setup_game(&op_ctx, primary_region_id).await; - - Ctx { - op_ctx, - game_id, - primary_region_id, - namespace_id, - mm_config_meta, - } - } - - fn config(&self, bearer_token: &str) -> Configuration { - Configuration { - base_path: "http://traefik.traefik.svc.cluster.local:80".into(), - bearer_access_token: Some(bearer_token.to_string()), - ..Default::default() - } - } - - async fn issue_lobby_token(&self) -> String { - // Create lobby - let lobby_group_meta = &self.mm_config_meta.lobby_groups[0]; - let lobby_id = Uuid::new_v4(); - - msg!([self.op_ctx] mm::msg::lobby_create(lobby_id) -> mm::msg::lobby_create_complete { - lobby_id: Some(lobby_id.into()), - namespace_id: Some(self.namespace_id.into()), - lobby_group_id: lobby_group_meta.lobby_group_id, - region_id: Some(self.primary_region_id.into()), - create_ray_id: None, - preemptively_created: false, - - creator_user_id: None, - is_custom: false, - publicity: None, - lobby_config_json: None, - tags: HashMap::new(), - dynamic_max_players: None, - }) - .await - .unwrap(); - - lobby_token(&self.op_ctx, lobby_id.to_string().as_str()).await - } - - async fn issue_cloud_token(&self) -> String { - let res = op!([self.op_ctx] cloud_game_token_create { - game_id: Some(self.game_id.into()), - }) - .await - .unwrap(); - - res.token - } - - async fn setup_region(ctx: &OperationContext<()>) -> (Uuid, String) { - tracing::info!("setup region"); - - let region_res = op!([ctx] faker_region {}).await.unwrap(); - let region_id = region_res.region_id.as_ref().unwrap().as_uuid(); - - let get_res = op!([ctx] region_get { - region_ids: vec![region_id.into()], - }) - .await - .unwrap(); - let region_data = get_res.regions.first().unwrap(); - - (region_id, region_data.name_id.clone()) - } - - async fn setup_game( - ctx: &OperationContext<()>, - region_id: Uuid, - ) -> ( - Uuid, - Uuid, - Uuid, - backend::matchmaker::VersionConfig, - backend::matchmaker::VersionConfigMeta, - ) { - let game_res = op!([ctx] faker_game { - ..Default::default() - }) - .await - .unwrap(); - - let build_res = op!([ctx] faker_build { - game_id: game_res.game_id, - image: backend::faker::Image::MmLobbyAutoReady as i32, - }) - .await - .unwrap(); - - let game_version_res = op!([ctx] faker_game_version { - game_id: game_res.game_id, - override_lobby_groups: Some(faker::game_version::request::OverrideLobbyGroups { - lobby_groups: vec![backend::matchmaker::LobbyGroup { - name_id: LOBBY_GROUP_NAME_ID.into(), - - regions: vec![backend::matchmaker::lobby_group::Region { - region_id: Some(region_id.into()), - tier_name_id: util_mm::test::TIER_NAME_ID.to_owned(), - idle_lobbies: None, - }], - max_players_normal: 8, - max_players_direct: 10, - max_players_party: 12, - listable: true, - taggable: false, - allow_dynamic_max_players: false, - - runtime: Some(backend::matchmaker::lobby_runtime::Docker { - build_id: build_res.build_id, - args: Vec::new(), - env_vars: Vec::new(), - network_mode: backend::matchmaker::lobby_runtime::NetworkMode::Bridge as i32, - ports: vec![ - backend::matchmaker::lobby_runtime::Port { - label: "test-80-http".into(), - target_port: Some(80), - port_range: None, - proxy_protocol: backend::matchmaker::lobby_runtime::ProxyProtocol::Http as i32, - proxy_kind: backend::matchmaker::lobby_runtime::ProxyKind::GameGuard as i32, - }, - backend::matchmaker::lobby_runtime::Port { - label: "test-80-https".into(), - target_port: Some(80), - port_range: None, - proxy_protocol: backend::matchmaker::lobby_runtime::ProxyProtocol::Https as i32, - proxy_kind: backend::matchmaker::lobby_runtime::ProxyKind::GameGuard as i32, - }, - backend::matchmaker::lobby_runtime::Port { - label: "test-5050-https".into(), - target_port: Some(5050), - port_range: None, - proxy_protocol: backend::matchmaker::lobby_runtime::ProxyProtocol::Https as i32, - proxy_kind: backend::matchmaker::lobby_runtime::ProxyKind::GameGuard as i32, - }, - ], - }.into()), - - actions: None, - }], - }), - ..Default::default() - }) - .await - .unwrap(); - - let namespace_res = op!([ctx] faker_game_namespace { - game_id: game_res.game_id, - version_id: game_version_res.version_id, - ..Default::default() - }) - .await - .unwrap(); - - ( - game_res.game_id.as_ref().unwrap().as_uuid(), - game_version_res.version_id.as_ref().unwrap().as_uuid(), - namespace_res.namespace_id.as_ref().unwrap().as_uuid(), - game_version_res.mm_config.clone().unwrap(), - game_version_res.mm_config_meta.clone().unwrap(), - ) - } -} - -#[tokio::test(flavor = "multi_thread")] -async fn generic() { - let ctx = Ctx::init().await; - let lobby_token = ctx.issue_lobby_token().await; - - // MARK: GET /entries - { - tracing::info!("get empty value"); - - let res = kv_api::kv_get(&ctx.config(&lobby_token), "non/existent/value", None, None) - .await - .unwrap(); - - assert!( - matches!(res.value, None | Some(Value::Null)), - "invalid get response" - ); - } - - // MARK: PUT /entries - let value1 = { - tracing::info!("put value"); - - let value = json!({ - "likes": 12 - }); - - kv_api::kv_put( - &ctx.config(&lobby_token), - models::KvPutRequest { - key: "some/value".into(), - value: Some(value.clone()), - namespace_id: None, - }, - ) - .await - .unwrap(); - - value - }; - - // MARK: GET /entries - { - tracing::info!("get value"); - - let res = kv_api::kv_get(&ctx.config(&lobby_token), "some/value", None, None) - .await - .unwrap(); - - assert_eq!(res.value.unwrap(), value1, "wrong value received"); - } - - // MARK: PUT /entries - let value2 = { - tracing::info!("put another value"); - - let value = json!({ - "follows": 100 - }); - - kv_api::kv_put( - &ctx.config(&lobby_token), - models::KvPutRequest { - key: "some/other-value".into(), - value: Some(value.clone()), - namespace_id: None, - }, - ) - .await - .unwrap(); - - value - }; - - // MARK: GET /entries/batch - { - tracing::info!("get multiple values"); - - // Individual keys - { - // OpenAPI generator does not support repeated query strings - let res = reqwest::Client::new() - .get("http://traefik.traefik.svc.cluster.local:80/kv/entries/batch") - .bearer_auth(&lobby_token) - .query(&[ - ("keys", "some/value"), - ("keys", "some/other-value"), - ("keys", "non/existent"), - ]) - .send() - .await - .unwrap() - .error_for_status() - .unwrap() - .json::() - .await - .unwrap(); - - assert_eq!(res.entries.len(), 2, "wrong key count"); - - let entry1 = res.entries.iter().find(|x| x.key == "some/value").unwrap(); - assert_eq!(*entry1.value.as_ref().unwrap(), value1); - - let entry2 = res - .entries - .iter() - .find(|x| x.key == "some/other-value") - .unwrap(); - assert_eq!(*entry2.value.as_ref().unwrap(), value2); - } - } - - // MARK: GET /entries - { - tracing::info!("watch value"); - - let value = json!({ - "update": true - }); - - let (res, _) = tokio::join!( - async { - kv_api::kv_get( - &ctx.config(&lobby_token), - "some/value", - Some(&util::timestamp::now().to_string()), - None, - ) - .await - .unwrap() - }, - async { - // Wait before putting - tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; - - kv_api::kv_put( - &ctx.config(&lobby_token), - models::KvPutRequest { - key: "some/value".into(), - value: Some(value.clone()), - namespace_id: None, - }, - ) - .await - .unwrap(); - } - ); - - assert_eq!(res.value.unwrap(), value, "wrong value received"); - } - - // MARK: GET /entries/batch - { - tracing::info!("watch multiple keys"); - - let value = json!({ - "update": true - }); - - let (res, _) = tokio::join!( - async { - // OpenAPI generator does not support repeated query strings - reqwest::Client::new() - .get("http://traefik.traefik.svc.cluster.local:80/kv/entries/batch") - .bearer_auth(&lobby_token) - .query(&[ - ("keys", "some/value"), - ("keys", "some/other-value"), - ("watch_index", &util::timestamp::now().to_string()), - ]) - .send() - .await - .unwrap() - .error_for_status() - .unwrap() - .json::() - .await - .unwrap() - }, - async { - // Wait before putting - tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; - - kv_api::kv_put( - &ctx.config(&lobby_token), - models::KvPutRequest { - key: "some/value".into(), - value: Some(value.clone()), - namespace_id: None, - }, - ) - .await - .unwrap(); - } - ); - - // Ordered alphabetically - assert_eq!(res.entries.len(), 1, "wrong key count"); - - let first = res.entries.first().unwrap(); - assert_eq!(first.key, "some/value", "wrong key"); - assert_eq!(*first.value.as_ref().unwrap(), value, "wrong value"); - } - - // MARK: PUT /put - { - tracing::info!("put value"); - - let value = json!({ - "likes": 12 - }); - - kv_api::kv_put( - &ctx.config(&lobby_token), - models::KvPutRequest { - key: "some/value".into(), - value: Some(value.clone()), - namespace_id: None, - }, - ) - .await - .unwrap(); - }; - - // MARK: DELETE /delete - { - tracing::info!("delete value"); - - kv_api::kv_delete(&ctx.config(&lobby_token), "some/value", None) - .await - .unwrap(); - } - - // MARK: GET /get - { - tracing::info!("get value"); - - let res = kv_api::kv_get(&ctx.config(&lobby_token), "some/value", None, None) - .await - .unwrap(); - - assert!( - matches!(res.value, Some(serde_json::Value::Null) | None), - "wrong value received" - ); - } - - // TODO: - // - watch tests with specific anchor - // - tests with cloud token - // - write tests for put batch and delete batch - // - max key length - // - max value length -} - -#[tokio::test(flavor = "multi_thread")] -async fn list() { - let ctx = Ctx::init().await; - let cloud_token = ctx.issue_cloud_token().await; - - let values = (0..12).map(|i| json!({ "idx": i })).collect::>(); - - // Write data - for (i, value) in values.iter().enumerate() { - kv_api::kv_put( - &ctx.config(&cloud_token), - models::KvPutRequest { - key: format!("root-{i}"), - value: Some(value.clone()), - namespace_id: Some(ctx.namespace_id), - }, - ) - .await - .unwrap(); - - kv_api::kv_put( - &ctx.config(&cloud_token), - models::KvPutRequest { - key: format!("value/idx-{i}"), - value: Some(value.clone()), - namespace_id: Some(ctx.namespace_id), - }, - ) - .await - .unwrap(); - } - - // kv-list is not consistent for performance - tokio::time::sleep(Duration::from_secs(2)).await; - - // List root - let res = kv_api::kv_list(&ctx.config(&cloud_token), "", &ctx.namespace_id.to_string()) - .await - .unwrap(); - - assert_eq!( - values.len(), - res.entries.len(), - "wrong value count returned" - ); - - // List subdir - let res = kv_api::kv_list( - &ctx.config(&cloud_token), - "value", - &ctx.namespace_id.to_string(), - ) - .await - .unwrap(); - - assert_eq!( - values.len(), - res.entries.len(), - "wrong value count returned" - ); -} - -/// Issues a testing lobby token. We use this since we can't access the lobby token issued -/// on the lobby creation. -async fn lobby_token(ctx: &OperationContext<()>, lobby_id: &str) -> String { - let token_res = op!([ctx] token_create { - issuer: "test".into(), - token_config: Some(token::create::request::TokenConfig { - ttl: util::duration::days(365), - }), - refresh_token_config: None, - client: None, - kind: Some(token::create::request::Kind::New(token::create::request::KindNew { - entitlements: vec![ - proto::claims::Entitlement { - kind: Some( - proto::claims::entitlement::Kind::MatchmakerLobby(proto::claims::entitlement::MatchmakerLobby { - lobby_id: Some(Uuid::from_str(lobby_id).unwrap().into()), - }) - ) - } - ], - })), - label: Some("lobby".into()), - ..Default::default() - }) - .await - .unwrap(); - - token_res.token.as_ref().unwrap().token.clone() -} +// TODO: KV will be deprecated + +// use std::{collections::HashMap, str::FromStr, sync::Once, time::Duration}; + +// use proto::backend::{self, pkg::*}; +// use reqwest::header; +// use rivet_api::{ +// apis::{configuration::Configuration, *}, +// models, +// }; +// use rivet_operation::prelude::*; +// use serde_json::{json, Value}; + +// const LOBBY_GROUP_NAME_ID: &str = "test"; + +// static GLOBAL_INIT: Once = Once::new(); + +// struct Ctx { +// op_ctx: OperationContext<()>, +// game_id: Uuid, +// primary_region_id: Uuid, +// namespace_id: Uuid, +// mm_config_meta: backend::matchmaker::VersionConfigMeta, +// } + +// impl Ctx { +// async fn init() -> Ctx { +// GLOBAL_INIT.call_once(|| { +// tracing_subscriber::fmt() +// .pretty() +// .with_max_level(tracing::Level::INFO) +// .with_target(false) +// .init(); +// }); + +// let pools = rivet_pools::from_env("api-kv-test").await.unwrap(); +// let cache = rivet_cache::CacheInner::new( +// "api-kv-test".to_string(), +// std::env::var("RIVET_SOURCE_HASH").unwrap(), +// pools.redis_cache().unwrap(), +// ); +// let client = chirp_client::SharedClient::from_env(pools.clone()) +// .expect("create client") +// .wrap_new("api-kv-test"); +// let conn = rivet_connection::Connection::new(client, pools, cache); +// let op_ctx = OperationContext::new( +// "api-kv-test".to_string(), +// std::time::Duration::from_secs(60), +// conn, +// Uuid::new_v4(), +// Uuid::new_v4(), +// util::timestamp::now(), +// util::timestamp::now(), +// (), +// Vec::new(), +// ); + +// let (primary_region_id, _) = Self::setup_region(&op_ctx).await; +// let (game_id, _, namespace_id, _, mm_config_meta) = +// Self::setup_game(&op_ctx, primary_region_id).await; + +// Ctx { +// op_ctx, +// game_id, +// primary_region_id, +// namespace_id, +// mm_config_meta, +// } +// } + +// fn config(&self, bearer_token: &str) -> Configuration { +// Configuration { +// base_path: "http://traefik.traefik.svc.cluster.local:80".into(), +// bearer_access_token: Some(bearer_token.to_string()), +// client: { +// let mut headers = header::HeaderMap::new(); +// headers.insert( +// header::HOST, +// header::HeaderValue::from_str(util::env::domain_main_api().unwrap()).unwrap(), +// ); +// headers.insert( +// "cf-connecting-ip", +// header::HeaderValue::from_static("127.0.0.1"), +// ); +// reqwest::Client::builder() +// .default_headers(headers) +// .build() +// .unwrap() +// }, +// ..Default::default() +// } +// } + +// async fn issue_lobby_token(&self) -> String { +// // Create lobby +// let lobby_group_meta = &self.mm_config_meta.lobby_groups[0]; +// let lobby_id = Uuid::new_v4(); + +// msg!([self.op_ctx] mm::msg::lobby_create(lobby_id) -> mm::msg::lobby_create_complete { +// lobby_id: Some(lobby_id.into()), +// namespace_id: Some(self.namespace_id.into()), +// lobby_group_id: lobby_group_meta.lobby_group_id, +// region_id: Some(self.primary_region_id.into()), +// create_ray_id: None, +// preemptively_created: false, + +// creator_user_id: None, +// is_custom: false, +// publicity: None, +// lobby_config_json: None, +// tags: HashMap::new(), +// dynamic_max_players: None, +// }) +// .await +// .unwrap(); + +// lobby_token(&self.op_ctx, lobby_id.to_string().as_str()).await +// } + +// async fn issue_cloud_token(&self) -> String { +// let res = op!([self.op_ctx] cloud_game_token_create { +// game_id: Some(self.game_id.into()), +// }) +// .await +// .unwrap(); + +// res.token +// } + +// async fn setup_region(ctx: &OperationContext<()>) -> (Uuid, String) { +// tracing::info!("setup region"); + +// let region_res = op!([ctx] faker_region {}).await.unwrap(); +// let region_id = region_res.region_id.as_ref().unwrap().as_uuid(); + +// let get_res = op!([ctx] region_get { +// region_ids: vec![region_id.into()], +// }) +// .await +// .unwrap(); +// let region_data = get_res.regions.first().unwrap(); + +// (region_id, region_data.name_id.clone()) +// } + +// async fn setup_game( +// ctx: &OperationContext<()>, +// region_id: Uuid, +// ) -> ( +// Uuid, +// Uuid, +// Uuid, +// backend::matchmaker::VersionConfig, +// backend::matchmaker::VersionConfigMeta, +// ) { +// let game_res = op!([ctx] faker_game { +// ..Default::default() +// }) +// .await +// .unwrap(); + +// let build_res = op!([ctx] faker_build { +// game_id: game_res.game_id, +// image: backend::faker::Image::MmLobbyAutoReady as i32, +// }) +// .await +// .unwrap(); + +// let game_version_res = op!([ctx] faker_game_version { +// game_id: game_res.game_id, +// override_lobby_groups: Some(faker::game_version::request::OverrideLobbyGroups { +// lobby_groups: vec![backend::matchmaker::LobbyGroup { +// name_id: LOBBY_GROUP_NAME_ID.into(), + +// regions: vec![backend::matchmaker::lobby_group::Region { +// region_id: Some(region_id.into()), +// tier_name_id: util_mm::test::TIER_NAME_ID.to_owned(), +// idle_lobbies: None, +// }], +// max_players_normal: 8, +// max_players_direct: 10, +// max_players_party: 12, +// listable: true, +// taggable: false, +// allow_dynamic_max_players: false, + +// runtime: Some(backend::matchmaker::lobby_runtime::Docker { +// build_id: build_res.build_id, +// args: Vec::new(), +// env_vars: Vec::new(), +// network_mode: backend::matchmaker::lobby_runtime::NetworkMode::Bridge as i32, +// ports: vec![ +// backend::matchmaker::lobby_runtime::Port { +// label: "test-80-http".into(), +// target_port: Some(80), +// port_range: None, +// proxy_protocol: backend::matchmaker::lobby_runtime::ProxyProtocol::Http as i32, +// proxy_kind: backend::matchmaker::lobby_runtime::ProxyKind::GameGuard as i32, +// }, +// backend::matchmaker::lobby_runtime::Port { +// label: "test-80-https".into(), +// target_port: Some(80), +// port_range: None, +// proxy_protocol: backend::matchmaker::lobby_runtime::ProxyProtocol::Https as i32, +// proxy_kind: backend::matchmaker::lobby_runtime::ProxyKind::GameGuard as i32, +// }, +// backend::matchmaker::lobby_runtime::Port { +// label: "test-5050-https".into(), +// target_port: Some(5050), +// port_range: None, +// proxy_protocol: backend::matchmaker::lobby_runtime::ProxyProtocol::Https as i32, +// proxy_kind: backend::matchmaker::lobby_runtime::ProxyKind::GameGuard as i32, +// }, +// ], +// }.into()), + +// actions: None, +// }], +// }), +// ..Default::default() +// }) +// .await +// .unwrap(); + +// let namespace_res = op!([ctx] faker_game_namespace { +// game_id: game_res.game_id, +// version_id: game_version_res.version_id, +// ..Default::default() +// }) +// .await +// .unwrap(); + +// ( +// game_res.game_id.as_ref().unwrap().as_uuid(), +// game_version_res.version_id.as_ref().unwrap().as_uuid(), +// namespace_res.namespace_id.as_ref().unwrap().as_uuid(), +// game_version_res.mm_config.clone().unwrap(), +// game_version_res.mm_config_meta.clone().unwrap(), +// ) +// } +// } + +// #[tokio::test(flavor = "multi_thread")] +// async fn generic() { +// let ctx = Ctx::init().await; +// let lobby_token = ctx.issue_lobby_token().await; + +// // MARK: GET /entries +// { +// tracing::info!("get empty value"); + +// let res = kv_api::kv_get(&ctx.config(&lobby_token), "non/existent/value", None, None) +// .await +// .unwrap(); + +// assert!( +// matches!(res.value, None | Some(Value::Null)), +// "invalid get response" +// ); +// } + +// // MARK: PUT /entries +// let value1 = { +// tracing::info!("put value"); + +// let value = json!({ +// "likes": 12 +// }); + +// kv_api::kv_put( +// &ctx.config(&lobby_token), +// models::KvPutRequest { +// key: "some/value".into(), +// value: Some(value.clone()), +// namespace_id: None, +// }, +// ) +// .await +// .unwrap(); + +// value +// }; + +// // MARK: GET /entries +// { +// tracing::info!("get value"); + +// let res = kv_api::kv_get(&ctx.config(&lobby_token), "some/value", None, None) +// .await +// .unwrap(); + +// assert_eq!(res.value.unwrap(), value1, "wrong value received"); +// } + +// // MARK: PUT /entries +// let value2 = { +// tracing::info!("put another value"); + +// let value = json!({ +// "follows": 100 +// }); + +// kv_api::kv_put( +// &ctx.config(&lobby_token), +// models::KvPutRequest { +// key: "some/other-value".into(), +// value: Some(value.clone()), +// namespace_id: None, +// }, +// ) +// .await +// .unwrap(); + +// value +// }; + +// // MARK: GET /entries/batch +// { +// tracing::info!("get multiple values"); + +// // Individual keys +// { +// let config = &ctx.config(&lobby_token); +// // OpenAPI generator does not support repeated query strings +// let res = config +// .client +// .get(format!("{}/kv/entries/batch", config.base_path)) +// .bearer_auth(&lobby_token) +// .query(&[ +// ("keys", "some/value"), +// ("keys", "some/other-value"), +// ("keys", "non/existent"), +// ]) +// .send() +// .await +// .unwrap() +// .error_for_status() +// .unwrap() +// .json::() +// .await +// .unwrap(); + +// assert_eq!(res.entries.len(), 2, "wrong key count"); + +// let entry1 = res.entries.iter().find(|x| x.key == "some/value").unwrap(); +// assert_eq!(*entry1.value.as_ref().unwrap(), value1); + +// let entry2 = res +// .entries +// .iter() +// .find(|x| x.key == "some/other-value") +// .unwrap(); +// assert_eq!(*entry2.value.as_ref().unwrap(), value2); +// } +// } + +// // MARK: GET /entries +// { +// tracing::info!("watch value"); + +// let value = json!({ +// "update": true +// }); + +// let (res, _) = tokio::join!( +// async { +// kv_api::kv_get( +// &ctx.config(&lobby_token), +// "some/value", +// Some(&util::timestamp::now().to_string()), +// None, +// ) +// .await +// .unwrap() +// }, +// async { +// // Wait before putting +// tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; + +// kv_api::kv_put( +// &ctx.config(&lobby_token), +// models::KvPutRequest { +// key: "some/value".into(), +// value: Some(value.clone()), +// namespace_id: None, +// }, +// ) +// .await +// .unwrap(); +// } +// ); + +// assert_eq!(res.value.unwrap(), value, "wrong value received"); +// } + +// // MARK: GET /entries/batch +// { +// tracing::info!("watch multiple keys"); + +// let value = json!({ +// "update": true +// }); + +// let (res, _) = tokio::join!( +// async { +// let config = &ctx.config(&lobby_token); +// // OpenAPI generator does not support repeated query strings +// config +// .client +// .get(format!("{}/kv/entries/batch", config.base_path)) +// .bearer_auth(&lobby_token) +// .query(&[ +// ("keys", "some/value"), +// ("keys", "some/other-value"), +// ("watch_index", &util::timestamp::now().to_string()), +// ]) +// .send() +// .await +// .unwrap() +// .error_for_status() +// .unwrap() +// .json::() +// .await +// .unwrap() +// }, +// async { +// // Wait before putting +// tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; + +// kv_api::kv_put( +// &ctx.config(&lobby_token), +// models::KvPutRequest { +// key: "some/value".into(), +// value: Some(value.clone()), +// namespace_id: None, +// }, +// ) +// .await +// .unwrap(); +// } +// ); + +// // Ordered alphabetically +// assert_eq!(res.entries.len(), 1, "wrong key count"); + +// let first = res.entries.first().unwrap(); +// assert_eq!(first.key, "some/value", "wrong key"); +// assert_eq!(*first.value.as_ref().unwrap(), value, "wrong value"); +// } + +// // MARK: PUT /put +// { +// tracing::info!("put value"); + +// let value = json!({ +// "likes": 12 +// }); + +// kv_api::kv_put( +// &ctx.config(&lobby_token), +// models::KvPutRequest { +// key: "some/value".into(), +// value: Some(value.clone()), +// namespace_id: None, +// }, +// ) +// .await +// .unwrap(); +// }; + +// // MARK: DELETE /delete +// { +// tracing::info!("delete value"); + +// kv_api::kv_delete(&ctx.config(&lobby_token), "some/value", None) +// .await +// .unwrap(); +// } + +// // MARK: GET /get +// { +// tracing::info!("get value"); + +// let res = kv_api::kv_get(&ctx.config(&lobby_token), "some/value", None, None) +// .await +// .unwrap(); + +// assert!( +// matches!(res.value, Some(serde_json::Value::Null) | None), +// "wrong value received" +// ); +// } + +// // TODO: +// // - watch tests with specific anchor +// // - tests with cloud token +// // - write tests for put batch and delete batch +// // - max key length +// // - max value length +// } + +// #[tokio::test(flavor = "multi_thread")] +// async fn list() { +// let ctx = Ctx::init().await; +// let cloud_token = ctx.issue_cloud_token().await; + +// let values = (0..12).map(|i| json!({ "idx": i })).collect::>(); + +// // Write data +// for (i, value) in values.iter().enumerate() { +// kv_api::kv_put( +// &ctx.config(&cloud_token), +// models::KvPutRequest { +// key: format!("root-{i}"), +// value: Some(value.clone()), +// namespace_id: Some(ctx.namespace_id), +// }, +// ) +// .await +// .unwrap(); + +// kv_api::kv_put( +// &ctx.config(&cloud_token), +// models::KvPutRequest { +// key: format!("value/idx-{i}"), +// value: Some(value.clone()), +// namespace_id: Some(ctx.namespace_id), +// }, +// ) +// .await +// .unwrap(); +// } + +// // kv-list is not consistent for performance +// tokio::time::sleep(Duration::from_secs(2)).await; + +// // List root +// let res = kv_api::kv_list(&ctx.config(&cloud_token), "", &ctx.namespace_id.to_string()) +// .await +// .unwrap(); + +// assert_eq!( +// values.len(), +// res.entries.len(), +// "wrong value count returned" +// ); + +// // List subdir +// let res = kv_api::kv_list( +// &ctx.config(&cloud_token), +// "value", +// &ctx.namespace_id.to_string(), +// ) +// .await +// .unwrap(); + +// assert_eq!( +// values.len(), +// res.entries.len(), +// "wrong value count returned" +// ); +// } + +// /// Issues a testing lobby token. We use this since we can't access the lobby token issued +// /// on the lobby creation. +// async fn lobby_token(ctx: &OperationContext<()>, lobby_id: &str) -> String { +// let token_res = op!([ctx] token_create { +// issuer: "test".into(), +// token_config: Some(token::create::request::TokenConfig { +// ttl: util::duration::days(365), +// }), +// refresh_token_config: None, +// client: None, +// kind: Some(token::create::request::Kind::New(token::create::request::KindNew { +// entitlements: vec![ +// proto::claims::Entitlement { +// kind: Some( +// proto::claims::entitlement::Kind::MatchmakerLobby(proto::claims::entitlement::MatchmakerLobby { +// lobby_id: Some(Uuid::from_str(lobby_id).unwrap().into()), +// }) +// ) +// } +// ], +// })), +// label: Some("lobby".into()), +// ..Default::default() +// }) +// .await +// .unwrap(); + +// token_res.token.as_ref().unwrap().token.clone() +// } diff --git a/svc/api/matchmaker/tests/common.rs b/svc/api/matchmaker/tests/common.rs index f05f842925..c6f2b232fe 100644 --- a/svc/api/matchmaker/tests/common.rs +++ b/svc/api/matchmaker/tests/common.rs @@ -1,6 +1,7 @@ use std::{str::FromStr, sync::Once}; use proto::backend::{self, pkg::*}; +use reqwest::header; use rivet_api::{apis::configuration::Configuration, models}; use rivet_operation::prelude::*; @@ -109,6 +110,21 @@ impl Ctx { Configuration { base_path: "http://traefik.traefik.svc.cluster.local:80".into(), bearer_access_token: Some(bearer_token), + client: { + let mut headers = header::HeaderMap::new(); + headers.insert( + header::HOST, + header::HeaderValue::from_str(util::env::domain_main_api().unwrap()).unwrap(), + ); + headers.insert( + "cf-connecting-ip", + header::HeaderValue::from_static("127.0.0.1"), + ); + reqwest::Client::builder() + .default_headers(headers) + .build() + .unwrap() + }, ..Default::default() } } diff --git a/svc/api/module/tests/basic.rs b/svc/api/module/tests/basic.rs index e0f8b83690..1b04d2d6d1 100644 --- a/svc/api/module/tests/basic.rs +++ b/svc/api/module/tests/basic.rs @@ -1,344 +1,346 @@ -use proto::backend::{self, pkg::*}; -use rivet_operation::prelude::*; -use serde_json::json; -use std::{str::FromStr, sync::Once}; - -use rivet_api::{ - apis::{configuration::Configuration, *}, - models, -}; - -const LOBBY_GROUP_NAME_ID: &str = "test"; - -static GLOBAL_INIT: Once = Once::new(); - -struct Ctx { - op_ctx: OperationContext<()>, - game_id: Uuid, - primary_region_id: Uuid, - namespace_id: Uuid, - mm_config_meta: backend::matchmaker::VersionConfigMeta, -} - -impl Ctx { - async fn init() -> Ctx { - GLOBAL_INIT.call_once(|| { - tracing_subscriber::fmt() - .pretty() - .with_max_level(tracing::Level::INFO) - .with_target(false) - .init(); - }); - - let pools = rivet_pools::from_env("api-module-test").await.unwrap(); - let cache = rivet_cache::CacheInner::new( - "api-module-test".to_string(), - std::env::var("RIVET_SOURCE_HASH").unwrap(), - pools.redis_cache().unwrap(), - ); - let client = chirp_client::SharedClient::from_env(pools.clone()) - .expect("create client") - .wrap_new("api-module-test"); - let conn = rivet_connection::Connection::new(client, pools, cache); - let op_ctx = OperationContext::new( - "api-module-test".to_string(), - std::time::Duration::from_secs(60), - conn, - Uuid::new_v4(), - Uuid::new_v4(), - util::timestamp::now(), - util::timestamp::now(), - (), - Vec::new(), - ); - - let (primary_region_id, _) = Self::setup_region(&op_ctx).await; - let (_, module_version_id) = Self::setup_module(&op_ctx).await; - let (game_id, _, namespace_id, _, mm_config_meta) = - Self::setup_game(&op_ctx, primary_region_id, module_version_id).await; - - Ctx { - op_ctx, - game_id, - primary_region_id, - namespace_id, - mm_config_meta, - } - } - - fn config(&self, bearer_token: &str) -> Configuration { - Configuration { - base_path: "http://traefik.traefik.svc.cluster.local:80".into(), - bearer_access_token: Some(bearer_token.to_string()), - ..Default::default() - } - } - - async fn issue_ns_token(&self) -> String { - let token_res = op!([self.op_ctx] cloud_namespace_token_public_create { - namespace_id: Some(self.namespace_id.into()), - }) - .await - .unwrap(); - - token_res.token - } - - async fn issue_lobby_token(&self) -> String { - // Create lobby - let lobby_group_meta = &self.mm_config_meta.lobby_groups[0]; - let lobby_id = Uuid::new_v4(); - - msg!([self.op_ctx] mm::msg::lobby_create(lobby_id) -> mm::msg::lobby_create_complete { - lobby_id: Some(lobby_id.into()), - namespace_id: Some(self.namespace_id.into()), - lobby_group_id: lobby_group_meta.lobby_group_id, - region_id: Some(self.primary_region_id.into()), - create_ray_id: None, - preemptively_created: false, - ..Default::default() - }) - .await - .unwrap(); - - lobby_token(&self.op_ctx, lobby_id.to_string().as_str()).await - } - - async fn issue_cloud_token(&self) -> String { - let res = op!([self.op_ctx] cloud_game_token_create { - game_id: Some(self.game_id.into()), - }) - .await - .unwrap(); - - res.token - } - - async fn setup_region(ctx: &OperationContext<()>) -> (Uuid, String) { - tracing::info!("setup region"); - - let region_res = op!([ctx] faker_region {}).await.unwrap(); - let region_id = region_res.region_id.as_ref().unwrap().as_uuid(); - - let get_res = op!([ctx] region_get { - region_ids: vec![region_id.into()], - }) - .await - .unwrap(); - let region_data = get_res.regions.first().unwrap(); - - (region_id, region_data.name_id.clone()) - } - - async fn setup_module(ctx: &OperationContext<()>) -> (Uuid, Uuid) { - let module_id = Uuid::new_v4(); - let version_id = Uuid::new_v4(); - - msg!([ctx] module::msg::create(module_id) -> module::msg::create_complete { - module_id: Some(module_id.into()), - name_id: "test".into(), - team_id: Some(Uuid::new_v4().into()), - creator_user_id: None, - }) - .await - .unwrap(); - - msg!([ctx] module::msg::version_create(version_id) -> module::msg::version_create_complete { - version_id: Some(version_id.into()), - module_id: Some(module_id.into()), - creator_user_id: None, - - major: 1, - minor: 0, - patch: 0, - - scripts: vec![ - backend::module::Script { - name: "foo".into(), - request_schema: "{}".into(), - response_schema: "{}".into(), - callable: Some(backend::module::script::Callable {}), - }, - ], - - image: Some(module::msg::version_create::message::Image::Docker(module::msg::version_create::message::Docker { - image_tag: "ghcr.io/rivet-gg/rivet-module-hello-world:0.0.1".into(), - })), - }).await.unwrap(); - - (module_id, version_id) - } - - async fn setup_game( - ctx: &OperationContext<()>, - region_id: Uuid, - module_version_id: Uuid, - ) -> ( - Uuid, - Uuid, - Uuid, - backend::matchmaker::VersionConfig, - backend::matchmaker::VersionConfigMeta, - ) { - let game_res = op!([ctx] faker_game { - ..Default::default() - }) - .await - .unwrap(); - - let build_res = op!([ctx] faker_build { - game_id: game_res.game_id, - image: backend::faker::Image::MmLobbyAutoReady as i32, - }) - .await - .unwrap(); - - let game_version_res = op!([ctx] faker_game_version { - game_id: game_res.game_id, - override_cdn_config: Some(faker::game_version::request::OverrideCdnConfig { - config: None, - }), - override_module_config: Some(faker::game_version::request::OverrideModuleConfig { - config: Some(backend::module::GameVersionConfig { - dependencies: vec![ - backend::module::game_version_config::Dependency { - key: "hello-world".into(), - module_version_id: Some(module_version_id.into()), - } - ] - }) - }), - override_lobby_groups: Some(faker::game_version::request::OverrideLobbyGroups { - lobby_groups: vec![backend::matchmaker::LobbyGroup { - name_id: LOBBY_GROUP_NAME_ID.into(), - - regions: vec![backend::matchmaker::lobby_group::Region { - region_id: Some(region_id.into()), - tier_name_id: util_mm::test::TIER_NAME_ID.to_owned(), - idle_lobbies: None, - }], - max_players_normal: 8, - max_players_direct: 10, - max_players_party: 12, - - runtime: Some(backend::matchmaker::lobby_runtime::Docker { - build_id: build_res.build_id, - args: Vec::new(), - env_vars: Vec::new(), - network_mode: backend::matchmaker::lobby_runtime::NetworkMode::Bridge as i32, - ports: vec![ - backend::matchmaker::lobby_runtime::Port { - label: "test-80-http".into(), - target_port: Some(80), - port_range: None, - proxy_protocol: backend::matchmaker::lobby_runtime::ProxyProtocol::Http as i32, - proxy_kind: backend::matchmaker::lobby_runtime::ProxyKind::GameGuard as i32, - }, - backend::matchmaker::lobby_runtime::Port { - label: "test-80-https".into(), - target_port: Some(80), - port_range: None, - proxy_protocol: backend::matchmaker::lobby_runtime::ProxyProtocol::Https as i32, - proxy_kind: backend::matchmaker::lobby_runtime::ProxyKind::GameGuard as i32, - }, - backend::matchmaker::lobby_runtime::Port { - label: "test-5050-https".into(), - target_port: Some(5050), - port_range: None, - proxy_protocol: backend::matchmaker::lobby_runtime::ProxyProtocol::Https as i32, - proxy_kind: backend::matchmaker::lobby_runtime::ProxyKind::GameGuard as i32, - }, - ], - }.into()), - ..Default::default() - }], - }), - ..Default::default() - }) - .await - .unwrap(); - - let mut module_ns_version_set_complete = - subscribe!([ctx] module::msg::ns_version_set_complete("*")) - .await - .unwrap(); - let namespace_res = op!([ctx] faker_game_namespace { - game_id: game_res.game_id, - version_id: game_version_res.version_id, - ..Default::default() - }) - .await - .unwrap(); - module_ns_version_set_complete.next().await.unwrap(); - - ( - game_res.game_id.as_ref().unwrap().as_uuid(), - game_version_res.version_id.as_ref().unwrap().as_uuid(), - namespace_res.namespace_id.as_ref().unwrap().as_uuid(), - game_version_res.mm_config.clone().unwrap(), - game_version_res.mm_config_meta.clone().unwrap(), - ) - } -} - -#[tokio::test(flavor = "multi_thread")] -async fn call() { - let ctx = Ctx::init().await; - let token = ctx.issue_ns_token().await; - - let res = module_api::module_call( - &ctx.config(&token), - "hello-world", - "foo", - models::ModuleCallRequest { - namespace_id: None, - data: Some(json!({ - "x": 5 - })), - }, - None, - ) - .await - .unwrap(); - assert_eq!( - 10, - res.data - .unwrap() - .as_object() - .unwrap() - .get("y") - .unwrap() - .as_i64() - .unwrap() - ); -} - -/// Issues a testing lobby token. We use this since we can't access the lobby token issued -/// on the lobby creation. -async fn lobby_token(ctx: &OperationContext<()>, lobby_id: &str) -> String { - let token_res = op!([ctx] token_create { - issuer: "test".into(), - token_config: Some(token::create::request::TokenConfig { - ttl: util::duration::days(365), - }), - refresh_token_config: None, - client: None, - kind: Some(token::create::request::Kind::New(token::create::request::KindNew { - entitlements: vec![ - proto::claims::Entitlement { - kind: Some( - proto::claims::entitlement::Kind::MatchmakerLobby(proto::claims::entitlement::MatchmakerLobby { - lobby_id: Some(Uuid::from_str(lobby_id).unwrap().into()), - }) - ) - } - ], - })), - label: Some("lobby".into()), - ..Default::default() - }) - .await - .unwrap(); - - token_res.token.as_ref().unwrap().token.clone() -} +// TODO: Modules were removed + +// use proto::backend::{self, pkg::*}; +// use rivet_operation::prelude::*; +// use serde_json::json; +// use std::{str::FromStr, sync::Once}; + +// use rivet_api::{ +// apis::{configuration::Configuration, *}, +// models, +// }; + +// const LOBBY_GROUP_NAME_ID: &str = "test"; + +// static GLOBAL_INIT: Once = Once::new(); + +// struct Ctx { +// op_ctx: OperationContext<()>, +// game_id: Uuid, +// primary_region_id: Uuid, +// namespace_id: Uuid, +// mm_config_meta: backend::matchmaker::VersionConfigMeta, +// } + +// impl Ctx { +// async fn init() -> Ctx { +// GLOBAL_INIT.call_once(|| { +// tracing_subscriber::fmt() +// .pretty() +// .with_max_level(tracing::Level::INFO) +// .with_target(false) +// .init(); +// }); + +// let pools = rivet_pools::from_env("api-module-test").await.unwrap(); +// let cache = rivet_cache::CacheInner::new( +// "api-module-test".to_string(), +// std::env::var("RIVET_SOURCE_HASH").unwrap(), +// pools.redis_cache().unwrap(), +// ); +// let client = chirp_client::SharedClient::from_env(pools.clone()) +// .expect("create client") +// .wrap_new("api-module-test"); +// let conn = rivet_connection::Connection::new(client, pools, cache); +// let op_ctx = OperationContext::new( +// "api-module-test".to_string(), +// std::time::Duration::from_secs(60), +// conn, +// Uuid::new_v4(), +// Uuid::new_v4(), +// util::timestamp::now(), +// util::timestamp::now(), +// (), +// Vec::new(), +// ); + +// let (primary_region_id, _) = Self::setup_region(&op_ctx).await; +// let (_, module_version_id) = Self::setup_module(&op_ctx).await; +// let (game_id, _, namespace_id, _, mm_config_meta) = +// Self::setup_game(&op_ctx, primary_region_id, module_version_id).await; + +// Ctx { +// op_ctx, +// game_id, +// primary_region_id, +// namespace_id, +// mm_config_meta, +// } +// } + +// fn config(&self, bearer_token: &str) -> Configuration { +// Configuration { +// base_path: "http://traefik.traefik.svc.cluster.local:80".into(), +// bearer_access_token: Some(bearer_token.to_string()), +// ..Default::default() +// } +// } + +// async fn issue_ns_token(&self) -> String { +// let token_res = op!([self.op_ctx] cloud_namespace_token_public_create { +// namespace_id: Some(self.namespace_id.into()), +// }) +// .await +// .unwrap(); + +// token_res.token +// } + +// async fn issue_lobby_token(&self) -> String { +// // Create lobby +// let lobby_group_meta = &self.mm_config_meta.lobby_groups[0]; +// let lobby_id = Uuid::new_v4(); + +// msg!([self.op_ctx] mm::msg::lobby_create(lobby_id) -> mm::msg::lobby_create_complete { +// lobby_id: Some(lobby_id.into()), +// namespace_id: Some(self.namespace_id.into()), +// lobby_group_id: lobby_group_meta.lobby_group_id, +// region_id: Some(self.primary_region_id.into()), +// create_ray_id: None, +// preemptively_created: false, +// ..Default::default() +// }) +// .await +// .unwrap(); + +// lobby_token(&self.op_ctx, lobby_id.to_string().as_str()).await +// } + +// async fn issue_cloud_token(&self) -> String { +// let res = op!([self.op_ctx] cloud_game_token_create { +// game_id: Some(self.game_id.into()), +// }) +// .await +// .unwrap(); + +// res.token +// } + +// async fn setup_region(ctx: &OperationContext<()>) -> (Uuid, String) { +// tracing::info!("setup region"); + +// let region_res = op!([ctx] faker_region {}).await.unwrap(); +// let region_id = region_res.region_id.as_ref().unwrap().as_uuid(); + +// let get_res = op!([ctx] region_get { +// region_ids: vec![region_id.into()], +// }) +// .await +// .unwrap(); +// let region_data = get_res.regions.first().unwrap(); + +// (region_id, region_data.name_id.clone()) +// } + +// async fn setup_module(ctx: &OperationContext<()>) -> (Uuid, Uuid) { +// let module_id = Uuid::new_v4(); +// let version_id = Uuid::new_v4(); + +// msg!([ctx] module::msg::create(module_id) -> module::msg::create_complete { +// module_id: Some(module_id.into()), +// name_id: "test".into(), +// team_id: Some(Uuid::new_v4().into()), +// creator_user_id: None, +// }) +// .await +// .unwrap(); + +// msg!([ctx] module::msg::version_create(version_id) -> module::msg::version_create_complete { +// version_id: Some(version_id.into()), +// module_id: Some(module_id.into()), +// creator_user_id: None, + +// major: 1, +// minor: 0, +// patch: 0, + +// scripts: vec![ +// backend::module::Script { +// name: "foo".into(), +// request_schema: "{}".into(), +// response_schema: "{}".into(), +// callable: Some(backend::module::script::Callable {}), +// }, +// ], + +// image: Some(module::msg::version_create::message::Image::Docker(module::msg::version_create::message::Docker { +// image_tag: "ghcr.io/rivet-gg/rivet-module-hello-world:0.0.1".into(), +// })), +// }).await.unwrap(); + +// (module_id, version_id) +// } + +// async fn setup_game( +// ctx: &OperationContext<()>, +// region_id: Uuid, +// module_version_id: Uuid, +// ) -> ( +// Uuid, +// Uuid, +// Uuid, +// backend::matchmaker::VersionConfig, +// backend::matchmaker::VersionConfigMeta, +// ) { +// let game_res = op!([ctx] faker_game { +// ..Default::default() +// }) +// .await +// .unwrap(); + +// let build_res = op!([ctx] faker_build { +// game_id: game_res.game_id, +// image: backend::faker::Image::MmLobbyAutoReady as i32, +// }) +// .await +// .unwrap(); + +// let game_version_res = op!([ctx] faker_game_version { +// game_id: game_res.game_id, +// override_cdn_config: Some(faker::game_version::request::OverrideCdnConfig { +// config: None, +// }), +// override_module_config: Some(faker::game_version::request::OverrideModuleConfig { +// config: Some(backend::module::GameVersionConfig { +// dependencies: vec![ +// backend::module::game_version_config::Dependency { +// key: "hello-world".into(), +// module_version_id: Some(module_version_id.into()), +// } +// ] +// }) +// }), +// override_lobby_groups: Some(faker::game_version::request::OverrideLobbyGroups { +// lobby_groups: vec![backend::matchmaker::LobbyGroup { +// name_id: LOBBY_GROUP_NAME_ID.into(), + +// regions: vec![backend::matchmaker::lobby_group::Region { +// region_id: Some(region_id.into()), +// tier_name_id: util_mm::test::TIER_NAME_ID.to_owned(), +// idle_lobbies: None, +// }], +// max_players_normal: 8, +// max_players_direct: 10, +// max_players_party: 12, + +// runtime: Some(backend::matchmaker::lobby_runtime::Docker { +// build_id: build_res.build_id, +// args: Vec::new(), +// env_vars: Vec::new(), +// network_mode: backend::matchmaker::lobby_runtime::NetworkMode::Bridge as i32, +// ports: vec![ +// backend::matchmaker::lobby_runtime::Port { +// label: "test-80-http".into(), +// target_port: Some(80), +// port_range: None, +// proxy_protocol: backend::matchmaker::lobby_runtime::ProxyProtocol::Http as i32, +// proxy_kind: backend::matchmaker::lobby_runtime::ProxyKind::GameGuard as i32, +// }, +// backend::matchmaker::lobby_runtime::Port { +// label: "test-80-https".into(), +// target_port: Some(80), +// port_range: None, +// proxy_protocol: backend::matchmaker::lobby_runtime::ProxyProtocol::Https as i32, +// proxy_kind: backend::matchmaker::lobby_runtime::ProxyKind::GameGuard as i32, +// }, +// backend::matchmaker::lobby_runtime::Port { +// label: "test-5050-https".into(), +// target_port: Some(5050), +// port_range: None, +// proxy_protocol: backend::matchmaker::lobby_runtime::ProxyProtocol::Https as i32, +// proxy_kind: backend::matchmaker::lobby_runtime::ProxyKind::GameGuard as i32, +// }, +// ], +// }.into()), +// ..Default::default() +// }], +// }), +// ..Default::default() +// }) +// .await +// .unwrap(); + +// let mut module_ns_version_set_complete = +// subscribe!([ctx] module::msg::ns_version_set_complete("*")) +// .await +// .unwrap(); +// let namespace_res = op!([ctx] faker_game_namespace { +// game_id: game_res.game_id, +// version_id: game_version_res.version_id, +// ..Default::default() +// }) +// .await +// .unwrap(); +// module_ns_version_set_complete.next().await.unwrap(); + +// ( +// game_res.game_id.as_ref().unwrap().as_uuid(), +// game_version_res.version_id.as_ref().unwrap().as_uuid(), +// namespace_res.namespace_id.as_ref().unwrap().as_uuid(), +// game_version_res.mm_config.clone().unwrap(), +// game_version_res.mm_config_meta.clone().unwrap(), +// ) +// } +// } + +// #[tokio::test(flavor = "multi_thread")] +// async fn call() { +// let ctx = Ctx::init().await; +// let token = ctx.issue_ns_token().await; + +// let res = module_api::module_call( +// &ctx.config(&token), +// "hello-world", +// "foo", +// models::ModuleCallRequest { +// namespace_id: None, +// data: Some(json!({ +// "x": 5 +// })), +// }, +// None, +// ) +// .await +// .unwrap(); +// assert_eq!( +// 10, +// res.data +// .unwrap() +// .as_object() +// .unwrap() +// .get("y") +// .unwrap() +// .as_i64() +// .unwrap() +// ); +// } + +// /// Issues a testing lobby token. We use this since we can't access the lobby token issued +// /// on the lobby creation. +// async fn lobby_token(ctx: &OperationContext<()>, lobby_id: &str) -> String { +// let token_res = op!([ctx] token_create { +// issuer: "test".into(), +// token_config: Some(token::create::request::TokenConfig { +// ttl: util::duration::days(365), +// }), +// refresh_token_config: None, +// client: None, +// kind: Some(token::create::request::Kind::New(token::create::request::KindNew { +// entitlements: vec![ +// proto::claims::Entitlement { +// kind: Some( +// proto::claims::entitlement::Kind::MatchmakerLobby(proto::claims::entitlement::MatchmakerLobby { +// lobby_id: Some(Uuid::from_str(lobby_id).unwrap().into()), +// }) +// ) +// } +// ], +// })), +// label: Some("lobby".into()), +// ..Default::default() +// }) +// .await +// .unwrap(); + +// token_res.token.as_ref().unwrap().token.clone() +// } diff --git a/svc/api/route/tests/basic.rs b/svc/api/route/tests/basic.rs index ab9753a108..acc31d04f7 100644 --- a/svc/api/route/tests/basic.rs +++ b/svc/api/route/tests/basic.rs @@ -244,7 +244,7 @@ async fn job_run() { let res = reqwest::Client::new() .get(&format!( - "{API_ROUTE_URL}/traefik/config/core?region={region}&token={token}", + "{API_ROUTE_URL}/traefik/config/game-guard?region={region}&token={token}", region = region.name_id, token = get_api_route_token().await )) diff --git a/svc/api/status/tests/basic.rs b/svc/api/status/tests/basic.rs index 2693ee0a47..f9d9f5867f 100644 --- a/svc/api/status/tests/basic.rs +++ b/svc/api/status/tests/basic.rs @@ -1,81 +1,83 @@ -use std::sync::Once; +// TODO: Rewrite with new api clients -use rivet_operation::prelude::*; +// use std::sync::Once; -static GLOBAL_INIT: Once = Once::new(); +// use rivet_operation::prelude::*; -struct Ctx { - op_ctx: OperationContext<()>, - http_client: rivet_status::ClientWrapper, -} +// static GLOBAL_INIT: Once = Once::new(); -impl Ctx { - async fn init() -> Ctx { - GLOBAL_INIT.call_once(|| { - tracing_subscriber::fmt() - .pretty() - .with_max_level(tracing::Level::INFO) - .with_target(false) - .init(); - }); +// struct Ctx { +// op_ctx: OperationContext<()>, +// http_client: rivet_status::ClientWrapper, +// } - let pools = rivet_pools::from_env("api-status-test").await.unwrap(); - let cache = rivet_cache::CacheInner::new( - "api-status-test".to_string(), - std::env::var("RIVET_SOURCE_HASH").unwrap(), - pools.redis_cache().unwrap(), - ); - let client = chirp_client::SharedClient::from_env(pools.clone()) - .expect("create client") - .wrap_new("api-status-test"); - let conn = rivet_connection::Connection::new(client, pools, cache); - let op_ctx = OperationContext::new( - "api-status-test".to_string(), - std::time::Duration::from_secs(60), - conn, - Uuid::new_v4(), - Uuid::new_v4(), - util::timestamp::now(), - util::timestamp::now(), - (), - Vec::new(), - ); +// impl Ctx { +// async fn init() -> Ctx { +// GLOBAL_INIT.call_once(|| { +// tracing_subscriber::fmt() +// .pretty() +// .with_max_level(tracing::Level::INFO) +// .with_target(false) +// .init(); +// }); - let http_client = rivet_status::Config::builder() - .set_uri("http://traefik.traefik.svc.cluster.local:80/status") - .set_bearer_token( - util::env::read_secret(&["rivet", "api_status", "token"]) - .await - .unwrap(), - ) - .build_client(); +// let pools = rivet_pools::from_env("api-status-test").await.unwrap(); +// let cache = rivet_cache::CacheInner::new( +// "api-status-test".to_string(), +// std::env::var("RIVET_SOURCE_HASH").unwrap(), +// pools.redis_cache().unwrap(), +// ); +// let client = chirp_client::SharedClient::from_env(pools.clone()) +// .expect("create client") +// .wrap_new("api-status-test"); +// let conn = rivet_connection::Connection::new(client, pools, cache); +// let op_ctx = OperationContext::new( +// "api-status-test".to_string(), +// std::time::Duration::from_secs(60), +// conn, +// Uuid::new_v4(), +// Uuid::new_v4(), +// util::timestamp::now(), +// util::timestamp::now(), +// (), +// Vec::new(), +// ); - Ctx { - op_ctx, - http_client, - } - } +// let http_client = rivet_status::Config::builder() +// .set_uri("http://traefik.traefik.svc.cluster.local:80/status") +// .set_bearer_token( +// util::env::read_secret(&["rivet", "api_status", "token"]) +// .await +// .unwrap(), +// ) +// .build_client(); - fn chirp(&self) -> &chirp_client::Client { - self.op_ctx.chirp() - } +// Ctx { +// op_ctx, +// http_client, +// } +// } - fn op_ctx(&self) -> &OperationContext<()> { - &self.op_ctx - } -} +// fn chirp(&self) -> &chirp_client::Client { +// self.op_ctx.chirp() +// } -#[tokio::test(flavor = "multi_thread")] -async fn matchmaker_find() { - let ctx = Ctx::init().await; +// fn op_ctx(&self) -> &OperationContext<()> { +// &self.op_ctx +// } +// } - let region_res = op!([ctx] faker_region {}).await.unwrap(); - let region = region_res.region.unwrap(); +// #[tokio::test(flavor = "multi_thread")] +// async fn matchmaker_find() { +// let ctx = Ctx::init().await; - ctx.http_client - .matchmaker() - .region(®ion.name_id) - .send() - .await - .unwrap(); -} +// let region_res = op!([ctx] faker_region {}).await.unwrap(); +// let region = region_res.region.unwrap(); + +// ctx.http_client +// .matchmaker() +// .region(®ion.name_id) +// .send() +// .await +// .unwrap(); +// }