test: seed ready wrapups, federation-off gate target
This commit is contained in:
@@ -41,6 +41,9 @@ jobs:
|
|||||||
- name: test
|
- name: test
|
||||||
run: cargo test
|
run: cargo test
|
||||||
|
|
||||||
|
- name: test (federation off)
|
||||||
|
run: cargo test --workspace --no-default-features
|
||||||
|
|
||||||
# Layering guards. These live in the Makefile and were previously local-only,
|
# Layering guards. These live in the Makefile and were previously local-only,
|
||||||
# so a PR could go green in CI while violating them.
|
# so a PR could go green in CI while violating them.
|
||||||
- name: guards
|
- name: guards
|
||||||
|
|||||||
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
@@ -41,6 +41,9 @@ jobs:
|
|||||||
- name: test
|
- name: test
|
||||||
run: cargo test
|
run: cargo test
|
||||||
|
|
||||||
|
- name: test (federation off)
|
||||||
|
run: cargo test --workspace --no-default-features
|
||||||
|
|
||||||
# Layering guards. These live in the Makefile and were previously local-only,
|
# Layering guards. These live in the Makefile and were previously local-only,
|
||||||
# so a PR could go green in CI while violating them.
|
# so a PR could go green in CI while violating them.
|
||||||
- name: guards
|
- name: guards
|
||||||
|
|||||||
7
Makefile
7
Makefile
@@ -1,6 +1,6 @@
|
|||||||
.DEFAULT_GOAL := check
|
.DEFAULT_GOAL := check
|
||||||
|
|
||||||
check: fmt-check clippy test check-appcontext check-handler-deps check-handler-repos check-presentation-adapters check-federation-off-social check-binaries-are-thin check-sqlite-is-ap-free
|
check: fmt-check clippy test test-federation-off check-appcontext check-handler-deps check-handler-repos check-presentation-adapters check-federation-off-social check-binaries-are-thin check-sqlite-is-ap-free
|
||||||
@echo "✅ All checks passed"
|
@echo "✅ All checks passed"
|
||||||
|
|
||||||
check-appcontext:
|
check-appcontext:
|
||||||
@@ -99,6 +99,9 @@ clippy:
|
|||||||
test:
|
test:
|
||||||
cargo test --workspace
|
cargo test --workspace
|
||||||
|
|
||||||
|
test-federation-off:
|
||||||
|
cargo test --workspace --no-default-features
|
||||||
|
|
||||||
fix:
|
fix:
|
||||||
cargo fmt
|
cargo fmt
|
||||||
cargo clippy --fix --allow-dirty --allow-staged
|
cargo clippy --fix --allow-dirty --allow-staged
|
||||||
@@ -126,4 +129,4 @@ dev-spa:
|
|||||||
spa-dev:
|
spa-dev:
|
||||||
@npm --prefix spa run dev
|
@npm --prefix spa run dev
|
||||||
|
|
||||||
.PHONY: check fmt fmt-check clippy test fix dev dev-stop dev-worker dev-spa spa-dev check-appcontext check-handler-deps check-handler-repos check-presentation-adapters check-federation-off-social check-binaries-are-thin check-sqlite-is-ap-free
|
.PHONY: check fmt fmt-check clippy test test-federation-off fix dev dev-stop dev-worker dev-spa spa-dev check-appcontext check-handler-deps check-handler-repos check-presentation-adapters check-federation-off-social check-binaries-are-thin check-sqlite-is-ap-free
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ const CLASSIC_VISITOR_PAGES: &[(&str, u16)] = &[
|
|||||||
("/logout", 303),
|
("/logout", 303),
|
||||||
("/tags/drama", 307),
|
("/tags/drama", 307),
|
||||||
("/users/{id}/watchlist", 200),
|
("/users/{id}/watchlist", 200),
|
||||||
("/wrapups/{id}/2025", 404),
|
("/wrapups/{id}/2025", 200),
|
||||||
("/wrapups/global/2025", 404),
|
("/wrapups/global/2025", 200),
|
||||||
("/users/{id}/following-list", 303),
|
("/users/{id}/following-list", 303),
|
||||||
("/users/{id}/followers-list", 303),
|
("/users/{id}/followers-list", 303),
|
||||||
("/posters/abc.jpg", 308),
|
("/posters/abc.jpg", 308),
|
||||||
@@ -173,7 +173,7 @@ async fn seed() -> Seed {
|
|||||||
.connect("sqlite::memory:")
|
.connect("sqlite::memory:")
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let router = bootstrap::build_server_on(&test_config(), pool)
|
let router = bootstrap::build_server_on(&test_config(), pool.clone())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -231,10 +231,7 @@ async fn seed() -> Seed {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
assert!(
|
assert_eq!(status, 201, "log review: {body}");
|
||||||
status == 200 || status == 201,
|
|
||||||
"log review {status}: {body}"
|
|
||||||
);
|
|
||||||
|
|
||||||
let (status, _, body) = send(
|
let (status, _, body) = send(
|
||||||
&router,
|
&router,
|
||||||
@@ -246,10 +243,7 @@ async fn seed() -> Seed {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
assert!(
|
assert_eq!(status, 200, "create goal: {body}");
|
||||||
status == 200 || status == 201,
|
|
||||||
"create goal {status}: {body}"
|
|
||||||
);
|
|
||||||
|
|
||||||
let (status, _, body) = send(
|
let (status, _, body) = send(
|
||||||
&router,
|
&router,
|
||||||
@@ -262,18 +256,14 @@ async fn seed() -> Seed {
|
|||||||
.await;
|
.await;
|
||||||
assert_eq!(status, 200, "list movies: {body}");
|
assert_eq!(status, 200, "list movies: {body}");
|
||||||
let movies: serde_json::Value = serde_json::from_str(&body).unwrap();
|
let movies: serde_json::Value = serde_json::from_str(&body).unwrap();
|
||||||
let first = movies
|
let movie_id = movies["items"][0]["id"]
|
||||||
.get("movies")
|
|
||||||
.and_then(|m| m.get(0))
|
|
||||||
.or_else(|| movies.get(0))
|
|
||||||
.or_else(|| movies.get("items").and_then(|m| m.get(0)))
|
|
||||||
.unwrap_or_else(|| panic!("no movie in {body}"));
|
|
||||||
let movie_id = first["id"]
|
|
||||||
.as_str()
|
.as_str()
|
||||||
.or_else(|| first["movie"]["id"].as_str())
|
|
||||||
.unwrap_or_else(|| panic!("no movie id in {body}"))
|
.unwrap_or_else(|| panic!("no movie id in {body}"))
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
|
seed_ready_wrapup(&pool, Some(&user_id)).await;
|
||||||
|
seed_ready_wrapup(&pool, None).await;
|
||||||
|
|
||||||
Seed {
|
Seed {
|
||||||
router,
|
router,
|
||||||
user_id,
|
user_id,
|
||||||
@@ -282,6 +272,35 @@ async fn seed() -> Seed {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Inserts a READY 2025 wrap-up record (user scope, or global when `user_id` is None),
|
||||||
|
/// the state the worker leaves behind after generating a report.
|
||||||
|
async fn seed_ready_wrapup(pool: &sqlx::SqlitePool, user_id: Option<&str>) {
|
||||||
|
use chrono::NaiveDate;
|
||||||
|
use domain::models::wrapup::{DateRange, WrapUpScope};
|
||||||
|
|
||||||
|
let start = NaiveDate::from_ymd_opt(2025, 1, 1).unwrap();
|
||||||
|
let end = NaiveDate::from_ymd_opt(2026, 1, 1).unwrap();
|
||||||
|
let scope = match user_id {
|
||||||
|
Some(id) => WrapUpScope::User(id.parse().unwrap()),
|
||||||
|
None => WrapUpScope::Global,
|
||||||
|
};
|
||||||
|
let report = domain::services::wrapup_analyzer::build_report(
|
||||||
|
scope,
|
||||||
|
DateRange::new(start, end).unwrap(),
|
||||||
|
&[],
|
||||||
|
);
|
||||||
|
sqlx::query(
|
||||||
|
"INSERT INTO wrap_up_records (id, user_id, start_date, end_date, status, report_json) \
|
||||||
|
VALUES (?, ?, '2025-01-01', '2026-01-01', 'ready', ?)",
|
||||||
|
)
|
||||||
|
.bind(uuid::Uuid::new_v4().to_string())
|
||||||
|
.bind(user_id)
|
||||||
|
.bind(serde_json::to_string(&report).unwrap())
|
||||||
|
.execute(pool)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
fn expand(seed: &Seed, template: &str) -> String {
|
fn expand(seed: &Seed, template: &str) -> String {
|
||||||
template
|
template
|
||||||
.replace("{id}", &seed.user_id)
|
.replace("{id}", &seed.user_id)
|
||||||
@@ -314,6 +333,16 @@ async fn every_classic_page_renders_for_a_visitor() {
|
|||||||
#[cfg(not(feature = "federation"))]
|
#[cfg(not(feature = "federation"))]
|
||||||
check_table(&seed, FEDERATION_OFF_PAGES, None).await;
|
check_table(&seed, FEDERATION_OFF_PAGES, None).await;
|
||||||
|
|
||||||
|
// A dropped wrapup route would also 404, so require the template itself.
|
||||||
|
for template in ["/wrapups/{id}/2025", "/wrapups/global/2025"] {
|
||||||
|
let (status, _, body) = send(&seed.router, get(&expand(&seed, template), None)).await;
|
||||||
|
assert_eq!(status, 200, "{template}");
|
||||||
|
assert!(
|
||||||
|
body.contains("class=\"wu-container\""),
|
||||||
|
"wrapup template not rendered for {template}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// The owner embeds this widget in an iframe on their personal website.
|
// The owner embeds this widget in an iframe on their personal website.
|
||||||
let (status, _, body) = send(
|
let (status, _, body) = send(
|
||||||
&seed.router,
|
&seed.router,
|
||||||
@@ -339,16 +368,18 @@ async fn every_classic_page_renders_for_the_signed_in_owner() {
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn feeds_and_openapi_are_served() {
|
async fn feeds_and_openapi_are_served() {
|
||||||
let seed = seed().await;
|
let seed = seed().await;
|
||||||
for template in [
|
// `/docs` (what users type) redirects to the Swagger UI at `/docs/`.
|
||||||
"/feed.rss",
|
for (template, expected) in [
|
||||||
"/users/{id}/feed.rss",
|
("/feed.rss", 200),
|
||||||
"/openapi.json",
|
("/users/{id}/feed.rss", 200),
|
||||||
"/docs/",
|
("/openapi.json", 200),
|
||||||
"/scalar",
|
("/docs", 303),
|
||||||
|
("/docs/", 200),
|
||||||
|
("/scalar", 200),
|
||||||
] {
|
] {
|
||||||
let uri = expand(&seed, template);
|
let uri = expand(&seed, template);
|
||||||
let (status, _, _) = send(&seed.router, get(&uri, None)).await;
|
let (status, _, _) = send(&seed.router, get(&uri, None)).await;
|
||||||
assert_eq!(status, 200, "{uri}");
|
assert_eq!(status, expected, "{uri}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user