forge
ExploreLog in

Tahinli/forge

public
0 watching
★ 0
4.1 KiB
1//! Shared fixtures for the in-crate router and state tests. Compiled only under `cfg(test)`.
2//!
3//! Every test that needs a `Config`, an `AppState` or a router builds them here, so a new config
4//! or state field is added in one place.
5
6use std::path::Path;
7use std::sync::Arc;
8use std::time::Duration;
9
10use forge_core::time::stamp_after;
11use forge_core::token::hash_token;
12use forge_core::{Config, Registration, Store};
13use forge_git::GitEnv;
14use tokio::sync::Notify;
15use topcoat::cookie::RouterBuilderCookieExt;
16use topcoat::router::tower::TowerLayer;
17use topcoat::router::{Compression, Router, RouterBuilderDiscoverExt};
18
19use crate::pages::repo_ctx::RepoMovedLayer;
20use crate::pages::settings_profile::avatar_body_limit;
21use crate::state::AppState;
22use crate::throttle::Throttle;
23
24/// Fixed instance key shared by every test state.
25pub const KEY: [u8; 32] = [7u8; 32];
26/// Fixed internal API token shared by every test state.
27pub const INTERNAL_TOKEN: &str = "test-token";
28/// Fixed admin token shared by every test state.
29pub const ADMIN_TOKEN: &str = "test-admin-token";
30
31/// The canonical test configuration. Data lives under `dir`, the database at `dir/forge.db`.
32pub fn test_config(dir: &Path) -> Config {
33 Config {
34 database: dir.join("forge.db"),
35 data_dir: dir.to_path_buf(),
36 listen: "127.0.0.1:7660".parse().unwrap(),
37 base_url: "https://forge.test/".into(),
38 user_content_base_url: "https://forge.test".into(),
39 ssh_listen: "127.0.0.1:2222".parse().unwrap(),
40 user_content_listen: "127.0.0.1:7661".parse().unwrap(),
41 ssh_public_host: "forge.test".into(),
42 ssh_public_port: 22,
43 registration: Registration::Closed,
44 trusted_proxies: Vec::new(),
45 webhooks: Default::default(),
46 backup: Default::default(),
47 releases: Default::default(),
48 replication: Default::default(),
49 lfs: Default::default(),
50 ci: Default::default(),
51 advisories: Default::default(),
52 mail: Default::default(),
53 orgs: Default::default(),
54 self_update: Default::default(),
55 }
56}
57
58/// Opens (and migrates) the store at `dir/forge.db` and builds the shared state around it.
59pub async fn test_state(dir: &Path) -> AppState {
60 let store = Store::open(&dir.join("forge.db")).await.unwrap();
61 store.set_secret_key(KEY);
62 AppState {
63 config: Arc::new(test_config(dir)),
64 store,
65 git: Arc::new(GitEnv {
66 git_bin: "git".into(),
67 data_dir: dir.to_path_buf(),
68 }),
69 key: Arc::new(KEY),
70 internal_token: Arc::from(INTERNAL_TOKEN),
71 admin_token: Arc::from(ADMIN_TOKEN),
72 jobs: Arc::new(crate::backup::Jobs::default()),
73 internal_socket: dir.join("internal.sock"),
74 throttle: Arc::new(Throttle::default()),
75 webhook_waker: Arc::new(Notify::new()),
76 mirror_waker: Arc::new(Notify::new()),
77 blobs: crate::blobs::BlobStore::open(&dir.join("blobs")).expect("blob store"),
78 replication: Arc::new(crate::replication::ReplicationQueue::default()),
79 ci_waker: Arc::new(Notify::new()),
80 mailer: Arc::new(crate::mail::FakeMailer::default()),
81 mail_waker: Arc::new(Notify::new()),
82 notify_hub: Arc::new(crate::notify_hub::NotifyHub::new()),
83 ci_live: Arc::new(crate::ci::CiLive::default()),
84 }
85}
86
87/// The public router as boot.rs builds it, minus the listeners.
88pub fn app_router(state: AppState) -> Router {
89 Router::builder()
90 .discover()
91 .app_context(state)
92 .cookies()
93 .layer(avatar_body_limit())
94 .layer(RepoMovedLayer)
95 .layer(TowerLayer::new(crate::compression::ResponseCompression))
96 .compression(Compression::off())
97 .build()
98}
99
100/// Creates a session for `user_id` that expires in an hour and has no user agent.
101pub async fn create_session(store: &Store, user_id: &str, token: &str, csrf: &str) {
102 store
103 .create_session(
104 user_id,
105 &hash_token(token),
106 csrf,
107 &stamp_after(Duration::from_secs(3600)),
108 None,
109 )
110 .await
111 .expect("session");
112}