Skip to content

tests: Extract routes module #5535

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Nov 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/tests/all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,14 @@ mod authentication;
mod blocked_routes;
mod builders;
mod categories;
mod category;
mod dump_db;
mod keyword;
mod krate;
mod metrics;
mod not_found_error;
mod owners;
mod pagination;
mod read_only_mode;
mod record;
mod routes;
mod schema_details;
mod server;
mod server_binary;
Expand Down
25 changes: 0 additions & 25 deletions src/tests/krate/following.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,6 @@ use crate::builders::CrateBuilder;
use crate::util::{RequestHelper, TestApp};
use crate::OkBool;

#[test]
fn diesel_not_found_results_in_404() {
let (_, _, user) = TestApp::init().with_user();

user.get("/api/v1/crates/foo_following/following")
.assert_not_found();
}

#[test]
fn following() {
// TODO: Test anon requests as well?
Expand Down Expand Up @@ -58,23 +50,6 @@ fn following() {
assert_eq!(user.search("following=1").crates.len(), 0);
}

#[test]
fn disallow_api_token_auth_for_get_crate_following_status() {
let (app, _, _, token) = TestApp::init().with_token();
let api_token = token.as_model();

let a_crate = "a_crate";

app.db(|conn| {
CrateBuilder::new(a_crate, api_token.user_id).expect_build(conn);
});

// Token auth on GET for get following status is disallowed
token
.get(&format!("/api/v1/crates/{a_crate}/following"))
.assert_forbidden();
}

#[test]
fn getting_followed_crates_allows_api_token_auth() {
let (app, _, user, token) = TestApp::init().with_token();
Expand Down
7 changes: 0 additions & 7 deletions src/tests/krate/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
mod dependencies;
mod downloads;
mod following;
mod owners;
mod publish;
mod reverse_dependencies;
mod search;
mod show;
mod summary;
mod versions;
mod yanking;
2 changes: 1 addition & 1 deletion src/tests/krate/publish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ fn new_with_underscore_renamed_dependency() {

#[test]
fn new_krate_with_dependency() {
use super::dependencies::Deps;
use crate::routes::crates::versions::dependencies::Deps;

let (app, anon, user, token) = TestApp::full().with_token();

Expand Down
29 changes: 29 additions & 0 deletions src/tests/pagination.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use crate::builders::CrateBuilder;
use crate::util::{RequestHelper, TestApp};
use http::status::StatusCode;
use ipnetwork::IpNetwork;
use serde_json::json;

#[test]
fn pagination_blocks_ip_from_cidr_block_list() {
let (app, anon, user) = TestApp::init()
.with_config(|config| {
config.max_allowed_page_offset = 1;
config.page_offset_cidr_blocklist = vec!["127.0.0.1/24".parse::<IpNetwork>().unwrap()];
})
.with_user();
let user = user.as_model();

app.db(|conn| {
CrateBuilder::new("pagination_links_1", user.id).expect_build(conn);
CrateBuilder::new("pagination_links_2", user.id).expect_build(conn);
CrateBuilder::new("pagination_links_3", user.id).expect_build(conn);
});

let response = anon.get_with_query::<()>("/api/v1/crates", "page=2&per_page=1");
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
assert_eq!(
response.into_json(),
json!({ "errors": [{ "detail": "requested page offset is too large" }] })
);
}
49 changes: 4 additions & 45 deletions src/tests/category.rs → src/tests/routes/categories/get.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,10 @@
use crate::util::insta::assert_yaml_snapshot;
use crate::{
builders::CrateBuilder, new_category, util::MockAnonymousUser, RequestHelper, TestApp,
};
use crate::builders::CrateBuilder;
use crate::new_category;
use crate::util::{MockAnonymousUser, RequestHelper, TestApp};
use cargo_registry::models::Category;
use insta::assert_yaml_snapshot;
use serde_json::Value;

#[test]
fn index() {
let (app, anon) = TestApp::init().empty();

// List 0 categories if none exist
let json: Value = anon.get("/api/v1/categories").good();
assert_yaml_snapshot!(json);

// Create a category and a subcategory
app.db(|conn| {
new_category("foo", "foo", "Foo crates")
.create_or_update(conn)
.unwrap();
new_category("foo::bar", "foo::bar", "Bar crates")
.create_or_update(conn)
.unwrap();
});

// Only the top-level categories should be on the page
let json: Value = anon.get("/api/v1/categories").good();
assert_yaml_snapshot!(json, {
".categories[].created_at" => "[datetime]",
});
}

#[test]
fn show() {
let (app, anon) = TestApp::init().empty();
Expand Down Expand Up @@ -129,19 +104,3 @@ fn update_crate() {
assert_eq!(count(&anon, "category-2"), 0);
});
}

#[test]
fn category_slugs_returns_all_slugs_in_alphabetical_order() {
let (app, anon) = TestApp::init().empty();
app.db(|conn| {
new_category("Foo", "foo", "For crates that foo")
.create_or_update(conn)
.unwrap();
new_category("Bar", "bar", "For crates that bar")
.create_or_update(conn)
.unwrap();
});

let response: Value = anon.get("/api/v1/category_slugs").good();
assert_yaml_snapshot!(response);
}
29 changes: 29 additions & 0 deletions src/tests/routes/categories/list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use crate::new_category;
use crate::util::{RequestHelper, TestApp};
use insta::assert_yaml_snapshot;
use serde_json::Value;

#[test]
fn index() {
let (app, anon) = TestApp::init().empty();

// List 0 categories if none exist
let json: Value = anon.get("/api/v1/categories").good();
assert_yaml_snapshot!(json);

// Create a category and a subcategory
app.db(|conn| {
new_category("foo", "foo", "Foo crates")
.create_or_update(conn)
.unwrap();
new_category("foo::bar", "foo::bar", "Bar crates")
.create_or_update(conn)
.unwrap();
});

// Only the top-level categories should be on the page
let json: Value = anon.get("/api/v1/categories").good();
assert_yaml_snapshot!(json, {
".categories[].created_at" => "[datetime]",
});
}
2 changes: 2 additions & 0 deletions src/tests/routes/categories/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod get;
pub mod list;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
source: src/tests/category.rs
assertion_line: 51
source: src/tests/routes/categories/get.rs
assertion_line: 26
expression: json
---
category:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
source: src/tests/category.rs
assertion_line: 33
source: src/tests/routes/categories/list.rs
assertion_line: 26
expression: json
---
categories:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
source: src/tests/routes/categories/list.rs
assertion_line: 12
expression: json
---
categories: []
meta:
total: 0

20 changes: 20 additions & 0 deletions src/tests/routes/category_slugs/list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use crate::new_category;
use crate::util::{RequestHelper, TestApp};
use insta::assert_yaml_snapshot;
use serde_json::Value;

#[test]
fn category_slugs_returns_all_slugs_in_alphabetical_order() {
let (app, anon) = TestApp::init().empty();
app.db(|conn| {
new_category("Foo", "foo", "For crates that foo")
.create_or_update(conn)
.unwrap();
new_category("Bar", "bar", "For crates that bar")
.create_or_update(conn)
.unwrap();
});

let response: Value = anon.get("/api/v1/category_slugs").good();
assert_yaml_snapshot!(response);
}
1 change: 1 addition & 0 deletions src/tests/routes/category_slugs/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod list;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
source: src/tests/category.rs
assertion_line: 153
source: src/tests/routes/category_slugs/list.rs
assertion_line: 19
expression: response
---
category_slugs:
Expand Down
83 changes: 83 additions & 0 deletions src/tests/routes/crates/downloads.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use crate::builders::{CrateBuilder, VersionBuilder};
use crate::util::{MockAnonymousUser, RequestHelper, TestApp};
use cargo_registry::views::EncodableVersionDownload;
use chrono::{Duration, Utc};
use http::StatusCode;

#[derive(Deserialize)]
struct Downloads {
version_downloads: Vec<EncodableVersionDownload>,
}

pub fn persist_downloads_count(app: &TestApp) {
app.as_inner()
.downloads_counter
.persist_all_shards(app.as_inner())
.expect("failed to persist downloads count")
.log();
}

#[track_caller]
pub fn assert_dl_count(
anon: &MockAnonymousUser,
name_and_version: &str,
query: Option<&str>,
count: i32,
) {
let url = format!("/api/v1/crates/{name_and_version}/downloads");
let downloads: Downloads = if let Some(query) = query {
anon.get_with_query(&url, query).good()
} else {
anon.get(&url).good()
};
let total_downloads = downloads
.version_downloads
.iter()
.map(|vd| vd.downloads)
.sum::<i32>();
assert_eq!(total_downloads, count);
}

#[test]
fn download() {
let (app, anon, user) = TestApp::init().with_user();
let user = user.as_model();

app.db(|conn| {
CrateBuilder::new("foo_download", user.id)
.version(VersionBuilder::new("1.0.0"))
.expect_build(conn);
});

let download = |name_and_version: &str| {
let url = format!("/api/v1/crates/{name_and_version}/download");
let response = anon.get::<()>(&url);
assert_eq!(response.status(), StatusCode::FOUND);
// TODO: test the with_json code path
};

download("foo_download/1.0.0");
// No downloads are counted until the counters are persisted
assert_dl_count(&anon, "foo_download/1.0.0", None, 0);
assert_dl_count(&anon, "foo_download", None, 0);
persist_downloads_count(&app);
// Now that the counters are persisted the download counts show up.
assert_dl_count(&anon, "foo_download/1.0.0", None, 1);
assert_dl_count(&anon, "foo_download", None, 1);

download("FOO_DOWNLOAD/1.0.0");
persist_downloads_count(&app);
assert_dl_count(&anon, "FOO_DOWNLOAD/1.0.0", None, 2);
assert_dl_count(&anon, "FOO_DOWNLOAD", None, 2);

let yesterday = (Utc::now().date_naive() + Duration::days(-1)).format("%F");
let query = format!("before_date={yesterday}");
assert_dl_count(&anon, "FOO_DOWNLOAD/1.0.0", Some(&query), 0);
// crate/downloads always returns the last 90 days and ignores date params
assert_dl_count(&anon, "FOO_DOWNLOAD", Some(&query), 2);

let tomorrow = (Utc::now().date_naive() + Duration::days(1)).format("%F");
let query = format!("before_date={tomorrow}");
assert_dl_count(&anon, "FOO_DOWNLOAD/1.0.0", Some(&query), 2);
assert_dl_count(&anon, "FOO_DOWNLOAD", Some(&query), 2);
}
27 changes: 27 additions & 0 deletions src/tests/routes/crates/following.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use crate::builders::CrateBuilder;
use crate::util::{RequestHelper, TestApp};

#[test]
fn diesel_not_found_results_in_404() {
let (_, _, user) = TestApp::init().with_user();

user.get("/api/v1/crates/foo_following/following")
.assert_not_found();
}

#[test]
fn disallow_api_token_auth_for_get_crate_following_status() {
let (app, _, _, token) = TestApp::init().with_token();
let api_token = token.as_model();

let a_crate = "a_crate";

app.db(|conn| {
CrateBuilder::new(a_crate, api_token.user_id).expect_build(conn);
});

// Token auth on GET for get following status is disallowed
token
.get(&format!("/api/v1/crates/{a_crate}/following"))
.assert_forbidden();
}
Loading