Add test scaffolding
Signed-off-by: Olivier 'reivilibre <olivier@librepush.net>
This commit is contained in:
parent
ed9a36a662
commit
eb0a417c35
44
Cargo.lock
generated
44
Cargo.lock
generated
@ -613,6 +613,18 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.9.5"
|
||||
@ -872,6 +884,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.34"
|
||||
@ -1629,6 +1647,7 @@ dependencies = [
|
||||
"futures",
|
||||
"governor",
|
||||
"hornbeam",
|
||||
"insta",
|
||||
"josekit",
|
||||
"metrics",
|
||||
"metrics-exporter-prometheus",
|
||||
@ -1723,6 +1742,19 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "insta"
|
||||
version = "1.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "810ae6042d48e2c9e9215043563a58a80b877bc863228a74cf10c49d4620a6f5"
|
||||
dependencies = [
|
||||
"console",
|
||||
"lazy_static",
|
||||
"linked-hash-map",
|
||||
"serde",
|
||||
"similar",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
@ -1901,6 +1933,12 @@ dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.1.4"
|
||||
@ -3017,6 +3055,12 @@ dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "similar"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640"
|
||||
|
||||
[[package]]
|
||||
name = "sketches-ddsketch"
|
||||
version = "0.2.1"
|
||||
|
@ -42,5 +42,6 @@ tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
|
||||
|
||||
[dev-dependencies]
|
||||
axum-test-helper = "0.3.0"
|
||||
insta = { version = "1.39.0", features = ["serde", "yaml"] }
|
||||
pgtemp = "0.3.0"
|
||||
rstest = "0.21.0"
|
||||
|
@ -10,4 +10,4 @@
|
||||
|
||||
# Development
|
||||
|
||||
|
||||
- [Testing](dev/testing.md)
|
||||
|
45
docs/dev/testing.md
Normal file
45
docs/dev/testing.md
Normal file
@ -0,0 +1,45 @@
|
||||
# Testing
|
||||
|
||||
## Testing approach
|
||||
|
||||
### Unit tests
|
||||
|
||||
Unit tests should live inside a module in the code unit they are testing,
|
||||
gated behind `#[cfg(test)]`. \
|
||||
This is fairly common Rust practice.
|
||||
|
||||
There is no hard and fast rule for the granularity of the unit tests,
|
||||
but they should test the smallest amount of logic that is simple to test,
|
||||
but no smaller. \
|
||||
In practice this means that unit tests should be at the function-level
|
||||
where this makes sense, or at the struct-level if this makes more sense.
|
||||
|
||||
For now, avoid the use of test mocks, but use them if it makes
|
||||
strong sense to do so.
|
||||
|
||||
|
||||
### Integration tests
|
||||
|
||||
Integration tests should live in the `tests/` directory.
|
||||
|
||||
In general, each test will get its own throwaway Postgres database.
|
||||
|
||||
|
||||
#### Snapshot tests
|
||||
|
||||
Some of the integration tests will compare snapshots (of e.g. HTML) against
|
||||
a gold standard.
|
||||
|
||||
When a new snapshot is created, the output should be manually verified,
|
||||
including in a browser if necessary.
|
||||
|
||||
It goes without saying that all snapshot changes should be expected;
|
||||
if they are not then treated as failures.
|
||||
|
||||
|
||||
### End-to-end tests
|
||||
|
||||
idCoop doesn't currently have end-to-end tests but this is on the wishlist
|
||||
for the future.
|
||||
|
||||
Will eventually look into Playwright etc.
|
@ -9,3 +9,6 @@ pub mod config;
|
||||
pub mod passwords;
|
||||
pub mod store;
|
||||
pub mod web;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
91
src/tests.rs
Normal file
91
src/tests.rs
Normal file
@ -0,0 +1,91 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use axum::Router;
|
||||
use confique::{Config, Partial};
|
||||
use josekit::jwk::alg::rsa::RsaKeyPair;
|
||||
use pgtemp::PgTempDB;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::{
|
||||
config::{Configuration, SecretConfig},
|
||||
store::IdCoopStore,
|
||||
web::make_router,
|
||||
};
|
||||
|
||||
struct TestSystem {
|
||||
database: PgTempDB,
|
||||
web: Router,
|
||||
}
|
||||
|
||||
const RSA_KEY_PAIR_PEM: &[u8] = include_bytes!("tests/keypair.pem");
|
||||
const RSA_PUBLIC_KEY_PEM: &[u8] = include_bytes!("tests/publickey.crt");
|
||||
|
||||
// #[rstest::fixture]
|
||||
async fn basic_system() -> TestSystem {
|
||||
let temp_db = pgtemp::PgTempDBBuilder::new()
|
||||
.with_dbname("test_idcoop")
|
||||
.start_async()
|
||||
.await;
|
||||
|
||||
let store = IdCoopStore::connect(&temp_db.connection_uri())
|
||||
.await
|
||||
.expect("failed to connect to pgtemp db");
|
||||
|
||||
let config_partial: <Configuration as confique::Config>::Partial =
|
||||
serde_json::from_value(json!({
|
||||
"listen": {
|
||||
// Not useful, not actually used in the tests
|
||||
"bind": "127.0.0.1:1",
|
||||
"public_base_uri": "http://idcoop.example.com",
|
||||
},
|
||||
"postgres": {
|
||||
"connect": "postgres://not-used-in-tests"
|
||||
},
|
||||
"oidc": {
|
||||
"issuer": "http://issuer.example.com",
|
||||
"rsa_keypair": "not-used-in-tests",
|
||||
"clients": {
|
||||
"aclient": {
|
||||
"redirect_uris": [
|
||||
"http://aclient.example.com/redirect"
|
||||
],
|
||||
"name": "AClient",
|
||||
"allow_user_classes": ["active"],
|
||||
"secret": "secretA",
|
||||
}
|
||||
}
|
||||
},
|
||||
"password_hashing": {
|
||||
// Use weak password hash settings; we're not testing Argon2 here,
|
||||
// we just want it to be fast.
|
||||
"memory": 512,
|
||||
"iterations": 1,
|
||||
},
|
||||
"ratelimits": {
|
||||
"login": "3 per hour, 2 burst",
|
||||
},
|
||||
}))
|
||||
.expect("bad test config");
|
||||
let config =
|
||||
Configuration::from_partial(config_partial.with_fallback(Partial::default_values()))
|
||||
.expect("failed to load builtin config");
|
||||
|
||||
let secrets = SecretConfig {
|
||||
rsa_key_pair: RsaKeyPair::from_pem(RSA_KEY_PAIR_PEM)
|
||||
.expect("failed to decode builtin RSA keypair"),
|
||||
};
|
||||
|
||||
let router = make_router(Arc::new(store), Arc::new(config), Arc::new(secrets))
|
||||
.await
|
||||
.expect("failed to make router");
|
||||
|
||||
TestSystem {
|
||||
database: temp_db,
|
||||
web: router,
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_demo() {
|
||||
let basic = basic_system().await;
|
||||
}
|
28
src/tests/keypair.pem
Normal file
28
src/tests/keypair.pem
Normal file
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDDu6acOa+3ae2S
|
||||
0llp5oMsXjBMd5QJeQJCcY5Q9NAITF2U9VBwAiMf2wmaTZ1aWWFGSb/zWef7Hx1e
|
||||
qNhsK9MYL+QdJih2I+KpMtDWm7hhy9FtCHVc9i1z9PruXb0om2jDWLuBkPdCqJZT
|
||||
C58ObZKmgL4OH5F1Qv5JR/ZX21OjLolXPJo1sonLv9mlgufvhUmnC17onSSqFLBA
|
||||
nhUedjbfdnLShkp0xa8G0nW7Ls7Idaxyo8M5S2M+azJyLI87eqjjfz0yIW0Am890
|
||||
mRa81hO2D+YNcVA2wIE9MEI/ie480YxLQ0VHCjX4DcVir4ceExysYkdL8VK+U14g
|
||||
NO67k4NVAgMBAAECggEABnseJyoZ0V7miOgCIemKClwMCVwkQLQLCRwtdCzG/p9Y
|
||||
sef1g9/uPc3I4Z0USruO5v7mJi6h6cS7+jhpAhvpX3GmgfiTemXxyVxvYcvCLSrM
|
||||
gmm3SR61npNMA7yC2OdcbqtvefjM1x4x7AoEeDvUkULOCDWvYUyYkuCZHYubl1mS
|
||||
Rtcp9rxzky2tjdp8CHySBa9Kz9LEjWdFGky7g3vSyqZtw6tkK5CTwMPb9aHwiEq1
|
||||
yDWCbqAPPnb300dXSqx7z3AcsxBi/lpCs79fQS1vSJ1/L9POpYxX0SMtffkR5+Bl
|
||||
Mkg9dZUVenfbP4n40FdMypTTX2KJiMkc8+f0+Tz9QQKBgQDrdT7xs0lqMeZWp2rD
|
||||
y2KLzRl0iO/+yKse+BgkeBggZ/Vh2TeF9ylTRYdmimxkJ8eZRipTr0F64BS/LPEk
|
||||
RgWviuf9dUl0gyuhYTOJgUw1wcgtB6e+04UKEUsQW6JoNZekkM+xTa7FskLmlJ4J
|
||||
zzowjF1lgJeEyX1tvWXKIVe+/QKBgQDUzy5nZoUqBrVTYxL2uadIUh8oiBKPU93U
|
||||
Gz3DUq90yfDa7lFhwMRQRXfNqGUy6tshsaF4fT1b62hZDSz1OH3h/y1LKQOdF5kc
|
||||
JJyk/4b7NJna16kwBLzWje5SjQKr51aQWU8JftZ5/8uck2j7vMi+mgwzpG45J7kv
|
||||
Q1I5decBOQKBgFq1sKotB/uBfdukY91KXYy+VzAuEUd2x3YG3kYufhz97+riZCGY
|
||||
NrN99cvrSBbNvHewMF5NBkzwRw3foob28vnN6dIbfVEFt6lUaSZwSYvsO9IdQOKj
|
||||
Wn2ma+TBaK/89Y7QuzLzWoGPS3bJipj83M4XRWP1RmpBtbCxZqWYctWBAoGAMZPi
|
||||
16wGsffGHpsiO+CcnDilkafByypar6N5DBwjTC4PsrF6vC9QjPLiKkNk8CvOyVa8
|
||||
q3lh5hw9vyFWq/pxOUldn/j6Iorw3KGa7MWrCLMEdPtxKwKvi7ydHRZE3Q+UFyT3
|
||||
SNsH1HxHTz74Yk1k5yK0XQOduisK9XvVmBVjr+ECgYEAyoSbo/1cyLKWgrIr0K/f
|
||||
stiKL9SmBmYbaGaxtQToB5Hnqso7Hz5YEDlrcr8s1ukEFghgeNYuDYw3ZKKGGfZm
|
||||
yVQKAt8ouoO8rfkLrtt0H+/0uJgouhewDEqf/O+MfzwDnFcT89J5ZTEf+9n6pjry
|
||||
fuiQnuwEsPYGCCFuWWlrdHQ=
|
||||
-----END PRIVATE KEY-----
|
9
src/tests/publickey.crt
Normal file
9
src/tests/publickey.crt
Normal file
@ -0,0 +1,9 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw7umnDmvt2ntktJZaeaD
|
||||
LF4wTHeUCXkCQnGOUPTQCExdlPVQcAIjH9sJmk2dWllhRkm/81nn+x8dXqjYbCvT
|
||||
GC/kHSYodiPiqTLQ1pu4YcvRbQh1XPYtc/T67l29KJtow1i7gZD3QqiWUwufDm2S
|
||||
poC+Dh+RdUL+SUf2V9tToy6JVzyaNbKJy7/ZpYLn74VJpwte6J0kqhSwQJ4VHnY2
|
||||
33Zy0oZKdMWvBtJ1uy7OyHWscqPDOUtjPmsyciyPO3qo4389MiFtAJvPdJkWvNYT
|
||||
tg/mDXFQNsCBPTBCP4nuPNGMS0NFRwo1+A3FYq+HHhMcrGJHS/FSvlNeIDTuu5OD
|
||||
VQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
Loading…
Reference in New Issue
Block a user