@@ -24,6 +24,7 @@ use tracing::instrument;
pub fn routes(rpc_server: &Arc<rpc::Server>, state: Arc<AppState>) -> Router<Body> {
Router::new()
+ .route("/user", get(get_authenticated_user))
.route("/users", get(get_users).post(create_user))
.route("/users/:id", put(update_user).delete(destroy_user))
.route("/users/:id/access_tokens", post(create_access_token))
@@ -85,10 +86,33 @@ pub async fn validate_api_token<B>(req: Request<B>, next: Next<B>) -> impl IntoR
Ok::<_, Error>(next.run(req).await)
}
+#[derive(Debug, Deserialize)]
+struct AuthenticatedUserParams {
+ github_user_id: i32,
+ github_login: String,
+}
+
+#[derive(Debug, Serialize)]
+struct AuthenticatedUserResponse {
+ user: User,
+ metrics_id: String,
+}
+
+async fn get_authenticated_user(
+ Query(params): Query<AuthenticatedUserParams>,
+ Extension(app): Extension<Arc<AppState>>,
+) -> Result<Json<AuthenticatedUserResponse>> {
+ let user = app
+ .db
+ .get_user_by_github_account(¶ms.github_login, Some(params.github_user_id))
+ .await?
+ .ok_or_else(|| Error::Http(StatusCode::NOT_FOUND, "user not found".into()))?;
+ let metrics_id = app.db.get_user_metrics_id(user.id).await?;
+ return Ok(Json(AuthenticatedUserResponse { user, metrics_id }));
+}
+
#[derive(Debug, Deserialize)]
struct GetUsersQueryParams {
- github_user_id: Option<i32>,
- github_login: Option<String>,
query: Option<String>,
page: Option<u32>,
limit: Option<u32>,
@@ -98,14 +122,6 @@ async fn get_users(
Query(params): Query<GetUsersQueryParams>,
Extension(app): Extension<Arc<AppState>>,
) -> Result<Json<Vec<User>>> {
- if let Some(github_login) = ¶ms.github_login {
- let user = app
- .db
- .get_user_by_github_account(github_login, params.github_user_id)
- .await?;
- return Ok(Json(Vec::from_iter(user)));
- }
-
let limit = params.limit.unwrap_or(100);
let users = if let Some(query) = params.query {
app.db.fuzzy_search_users(&query, limit).await?
@@ -124,6 +140,8 @@ struct CreateUserParams {
email_address: String,
email_confirmation_code: Option<String>,
#[serde(default)]
+ admin: bool,
+ #[serde(default)]
invite_count: i32,
}
@@ -131,6 +149,7 @@ struct CreateUserParams {
struct CreateUserResponse {
user: User,
signup_device_id: Option<String>,
+ metrics_id: String,
}
async fn create_user(
@@ -143,12 +162,10 @@ async fn create_user(
github_user_id: params.github_user_id,
invite_count: params.invite_count,
};
- let user_id;
- let signup_device_id;
+
// Creating a user via the normal signup process
- if let Some(email_confirmation_code) = params.email_confirmation_code {
- let result = app
- .db
+ let result = if let Some(email_confirmation_code) = params.email_confirmation_code {
+ app.db
.create_user_from_invite(
&Invite {
email_address: params.email_address,
@@ -156,34 +173,37 @@ async fn create_user(
},
user,
)
- .await?;
- user_id = result.user_id;
- signup_device_id = result.signup_device_id;
- if let Some(inviter_id) = result.inviting_user_id {
- rpc_server
- .invite_code_redeemed(inviter_id, user_id)
- .await
- .trace_err();
- }
+ .await?
}
// Creating a user as an admin
- else {
- user_id = app
- .db
+ else if params.admin {
+ app.db
.create_user(¶ms.email_address, false, user)
- .await?;
- signup_device_id = None;
+ .await?
+ } else {
+ Err(Error::Http(
+ StatusCode::UNPROCESSABLE_ENTITY,
+ "email confirmation code is required".into(),
+ ))?
+ };
+
+ if let Some(inviter_id) = result.inviting_user_id {
+ rpc_server
+ .invite_code_redeemed(inviter_id, result.user_id)
+ .await
+ .trace_err();
}
let user = app
.db
- .get_user_by_id(user_id)
+ .get_user_by_id(result.user_id)
.await?
.ok_or_else(|| anyhow!("couldn't find the user we just created"))?;
Ok(Json(CreateUserResponse {
user,
- signup_device_id,
+ metrics_id: result.metrics_id,
+ signup_device_id: result.signup_device_id,
}))
}
@@ -17,10 +17,11 @@ pub trait Db: Send + Sync {
email_address: &str,
admin: bool,
params: NewUserParams,
- ) -> Result<UserId>;
+ ) -> Result<NewUserResult>;
async fn get_all_users(&self, page: u32, limit: u32) -> Result<Vec<User>>;
async fn fuzzy_search_users(&self, query: &str, limit: u32) -> Result<Vec<User>>;
async fn get_user_by_id(&self, id: UserId) -> Result<Option<User>>;
+ async fn get_user_metrics_id(&self, id: UserId) -> Result<String>;
async fn get_users_by_ids(&self, ids: Vec<UserId>) -> Result<Vec<User>>;
async fn get_users_with_no_invites(&self, invited_by_another_user: bool) -> Result<Vec<User>>;
async fn get_user_by_github_account(
@@ -208,21 +209,26 @@ impl Db for PostgresDb {
email_address: &str,
admin: bool,
params: NewUserParams,
- ) -> Result<UserId> {
+ ) -> Result<NewUserResult> {
let query = "
INSERT INTO users (email_address, github_login, github_user_id, admin)
VALUES ($1, $2, $3, $4)
ON CONFLICT (github_login) DO UPDATE SET github_login = excluded.github_login
- RETURNING id
+ RETURNING id, metrics_id::text
";
- Ok(sqlx::query_scalar(query)
+ let (user_id, metrics_id): (UserId, String) = sqlx::query_as(query)
.bind(email_address)
.bind(params.github_login)
.bind(params.github_user_id)
.bind(admin)
.fetch_one(&self.pool)
- .await
- .map(UserId)?)
+ .await?;
+ Ok(NewUserResult {
+ user_id,
+ metrics_id,
+ signup_device_id: None,
+ inviting_user_id: None,
+ })
}
async fn get_all_users(&self, page: u32, limit: u32) -> Result<Vec<User>> {
@@ -256,6 +262,18 @@ impl Db for PostgresDb {
Ok(users.into_iter().next())
}
+ async fn get_user_metrics_id(&self, id: UserId) -> Result<String> {
+ let query = "
+ SELECT metrics_id::text
+ FROM users
+ WHERE id = $1
+ ";
+ Ok(sqlx::query_scalar(query)
+ .bind(id)
+ .fetch_one(&self.pool)
+ .await?)
+ }
+
async fn get_users_by_ids(&self, ids: Vec<UserId>) -> Result<Vec<User>> {
let ids = ids.into_iter().map(|id| id.0).collect::<Vec<_>>();
let query = "
@@ -493,13 +511,13 @@ impl Db for PostgresDb {
))?;
}
- let user_id: UserId = sqlx::query_scalar(
+ let (user_id, metrics_id): (UserId, String) = sqlx::query_as(
"
INSERT INTO users
(email_address, github_login, github_user_id, admin, invite_count, invite_code)
VALUES
($1, $2, $3, 'f', $4, $5)
- RETURNING id
+ RETURNING id, metrics_id::text
",
)
.bind(&invite.email_address)
@@ -559,6 +577,7 @@ impl Db for PostgresDb {
tx.commit().await?;
Ok(NewUserResult {
user_id,
+ metrics_id,
inviting_user_id,
signup_device_id,
})
@@ -1722,6 +1741,7 @@ pub struct NewUserParams {
#[derive(Debug)]
pub struct NewUserResult {
pub user_id: UserId,
+ pub metrics_id: String,
pub inviting_user_id: Option<UserId>,
pub signup_device_id: Option<String>,
}
@@ -1808,15 +1828,15 @@ mod test {
email_address: &str,
admin: bool,
params: NewUserParams,
- ) -> Result<UserId> {
+ ) -> Result<NewUserResult> {
self.background.simulate_random_delay().await;
let mut users = self.users.lock();
- if let Some(user) = users
+ let user_id = if let Some(user) = users
.values()
.find(|user| user.github_login == params.github_login)
{
- Ok(user.id)
+ user.id
} else {
let id = post_inc(&mut *self.next_user_id.lock());
let user_id = UserId(id);
@@ -1833,8 +1853,14 @@ mod test {
connected_once: false,
},
);
- Ok(user_id)
- }
+ user_id
+ };
+ Ok(NewUserResult {
+ user_id,
+ metrics_id: "the-metrics-id".to_string(),
+ inviting_user_id: None,
+ signup_device_id: None,
+ })
}
async fn get_all_users(&self, _page: u32, _limit: u32) -> Result<Vec<User>> {
@@ -1850,6 +1876,10 @@ mod test {
Ok(self.get_users_by_ids(vec![id]).await?.into_iter().next())
}
+ async fn get_user_metrics_id(&self, _id: UserId) -> Result<String> {
+ Ok("the-metrics-id".to_string())
+ }
+
async fn get_users_by_ids(&self, ids: Vec<UserId>) -> Result<Vec<User>> {
self.background.simulate_random_delay().await;
let users = self.users.lock();
@@ -12,89 +12,56 @@ async fn test_get_users_by_ids() {
] {
let db = test_db.db();
- let user1 = db
- .create_user(
- "u1@example.com",
- false,
- NewUserParams {
- github_login: "u1".into(),
- github_user_id: 1,
- invite_count: 0,
- },
- )
- .await
- .unwrap();
- let user2 = db
- .create_user(
- "u2@example.com",
- false,
- NewUserParams {
- github_login: "u2".into(),
- github_user_id: 2,
- invite_count: 0,
- },
- )
- .await
- .unwrap();
- let user3 = db
- .create_user(
- "u3@example.com",
- false,
- NewUserParams {
- github_login: "u3".into(),
- github_user_id: 3,
- invite_count: 0,
- },
- )
- .await
- .unwrap();
- let user4 = db
- .create_user(
- "u4@example.com",
- false,
- NewUserParams {
- github_login: "u4".into(),
- github_user_id: 4,
- invite_count: 0,
- },
- )
- .await
- .unwrap();
+ let mut user_ids = Vec::new();
+ for i in 1..=4 {
+ user_ids.push(
+ db.create_user(
+ &format!("user{i}@example.com"),
+ false,
+ NewUserParams {
+ github_login: format!("user{i}"),
+ github_user_id: i,
+ invite_count: 0,
+ },
+ )
+ .await
+ .unwrap()
+ .user_id,
+ );
+ }
assert_eq!(
- db.get_users_by_ids(vec![user1, user2, user3, user4])
- .await
- .unwrap(),
+ db.get_users_by_ids(user_ids.clone()).await.unwrap(),
vec![
User {
- id: user1,
- github_login: "u1".to_string(),
+ id: user_ids[0],
+ github_login: "user1".to_string(),
github_user_id: Some(1),
- email_address: Some("u1@example.com".to_string()),
+ email_address: Some("user1@example.com".to_string()),
admin: false,
..Default::default()
},
User {
- id: user2,
- github_login: "u2".to_string(),
+ id: user_ids[1],
+ github_login: "user2".to_string(),
github_user_id: Some(2),
- email_address: Some("u2@example.com".to_string()),
+ email_address: Some("user2@example.com".to_string()),
admin: false,
..Default::default()
},
User {
- id: user3,
- github_login: "u3".to_string(),
+ id: user_ids[2],
+ github_login: "user3".to_string(),
github_user_id: Some(3),
- email_address: Some("u3@example.com".to_string()),
+ email_address: Some("user3@example.com".to_string()),
admin: false,
..Default::default()
},
User {
- id: user4,
- github_login: "u4".to_string(),
+ id: user_ids[3],
+ github_login: "user4".to_string(),
github_user_id: Some(4),
- email_address: Some("u4@example.com".to_string()),
+ email_address: Some("user4@example.com".to_string()),
admin: false,
..Default::default()
}
@@ -121,7 +88,8 @@ async fn test_get_user_by_github_account() {
},
)
.await
- .unwrap();
+ .unwrap()
+ .user_id;
let user_id2 = db
.create_user(
"user2@example.com",
@@ -133,7 +101,8 @@ async fn test_get_user_by_github_account() {
},
)
.await
- .unwrap();
+ .unwrap()
+ .user_id;
let user = db
.get_user_by_github_account("login1", None)
@@ -177,7 +146,8 @@ async fn test_worktree_extensions() {
},
)
.await
- .unwrap();
+ .unwrap()
+ .user_id;
let project = db.register_project(user).await.unwrap();
db.update_worktree_extensions(project, 100, Default::default())
@@ -237,43 +207,25 @@ async fn test_user_activity() {
let test_db = TestDb::postgres().await;
let db = test_db.db();
- let user_1 = db
- .create_user(
- "u1@example.com",
- false,
- NewUserParams {
- github_login: "u1".into(),
- github_user_id: 0,
- invite_count: 0,
- },
- )
- .await
- .unwrap();
- let user_2 = db
- .create_user(
- "u2@example.com",
- false,
- NewUserParams {
- github_login: "u2".into(),
- github_user_id: 0,
- invite_count: 0,
- },
- )
- .await
- .unwrap();
- let user_3 = db
- .create_user(
- "u3@example.com",
- false,
- NewUserParams {
- github_login: "u3".into(),
- github_user_id: 0,
- invite_count: 0,
- },
- )
- .await
- .unwrap();
- let project_1 = db.register_project(user_1).await.unwrap();
+ let mut user_ids = Vec::new();
+ for i in 0..=2 {
+ user_ids.push(
+ db.create_user(
+ &format!("user{i}@example.com"),
+ false,
+ NewUserParams {
+ github_login: format!("user{i}"),
+ github_user_id: i,
+ invite_count: 0,
+ },
+ )
+ .await
+ .unwrap()
+ .user_id,
+ );
+ }
+
+ let project_1 = db.register_project(user_ids[0]).await.unwrap();
db.update_worktree_extensions(
project_1,
1,
@@ -281,34 +233,37 @@ async fn test_user_activity() {
)
.await
.unwrap();
- let project_2 = db.register_project(user_2).await.unwrap();
+ let project_2 = db.register_project(user_ids[1]).await.unwrap();
let t0 = OffsetDateTime::now_utc() - Duration::from_secs(60 * 60);
// User 2 opens a project
let t1 = t0 + Duration::from_secs(10);
- db.record_user_activity(t0..t1, &[(user_2, project_2)])
+ db.record_user_activity(t0..t1, &[(user_ids[1], project_2)])
.await
.unwrap();
let t2 = t1 + Duration::from_secs(10);
- db.record_user_activity(t1..t2, &[(user_2, project_2)])
+ db.record_user_activity(t1..t2, &[(user_ids[1], project_2)])
.await
.unwrap();
// User 1 joins the project
let t3 = t2 + Duration::from_secs(10);
- db.record_user_activity(t2..t3, &[(user_2, project_2), (user_1, project_2)])
- .await
- .unwrap();
+ db.record_user_activity(
+ t2..t3,
+ &[(user_ids[1], project_2), (user_ids[0], project_2)],
+ )
+ .await
+ .unwrap();
// User 1 opens another project
let t4 = t3 + Duration::from_secs(10);
db.record_user_activity(
t3..t4,
&[
- (user_2, project_2),
- (user_1, project_2),
- (user_1, project_1),
+ (user_ids[1], project_2),
+ (user_ids[0], project_2),
+ (user_ids[0], project_1),
],
)
.await
@@ -319,10 +274,10 @@ async fn test_user_activity() {
db.record_user_activity(
t4..t5,
&[
- (user_2, project_2),
- (user_1, project_2),
- (user_1, project_1),
- (user_3, project_1),
+ (user_ids[1], project_2),
+ (user_ids[0], project_2),
+ (user_ids[0], project_1),
+ (user_ids[2], project_1),
],
)
.await
@@ -330,13 +285,16 @@ async fn test_user_activity() {
// User 2 leaves
let t6 = t5 + Duration::from_secs(5);
- db.record_user_activity(t5..t6, &[(user_1, project_1), (user_3, project_1)])
- .await
- .unwrap();
+ db.record_user_activity(
+ t5..t6,
+ &[(user_ids[0], project_1), (user_ids[2], project_1)],
+ )
+ .await
+ .unwrap();
let t7 = t6 + Duration::from_secs(60);
let t8 = t7 + Duration::from_secs(10);
- db.record_user_activity(t7..t8, &[(user_1, project_1)])
+ db.record_user_activity(t7..t8, &[(user_ids[0], project_1)])
.await
.unwrap();
@@ -344,8 +302,8 @@ async fn test_user_activity() {
db.get_top_users_activity_summary(t0..t6, 10).await.unwrap(),
&[
UserActivitySummary {
- id: user_1,
- github_login: "u1".to_string(),
+ id: user_ids[0],
+ github_login: "user0".to_string(),
project_activity: vec![
ProjectActivitySummary {
id: project_1,
@@ -360,8 +318,8 @@ async fn test_user_activity() {
]
},
UserActivitySummary {
- id: user_2,
- github_login: "u2".to_string(),
+ id: user_ids[1],
+ github_login: "user1".to_string(),
project_activity: vec![ProjectActivitySummary {
id: project_2,
duration: Duration::from_secs(50),
@@ -369,8 +327,8 @@ async fn test_user_activity() {
}]
},
UserActivitySummary {
- id: user_3,
- github_login: "u3".to_string(),
+ id: user_ids[2],
+ github_login: "user2".to_string(),
project_activity: vec![ProjectActivitySummary {
id: project_1,
duration: Duration::from_secs(15),
@@ -442,7 +400,9 @@ async fn test_user_activity() {
);
assert_eq!(
- db.get_user_activity_timeline(t3..t6, user_1).await.unwrap(),
+ db.get_user_activity_timeline(t3..t6, user_ids[0])
+ .await
+ .unwrap(),
&[
UserActivityPeriod {
project_id: project_1,
@@ -459,7 +419,9 @@ async fn test_user_activity() {
]
);
assert_eq!(
- db.get_user_activity_timeline(t0..t8, user_1).await.unwrap(),
+ db.get_user_activity_timeline(t0..t8, user_ids[0])
+ .await
+ .unwrap(),
&[
UserActivityPeriod {
project_id: project_2,
@@ -501,7 +463,8 @@ async fn test_recent_channel_messages() {
},
)
.await
- .unwrap();
+ .unwrap()
+ .user_id;
let org = db.create_org("org", "org").await.unwrap();
let channel = db.create_org_channel(org, "channel").await.unwrap();
for i in 0..10 {
@@ -545,7 +508,8 @@ async fn test_channel_message_nonces() {
},
)
.await
- .unwrap();
+ .unwrap()
+ .user_id;
let org = db.create_org("org", "org").await.unwrap();
let channel = db.create_org_channel(org, "channel").await.unwrap();
@@ -587,7 +551,8 @@ async fn test_create_access_tokens() {
},
)
.await
- .unwrap();
+ .unwrap()
+ .user_id;
db.create_access_token_hash(user, "h1", 3).await.unwrap();
db.create_access_token_hash(user, "h2", 3).await.unwrap();
@@ -678,42 +643,27 @@ async fn test_add_contacts() {
] {
let db = test_db.db();
- let user_1 = db
- .create_user(
- "u1@example.com",
- false,
- NewUserParams {
- github_login: "u1".into(),
- github_user_id: 0,
- invite_count: 0,
- },
- )
- .await
- .unwrap();
- let user_2 = db
- .create_user(
- "u2@example.com",
- false,
- NewUserParams {
- github_login: "u2".into(),
- github_user_id: 1,
- invite_count: 0,
- },
- )
- .await
- .unwrap();
- let user_3 = db
- .create_user(
- "u3@example.com",
- false,
- NewUserParams {
- github_login: "u3".into(),
- github_user_id: 2,
- invite_count: 0,
- },
- )
- .await
- .unwrap();
+ let mut user_ids = Vec::new();
+ for i in 0..3 {
+ user_ids.push(
+ db.create_user(
+ &format!("user{i}@example.com"),
+ false,
+ NewUserParams {
+ github_login: format!("user{i}"),
+ github_user_id: i,
+ invite_count: 0,
+ },
+ )
+ .await
+ .unwrap()
+ .user_id,
+ );
+ }
+
+ let user_1 = user_ids[0];
+ let user_2 = user_ids[1];
+ let user_3 = user_ids[2];
// User starts with no contacts
assert_eq!(
@@ -927,12 +877,12 @@ async fn test_add_contacts() {
async fn test_invite_codes() {
let postgres = TestDb::postgres().await;
let db = postgres.db();
- let user1 = db
+ let NewUserResult { user_id: user1, .. } = db
.create_user(
- "u1@example.com",
+ "user1@example.com",
false,
NewUserParams {
- github_login: "u1".into(),
+ github_login: "user1".into(),
github_user_id: 0,
invite_count: 0,
},
@@ -954,13 +904,14 @@ async fn test_invite_codes() {
// User 2 redeems the invite code and becomes a contact of user 1.
let user2_invite = db
- .create_invite_from_code(&invite_code, "u2@example.com", Some("user-2-device-id"))
+ .create_invite_from_code(&invite_code, "user2@example.com", Some("user-2-device-id"))
.await
.unwrap();
let NewUserResult {
user_id: user2,
inviting_user_id,
signup_device_id,
+ metrics_id,
} = db
.create_user_from_invite(
&user2_invite,
@@ -976,6 +927,7 @@ async fn test_invite_codes() {
assert_eq!(invite_count, 1);
assert_eq!(inviting_user_id, Some(user1));
assert_eq!(signup_device_id.unwrap(), "user-2-device-id");
+ assert_eq!(db.get_user_metrics_id(user2).await.unwrap(), metrics_id);
assert_eq!(
db.get_contacts(user1).await.unwrap(),
[
@@ -1009,13 +961,14 @@ async fn test_invite_codes() {
// User 3 redeems the invite code and becomes a contact of user 1.
let user3_invite = db
- .create_invite_from_code(&invite_code, "u3@example.com", None)
+ .create_invite_from_code(&invite_code, "user3@example.com", None)
.await
.unwrap();
let NewUserResult {
user_id: user3,
inviting_user_id,
signup_device_id,
+ ..
} = db
.create_user_from_invite(
&user3_invite,
@@ -1067,7 +1020,7 @@ async fn test_invite_codes() {
);
// Trying to reedem the code for the third time results in an error.
- db.create_invite_from_code(&invite_code, "u4@example.com", Some("user-4-device-id"))
+ db.create_invite_from_code(&invite_code, "user4@example.com", Some("user-4-device-id"))
.await
.unwrap_err();
@@ -1079,7 +1032,7 @@ async fn test_invite_codes() {
// User 4 can now redeem the invite code and becomes a contact of user 1.
let user4_invite = db
- .create_invite_from_code(&invite_code, "u4@example.com", Some("user-4-device-id"))
+ .create_invite_from_code(&invite_code, "user4@example.com", Some("user-4-device-id"))
.await
.unwrap();
let user4 = db
@@ -1137,7 +1090,7 @@ async fn test_invite_codes() {
);
// An existing user cannot redeem invite codes.
- db.create_invite_from_code(&invite_code, "u2@example.com", Some("user-2-device-id"))
+ db.create_invite_from_code(&invite_code, "user2@example.com", Some("user-2-device-id"))
.await
.unwrap_err();
let (_, invite_count) = db.get_invite_code_for_user(user1).await.unwrap().unwrap();
@@ -1232,6 +1185,7 @@ async fn test_signups() {
user_id,
inviting_user_id,
signup_device_id,
+ ..
} = db
.create_user_from_invite(
&Invite {
@@ -1284,6 +1238,51 @@ async fn test_signups() {
.unwrap_err();
}
+#[tokio::test(flavor = "multi_thread")]
+async fn test_metrics_id() {
+ let postgres = TestDb::postgres().await;
+ let db = postgres.db();
+
+ let NewUserResult {
+ user_id: user1,
+ metrics_id: metrics_id1,
+ ..
+ } = db
+ .create_user(
+ "person1@example.com",
+ false,
+ NewUserParams {
+ github_login: "person1".into(),
+ github_user_id: 101,
+ invite_count: 5,
+ },
+ )
+ .await
+ .unwrap();
+ let NewUserResult {
+ user_id: user2,
+ metrics_id: metrics_id2,
+ ..
+ } = db
+ .create_user(
+ "person2@example.com",
+ false,
+ NewUserParams {
+ github_login: "person2".into(),
+ github_user_id: 102,
+ invite_count: 5,
+ },
+ )
+ .await
+ .unwrap();
+
+ assert_eq!(db.get_user_metrics_id(user1).await.unwrap(), metrics_id1);
+ assert_eq!(db.get_user_metrics_id(user2).await.unwrap(), metrics_id2);
+ assert_eq!(metrics_id1.len(), 36);
+ assert_eq!(metrics_id2.len(), 36);
+ assert_ne!(metrics_id1, metrics_id2);
+}
+
fn build_background_executor() -> Arc<Background> {
Deterministic::new(0).build_background()
}