forge
ExploreLog in

Tahinli/forge

public
0 watching
★ 0
3.9 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 }
55}
56
57/// Opens (and migrates) the store at `dir/forge.db` and builds the shared state around it.
58pub async fn test_state(dir: &Path) -> AppState {
59 let store = Store::open(&dir.join("forge.db")).await.unwrap();
60 store.set_secret_key(KEY);
61 AppState {
62 config: Arc::new(test_config(dir)),
63 store,
64 git: Arc::new(GitEnv {
65 git_bin: "git".into(),
66 data_dir: dir.to_path_buf(),
67 }),
68 key: Arc::new(KEY),
69 internal_token: Arc::from(INTERNAL_TOKEN),
70 admin_token: Arc::from(ADMIN_TOKEN),
71 jobs: Arc::new(crate::backup::Jobs::default()),
72 internal_socket: dir.join("internal.sock"),
73 throttle: Arc::new(Throttle::default()),
74 webhook_waker: Arc::new(Notify::new()),
75 mirror_waker: Arc::new(Notify::new()),
76 blobs: crate::blobs::BlobStore::open(&dir.join("blobs")).expect("blob store"),
77 replication: Arc::new(crate::replication::ReplicationQueue::default()),
78 ci_waker: Arc::new(Notify::new()),
79 mailer: Arc::new(crate::mail::FakeMailer::default()),
80 mail_waker: Arc::new(Notify::new()),
81 }
82}
83
84/// The public router as boot.rs builds it, minus the listeners.
85pub fn app_router(state: AppState) -> Router {
86 Router::builder()
87 .discover()
88 .app_context(state)
89 .cookies()
90 .layer(avatar_body_limit())
91 .layer(RepoMovedLayer)
92 .layer(TowerLayer::new(crate::compression::ResponseCompression))
93 .compression(Compression::off())
94 .build()
95}
96
97/// Creates a session for `user_id` that expires in an hour and has no user agent.
98pub async fn create_session(store: &Store, user_id: &str, token: &str, csrf: &str) {
99 store
100 .create_session(
101 user_id,
102 &hash_token(token),
103 csrf,
104 &stamp_after(Duration::from_secs(3600)),
105 None,
106 )
107 .await
108 .expect("session");
109}