From b011363524f1088dc536c31869f172ceab45f837 Mon Sep 17 00:00:00 2001 From: Cyborus Date: Tue, 14 May 2024 12:09:35 -0400 Subject: split tests into multiple files --- tests/admin.rs | 140 ++++++++++++++ tests/ci_test.rs | 535 ---------------------------------------------------- tests/common/mod.rs | 7 + tests/repo.rs | 242 ++++++++++++++++++++++++ tests/user.rs | 155 +++++++++++++++ 5 files changed, 544 insertions(+), 535 deletions(-) create mode 100644 tests/admin.rs delete mode 100644 tests/ci_test.rs create mode 100644 tests/common/mod.rs create mode 100644 tests/repo.rs create mode 100644 tests/user.rs diff --git a/tests/admin.rs b/tests/admin.rs new file mode 100644 index 0000000..a8e7e1d --- /dev/null +++ b/tests/admin.rs @@ -0,0 +1,140 @@ +use forgejo_api::structs::*; + +mod common; + +#[tokio::test] +async fn admin() { + let api = common::get_api(); + + let user_opt = CreateUserOption { + created_at: None, + email: "pipis@noreply.example.org".into(), + full_name: None, + login_name: None, + must_change_password: None, + password: Some("userpass".into()), + restricted: Some(false), + send_notify: Some(true), + source_id: None, + username: "Pipis".into(), + visibility: Some("public".into()), + }; + let _ = api + .admin_create_user(user_opt) + .await + .expect("failed to create user"); + + let query = AdminSearchUsersQuery::default(); + let users = api + .admin_search_users(query) + .await + .expect("failed to search users"); + assert!( + users + .iter() + .find(|u| u.login.as_ref().unwrap() == "Pipis") + .is_some(), + "could not find new user" + ); + let query = AdminGetAllEmailsQuery::default(); + let users = api + .admin_get_all_emails(query) + .await + .expect("failed to search emails"); + assert!( + users + .iter() + .find(|u| u.email.as_ref().unwrap() == "pipis@noreply.example.org") + .is_some(), + "could not find new user" + ); + + let org_opt = CreateOrgOption { + description: None, + email: None, + full_name: None, + location: None, + repo_admin_change_team_access: None, + username: "test-org".into(), + visibility: Some(CreateOrgOptionVisibility::Public), + website: None, + }; + let _ = api + .admin_create_org("Pipis", org_opt) + .await + .expect("failed to create org"); + let query = AdminGetAllOrgsQuery::default(); + assert!( + !api.admin_get_all_orgs(query).await.unwrap().is_empty(), + "org list empty" + ); + + let key_opt = CreateKeyOption { + key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN68ehQAsbGEwlXPa2AxbAh1QxFQrtRel2jeC0hRlPc1 user@noreply.example.org".into(), + read_only: None, + title: "Example Key".into(), + }; + let key = api + .admin_create_public_key("Pipis", key_opt) + .await + .expect("failed to create key"); + api.admin_delete_user_public_key("Pipis", key.id.unwrap()) + .await + .expect("failed to delete key"); + + let rename_opt = RenameUserOption { + new_username: "Bepis".into(), + }; + api.admin_rename_user("Pipis", rename_opt) + .await + .expect("failed to rename user"); + let query = AdminDeleteUserQuery { purge: Some(true) }; + api.admin_delete_user("Bepis", query) + .await + .expect("failed to delete user"); + let query = AdminDeleteUserQuery { purge: Some(true) }; + assert!( + api.admin_delete_user("Ghost", query).await.is_err(), + "deleting fake user should fail" + ); + + let query = AdminCronListQuery::default(); + let crons = api + .admin_cron_list(query) + .await + .expect("failed to get crons list"); + api.admin_cron_run(&crons.get(0).expect("no crons").name.as_ref().unwrap()) + .await + .expect("failed to run cron"); + + let hook_opt = CreateHookOption { + active: None, + authorization_header: None, + branch_filter: None, + config: CreateHookOptionConfig { + content_type: "json".into(), + url: url::Url::parse("http://test.local/").unwrap(), + additional: Default::default(), + }, + events: Some(Vec::new()), + r#type: CreateHookOptionType::Gitea, + }; + // yarr har har me matey this is me hook + let hook = api + .admin_create_hook(hook_opt) + .await + .expect("failed to create hook"); + let edit_hook = EditHookOption { + active: Some(true), + authorization_header: None, + branch_filter: None, + config: None, + events: None, + }; + api.admin_edit_hook(hook.id.unwrap(), edit_hook) + .await + .expect("failed to edit hook"); + api.admin_delete_hook(hook.id.unwrap()) + .await + .expect("failed to delete hook"); +} diff --git a/tests/ci_test.rs b/tests/ci_test.rs deleted file mode 100644 index 269c522..0000000 --- a/tests/ci_test.rs +++ /dev/null @@ -1,535 +0,0 @@ -use forgejo_api::{structs::*, Forgejo}; - -fn get_api() -> Forgejo { - let url = url::Url::parse(&std::env::var("FORGEJO_API_CI_INSTANCE_URL").unwrap()).unwrap(); - let token = std::env::var("FORGEJO_API_CI_TOKEN").unwrap(); - Forgejo::new(forgejo_api::Auth::Token(&token), url).unwrap() -} - -#[tokio::test] -async fn user() { - let api = get_api(); - - let myself = api.user_get_current().await.unwrap(); - assert!(myself.is_admin.unwrap(), "user should be admin"); - assert_eq!( - myself.login.as_ref().unwrap(), - "TestingAdmin", - "user should be named \"TestingAdmin\"" - ); - - let myself_indirect = api.user_get("TestingAdmin").await.unwrap(); - assert_eq!( - myself, myself_indirect, - "result of `myself` does not match result of `get_user`" - ); - - let query = UserListFollowingQuery::default(); - let following = api - .user_list_following("TestingAdmin", query) - .await - .unwrap(); - assert_eq!(following, Vec::new(), "following list not empty"); - - let query = UserListFollowersQuery::default(); - let followers = api - .user_list_followers("TestingAdmin", query) - .await - .unwrap(); - assert_eq!(followers, Vec::new(), "follower list not empty"); - - let url = url::Url::parse(&std::env::var("FORGEJO_API_CI_INSTANCE_URL").unwrap()).unwrap(); - let password_api = Forgejo::new( - forgejo_api::Auth::Password { - username: "TestingAdmin", - password: "password", - mfa: None, - }, - url, - ) - .expect("failed to log in using username and password"); - - assert!( - api.user_get_current().await.unwrap() == password_api.user_get_current().await.unwrap(), - "users not equal comparing token-auth and pass-auth" - ); -} - -#[tokio::test] -async fn repo() { - let api = get_api(); - - tokio::fs::create_dir("./test_repo").await.unwrap(); - let git = || { - let mut cmd = std::process::Command::new("git"); - cmd.current_dir("./test_repo"); - cmd - }; - let _ = git() - .args(["config", "--global", "init.defaultBranch", "main"]) - .status() - .unwrap(); - let _ = git().args(["init"]).status().unwrap(); - let _ = git() - .args(["config", "user.name", "TestingAdmin"]) - .status() - .unwrap(); - let _ = git() - .args(["config", "user.email", "admin@noreply.example.org"]) - .status() - .unwrap(); - tokio::fs::write("./test_repo/README.md", "# Test\nThis is a test repo") - .await - .unwrap(); - let _ = git().args(["add", "."]).status().unwrap(); - let _ = git() - .args(["commit", "-m", "initial commit"]) - .status() - .unwrap(); - - let repo_opt = CreateRepoOption { - auto_init: Some(false), - default_branch: Some("main".into()), - description: Some("Test Repo".into()), - gitignores: Some("".into()), - issue_labels: Some("".into()), - license: Some("".into()), - name: "test".into(), - object_format_name: None, - private: Some(false), - readme: None, - template: Some(false), - trust_model: Some(CreateRepoOptionTrustModel::Default), - }; - let remote_repo = api.create_current_user_repo(repo_opt).await.unwrap(); - assert!( - remote_repo.has_pull_requests.unwrap(), - "repo does not accept pull requests" - ); - assert!( - remote_repo.owner.as_ref().unwrap().login.as_ref().unwrap() == "TestingAdmin", - "repo owner is not \"TestingAdmin\"" - ); - assert!( - remote_repo.name.as_ref().unwrap() == "test", - "repo owner is not \"test\"" - ); - tokio::time::sleep(std::time::Duration::from_secs(3)).await; - - let mut remote_url = remote_repo.clone_url.clone().unwrap(); - remote_url.set_username("TestingAdmin").unwrap(); - remote_url.set_password(Some("password")).unwrap(); - let _ = git() - .args(["remote", "add", "origin", remote_url.as_str()]) - .status() - .unwrap(); - let _ = git() - .args(["push", "-u", "origin", "main"]) - .status() - .unwrap(); - - let _ = git().args(["switch", "-c", "test"]).status().unwrap(); - tokio::fs::write( - "./test_repo/example.rs", - "fn add_one(x: u32) -> u32 { x + 1 }", - ) - .await - .unwrap(); - let _ = git().args(["add", "."]).status().unwrap(); - let _ = git().args(["commit", "-m", "egg"]).status().unwrap(); - let _ = git() - .args(["push", "-u", "origin", "test"]) - .status() - .unwrap(); - - let pr_opt = CreatePullRequestOption { - assignee: None, - assignees: Some(vec!["TestingAdmin".into()]), - base: Some("main".into()), - body: Some("This is a test PR".into()), - due_date: None, - head: Some("test".into()), - labels: None, - milestone: None, - title: Some("test pr".into()), - }; - let pr = api - .repo_create_pull_request("TestingAdmin", "test", pr_opt) - .await - .expect("couldn't create pr"); - tokio::time::sleep(std::time::Duration::from_secs(3)).await; - let is_merged = api - .repo_pull_request_is_merged("TestingAdmin", "test", pr.number.unwrap()) - .await - .is_ok(); - assert!(!is_merged, "pr should not yet be merged"); - let pr_files_query = RepoGetPullRequestFilesQuery::default(); - let (_, _) = api - .repo_get_pull_request_files("TestingAdmin", "test", pr.number.unwrap(), pr_files_query) - .await - .unwrap(); - let merge_opt = MergePullRequestOption { - r#do: MergePullRequestOptionDo::Merge, - merge_commit_id: None, - merge_message_field: None, - merge_title_field: None, - delete_branch_after_merge: Some(true), - force_merge: None, - head_commit_id: None, - merge_when_checks_succeed: None, - }; - api.repo_merge_pull_request("TestingAdmin", "test", pr.number.unwrap(), merge_opt) - .await - .expect("couldn't merge pr"); - let is_merged = api - .repo_pull_request_is_merged("TestingAdmin", "test", pr.number.unwrap()) - .await - .is_ok(); - assert!(is_merged, "pr should be merged"); - let _ = git().args(["fetch"]).status().unwrap(); - let _ = git().args(["pull"]).status().unwrap(); - - let query = RepoListReleasesQuery::default(); - assert!( - api.repo_list_releases("TestingAdmin", "test", query) - .await - .unwrap() - .is_empty(), - "there should be no releases yet" - ); - - let tag_opt = CreateTagOption { - message: Some("This is a tag!".into()), - tag_name: "v1.0".into(), - target: None, - }; - api.repo_create_tag("TestingAdmin", "test", tag_opt) - .await - .expect("failed to create tag"); - - let release_opt = CreateReleaseOption { - body: Some("This is a release!".into()), - draft: Some(true), - name: Some("v1.0".into()), - prerelease: Some(false), - tag_name: "v1.0".into(), - target_commitish: None, - }; - let release = api - .repo_create_release("TestingAdmin", "test", release_opt) - .await - .expect("failed to create release"); - let edit_release = EditReleaseOption { - body: None, - draft: Some(false), - name: None, - prerelease: None, - tag_name: None, - target_commitish: None, - }; - api.repo_edit_release("TestingAdmin", "test", release.id.unwrap(), edit_release) - .await - .expect("failed to edit release"); - - let release_by_tag = api - .repo_get_release_by_tag("TestingAdmin", "test", "v1.0") - .await - .expect("failed to find release"); - let release_latest = api - .repo_get_latest_release("TestingAdmin", "test") - .await - .expect("failed to find latest release"); - assert!(release_by_tag == release_latest, "releases not equal"); - - let attachment = api - .repo_create_release_attachment( - "TestingAdmin", - "test", - release.id.unwrap(), - b"This is a file!".to_vec(), - RepoCreateReleaseAttachmentQuery { - name: Some("test.txt".into()), - }, - ) - .await - .expect("failed to create release attachment"); - assert!( - &*api - .download_release_attachment( - "TestingAdmin", - "test", - release.id.unwrap(), - attachment.id.unwrap() - ) - .await - .unwrap() - == b"This is a file!", - "couldn't download attachment" - ); - let _zip_archive = api - .repo_get_archive("TestingAdmin", "test", "v1.0.zip") - .await - .unwrap(); - let _tar_archive = api - .repo_get_archive("TestingAdmin", "test", "v1.0.tar.gz") - .await - .unwrap(); - // check these contents when their return value is fixed - - api.repo_delete_release_attachment( - "TestingAdmin", - "test", - release.id.unwrap(), - attachment.id.unwrap(), - ) - .await - .expect("failed to deleted attachment"); - - api.repo_delete_release("TestingAdmin", "test", release.id.unwrap()) - .await - .expect("failed to delete release"); - - api.repo_delete_tag("TestingAdmin", "test", "v1.0") - .await - .expect("failed to delete release"); -} - -#[tokio::test] -async fn admin() { - let api = get_api(); - - let user_opt = CreateUserOption { - created_at: None, - email: "pipis@noreply.example.org".into(), - full_name: None, - login_name: None, - must_change_password: None, - password: Some("userpass".into()), - restricted: Some(false), - send_notify: Some(true), - source_id: None, - username: "Pipis".into(), - visibility: Some("public".into()), - }; - let _ = api - .admin_create_user(user_opt) - .await - .expect("failed to create user"); - - let query = AdminSearchUsersQuery::default(); - let users = api - .admin_search_users(query) - .await - .expect("failed to search users"); - assert!( - users - .iter() - .find(|u| u.login.as_ref().unwrap() == "Pipis") - .is_some(), - "could not find new user" - ); - let query = AdminGetAllEmailsQuery::default(); - let users = api - .admin_get_all_emails(query) - .await - .expect("failed to search emails"); - assert!( - users - .iter() - .find(|u| u.email.as_ref().unwrap() == "pipis@noreply.example.org") - .is_some(), - "could not find new user" - ); - - let org_opt = CreateOrgOption { - description: None, - email: None, - full_name: None, - location: None, - repo_admin_change_team_access: None, - username: "test-org".into(), - visibility: Some(CreateOrgOptionVisibility::Public), - website: None, - }; - let _ = api - .admin_create_org("Pipis", org_opt) - .await - .expect("failed to create org"); - let query = AdminGetAllOrgsQuery::default(); - assert!( - !api.admin_get_all_orgs(query).await.unwrap().is_empty(), - "org list empty" - ); - - let key_opt = CreateKeyOption { - key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN68ehQAsbGEwlXPa2AxbAh1QxFQrtRel2jeC0hRlPc1 user@noreply.example.org".into(), - read_only: None, - title: "Example Key".into(), - }; - let key = api - .admin_create_public_key("Pipis", key_opt) - .await - .expect("failed to create key"); - api.admin_delete_user_public_key("Pipis", key.id.unwrap()) - .await - .expect("failed to delete key"); - - let rename_opt = RenameUserOption { - new_username: "Bepis".into(), - }; - api.admin_rename_user("Pipis", rename_opt) - .await - .expect("failed to rename user"); - let query = AdminDeleteUserQuery { purge: Some(true) }; - api.admin_delete_user("Bepis", query) - .await - .expect("failed to delete user"); - let query = AdminDeleteUserQuery { purge: Some(true) }; - assert!( - api.admin_delete_user("Ghost", query).await.is_err(), - "deleting fake user should fail" - ); - - let query = AdminCronListQuery::default(); - let crons = api - .admin_cron_list(query) - .await - .expect("failed to get crons list"); - api.admin_cron_run(&crons.get(0).expect("no crons").name.as_ref().unwrap()) - .await - .expect("failed to run cron"); - - let hook_opt = CreateHookOption { - active: None, - authorization_header: None, - branch_filter: None, - config: CreateHookOptionConfig { - content_type: "json".into(), - url: url::Url::parse("http://test.local/").unwrap(), - additional: Default::default(), - }, - events: Some(Vec::new()), - r#type: CreateHookOptionType::Gitea, - }; - // yarr har har me matey this is me hook - let hook = api - .admin_create_hook(hook_opt) - .await - .expect("failed to create hook"); - let edit_hook = EditHookOption { - active: Some(true), - authorization_header: None, - branch_filter: None, - config: None, - events: None, - }; - api.admin_edit_hook(hook.id.unwrap(), edit_hook) - .await - .expect("failed to edit hook"); - api.admin_delete_hook(hook.id.unwrap()) - .await - .expect("failed to delete hook"); -} - -#[tokio::test] -async fn oauth2_login() { - let api = get_api(); - let opt = forgejo_api::structs::CreateOAuth2ApplicationOptions { - confidential_client: Some(true), - name: Some("Test Application".into()), - redirect_uris: Some(vec!["http://127.0.0.1:48879/".into()]), - }; - let app = api.user_create_oauth2_application(opt).await.unwrap(); - let client_id = app.client_id.unwrap(); - let client_secret = app.client_secret.unwrap(); - - let base_url = &std::env::var("FORGEJO_API_CI_INSTANCE_URL").unwrap(); - - let client = reqwest::Client::builder() - .cookie_store(true) - .redirect(reqwest::redirect::Policy::none()) - .build() - .unwrap(); - - // Log in via the web interface - let _ = client - .post(&format!("{base_url}user/login")) - .form(&[("user_name", "TestingAdmin"), ("password", "password")]) - .send() - .await - .unwrap() - .error_for_status() - .unwrap(); - - // Load the authorization page - let response = client - .get(&format!( - "{base_url}login/oauth/authorize\ - ?client_id={client_id}\ - &redirect_uri=http%3A%2F%2F127.0.0.1%3A48879%2F\ - &response_type=code\ - &state=theyve" - )) - .send() - .await - .unwrap() - .error_for_status() - .unwrap(); - let csrf = response.cookies().find(|x| x.name() == "_csrf").unwrap(); - - // Authorize the new application via the web interface - let response = client - .post(&format!("{base_url}login/oauth/grant")) - .form(&[ - ("_csrf", csrf.value()), - ("client_id", &client_id), - ("state", "theyve"), - ("scope", ""), - ("nonce", ""), - ("redirect_uri", "http://127.0.0.1:48879/"), - ]) - .send() - .await - .unwrap() - .error_for_status() - .unwrap(); - - // Extract the code from the redirect url - let location = response.headers().get(reqwest::header::LOCATION).unwrap(); - let location = url::Url::parse(dbg!(location.to_str().unwrap())).unwrap(); - let mut code = None; - for (key, value) in location.query_pairs() { - if key == "code" { - code = Some(value.into_owned()); - } else if key == "error_description" { - panic!("{value}"); - } - } - let code = code.unwrap(); - - // Redeem the code and check it works - let url = url::Url::parse(&base_url).unwrap(); - let api = Forgejo::new(forgejo_api::Auth::None, url.clone()).unwrap(); - - let request = forgejo_api::structs::OAuthTokenRequest::Confidential { - client_id: &client_id, - client_secret: &client_secret, - code: &code, - redirect_uri: url::Url::parse("http://127.0.0.1:48879/").unwrap(), - }; - let token = api.oauth_get_access_token(request).await.unwrap(); - let token_api = - Forgejo::new(forgejo_api::Auth::OAuth2(&token.access_token), url.clone()).unwrap(); - let myself = token_api.user_get_current().await.unwrap(); - assert_eq!(myself.login.as_deref(), Some("TestingAdmin")); - - let request = forgejo_api::structs::OAuthTokenRequest::Refresh { - refresh_token: &token.refresh_token, - client_id: &client_id, - client_secret: &client_secret, - }; - let token = token_api.oauth_get_access_token(request).await.unwrap(); - let token_api = Forgejo::new(forgejo_api::Auth::OAuth2(&token.access_token), url).unwrap(); - let myself = token_api.user_get_current().await.unwrap(); - assert_eq!(myself.login.as_deref(), Some("TestingAdmin")); -} diff --git a/tests/common/mod.rs b/tests/common/mod.rs new file mode 100644 index 0000000..07d772f --- /dev/null +++ b/tests/common/mod.rs @@ -0,0 +1,7 @@ +use forgejo_api::Forgejo; + +pub fn get_api() -> Forgejo { + let url = url::Url::parse(&std::env::var("FORGEJO_API_CI_INSTANCE_URL").unwrap()).unwrap(); + let token = std::env::var("FORGEJO_API_CI_TOKEN").unwrap(); + Forgejo::new(forgejo_api::Auth::Token(&token), url).unwrap() +} diff --git a/tests/repo.rs b/tests/repo.rs new file mode 100644 index 0000000..bce5d77 --- /dev/null +++ b/tests/repo.rs @@ -0,0 +1,242 @@ +use forgejo_api::structs::*; + +mod common; + +#[tokio::test] +async fn repo() { + let api = common::get_api(); + + tokio::fs::create_dir("./test_repo").await.unwrap(); + let git = || { + let mut cmd = std::process::Command::new("git"); + cmd.current_dir("./test_repo"); + cmd + }; + let _ = git() + .args(["config", "--global", "init.defaultBranch", "main"]) + .status() + .unwrap(); + let _ = git().args(["init"]).status().unwrap(); + let _ = git() + .args(["config", "user.name", "TestingAdmin"]) + .status() + .unwrap(); + let _ = git() + .args(["config", "user.email", "admin@noreply.example.org"]) + .status() + .unwrap(); + tokio::fs::write("./test_repo/README.md", "# Test\nThis is a test repo") + .await + .unwrap(); + let _ = git().args(["add", "."]).status().unwrap(); + let _ = git() + .args(["commit", "-m", "initial commit"]) + .status() + .unwrap(); + + let repo_opt = CreateRepoOption { + auto_init: Some(false), + default_branch: Some("main".into()), + description: Some("Test Repo".into()), + gitignores: Some("".into()), + issue_labels: Some("".into()), + license: Some("".into()), + name: "test".into(), + object_format_name: None, + private: Some(false), + readme: None, + template: Some(false), + trust_model: Some(CreateRepoOptionTrustModel::Default), + }; + let remote_repo = api.create_current_user_repo(repo_opt).await.unwrap(); + assert!( + remote_repo.has_pull_requests.unwrap(), + "repo does not accept pull requests" + ); + assert!( + remote_repo.owner.as_ref().unwrap().login.as_ref().unwrap() == "TestingAdmin", + "repo owner is not \"TestingAdmin\"" + ); + assert!( + remote_repo.name.as_ref().unwrap() == "test", + "repo owner is not \"test\"" + ); + tokio::time::sleep(std::time::Duration::from_secs(3)).await; + + let mut remote_url = remote_repo.clone_url.clone().unwrap(); + remote_url.set_username("TestingAdmin").unwrap(); + remote_url.set_password(Some("password")).unwrap(); + let _ = git() + .args(["remote", "add", "origin", remote_url.as_str()]) + .status() + .unwrap(); + let _ = git() + .args(["push", "-u", "origin", "main"]) + .status() + .unwrap(); + + let _ = git().args(["switch", "-c", "test"]).status().unwrap(); + tokio::fs::write( + "./test_repo/example.rs", + "fn add_one(x: u32) -> u32 { x + 1 }", + ) + .await + .unwrap(); + let _ = git().args(["add", "."]).status().unwrap(); + let _ = git().args(["commit", "-m", "egg"]).status().unwrap(); + let _ = git() + .args(["push", "-u", "origin", "test"]) + .status() + .unwrap(); + + let pr_opt = CreatePullRequestOption { + assignee: None, + assignees: Some(vec!["TestingAdmin".into()]), + base: Some("main".into()), + body: Some("This is a test PR".into()), + due_date: None, + head: Some("test".into()), + labels: None, + milestone: None, + title: Some("test pr".into()), + }; + let pr = api + .repo_create_pull_request("TestingAdmin", "test", pr_opt) + .await + .expect("couldn't create pr"); + tokio::time::sleep(std::time::Duration::from_secs(3)).await; + let is_merged = api + .repo_pull_request_is_merged("TestingAdmin", "test", pr.number.unwrap()) + .await + .is_ok(); + assert!(!is_merged, "pr should not yet be merged"); + let pr_files_query = RepoGetPullRequestFilesQuery::default(); + let (_, _) = api + .repo_get_pull_request_files("TestingAdmin", "test", pr.number.unwrap(), pr_files_query) + .await + .unwrap(); + let merge_opt = MergePullRequestOption { + r#do: MergePullRequestOptionDo::Merge, + merge_commit_id: None, + merge_message_field: None, + merge_title_field: None, + delete_branch_after_merge: Some(true), + force_merge: None, + head_commit_id: None, + merge_when_checks_succeed: None, + }; + api.repo_merge_pull_request("TestingAdmin", "test", pr.number.unwrap(), merge_opt) + .await + .expect("couldn't merge pr"); + let is_merged = api + .repo_pull_request_is_merged("TestingAdmin", "test", pr.number.unwrap()) + .await + .is_ok(); + assert!(is_merged, "pr should be merged"); + let _ = git().args(["fetch"]).status().unwrap(); + let _ = git().args(["pull"]).status().unwrap(); + + let query = RepoListReleasesQuery::default(); + assert!( + api.repo_list_releases("TestingAdmin", "test", query) + .await + .unwrap() + .is_empty(), + "there should be no releases yet" + ); + + let tag_opt = CreateTagOption { + message: Some("This is a tag!".into()), + tag_name: "v1.0".into(), + target: None, + }; + api.repo_create_tag("TestingAdmin", "test", tag_opt) + .await + .expect("failed to create tag"); + + let release_opt = CreateReleaseOption { + body: Some("This is a release!".into()), + draft: Some(true), + name: Some("v1.0".into()), + prerelease: Some(false), + tag_name: "v1.0".into(), + target_commitish: None, + }; + let release = api + .repo_create_release("TestingAdmin", "test", release_opt) + .await + .expect("failed to create release"); + let edit_release = EditReleaseOption { + body: None, + draft: Some(false), + name: None, + prerelease: None, + tag_name: None, + target_commitish: None, + }; + api.repo_edit_release("TestingAdmin", "test", release.id.unwrap(), edit_release) + .await + .expect("failed to edit release"); + + let release_by_tag = api + .repo_get_release_by_tag("TestingAdmin", "test", "v1.0") + .await + .expect("failed to find release"); + let release_latest = api + .repo_get_latest_release("TestingAdmin", "test") + .await + .expect("failed to find latest release"); + assert!(release_by_tag == release_latest, "releases not equal"); + + let attachment = api + .repo_create_release_attachment( + "TestingAdmin", + "test", + release.id.unwrap(), + b"This is a file!".to_vec(), + RepoCreateReleaseAttachmentQuery { + name: Some("test.txt".into()), + }, + ) + .await + .expect("failed to create release attachment"); + assert!( + &*api + .download_release_attachment( + "TestingAdmin", + "test", + release.id.unwrap(), + attachment.id.unwrap() + ) + .await + .unwrap() + == b"This is a file!", + "couldn't download attachment" + ); + let _zip_archive = api + .repo_get_archive("TestingAdmin", "test", "v1.0.zip") + .await + .unwrap(); + let _tar_archive = api + .repo_get_archive("TestingAdmin", "test", "v1.0.tar.gz") + .await + .unwrap(); + // check these contents when their return value is fixed + + api.repo_delete_release_attachment( + "TestingAdmin", + "test", + release.id.unwrap(), + attachment.id.unwrap(), + ) + .await + .expect("failed to deleted attachment"); + + api.repo_delete_release("TestingAdmin", "test", release.id.unwrap()) + .await + .expect("failed to delete release"); + + api.repo_delete_tag("TestingAdmin", "test", "v1.0") + .await + .expect("failed to delete release"); +} diff --git a/tests/user.rs b/tests/user.rs new file mode 100644 index 0000000..48e9d18 --- /dev/null +++ b/tests/user.rs @@ -0,0 +1,155 @@ +use forgejo_api::{structs::*, Forgejo}; + +mod common; + +#[tokio::test] +async fn user() { + let api = common::get_api(); + + let myself = api.user_get_current().await.unwrap(); + assert!(myself.is_admin.unwrap(), "user should be admin"); + assert_eq!( + myself.login.as_ref().unwrap(), + "TestingAdmin", + "user should be named \"TestingAdmin\"" + ); + + let myself_indirect = api.user_get("TestingAdmin").await.unwrap(); + assert_eq!( + myself, myself_indirect, + "result of `myself` does not match result of `get_user`" + ); + + let query = UserListFollowingQuery::default(); + let following = api + .user_list_following("TestingAdmin", query) + .await + .unwrap(); + assert_eq!(following, Vec::new(), "following list not empty"); + + let query = UserListFollowersQuery::default(); + let followers = api + .user_list_followers("TestingAdmin", query) + .await + .unwrap(); + assert_eq!(followers, Vec::new(), "follower list not empty"); + + let url = url::Url::parse(&std::env::var("FORGEJO_API_CI_INSTANCE_URL").unwrap()).unwrap(); + let password_api = Forgejo::new( + forgejo_api::Auth::Password { + username: "TestingAdmin", + password: "password", + mfa: None, + }, + url, + ) + .expect("failed to log in using username and password"); + + assert!( + api.user_get_current().await.unwrap() == password_api.user_get_current().await.unwrap(), + "users not equal comparing token-auth and pass-auth" + ); +} + +#[tokio::test] +async fn oauth2_login() { + let api = common::get_api(); + let opt = forgejo_api::structs::CreateOAuth2ApplicationOptions { + confidential_client: Some(true), + name: Some("Test Application".into()), + redirect_uris: Some(vec!["http://127.0.0.1:48879/".into()]), + }; + let app = api.user_create_oauth2_application(opt).await.unwrap(); + let client_id = app.client_id.unwrap(); + let client_secret = app.client_secret.unwrap(); + + let base_url = &std::env::var("FORGEJO_API_CI_INSTANCE_URL").unwrap(); + + let client = reqwest::Client::builder() + .cookie_store(true) + .redirect(reqwest::redirect::Policy::none()) + .build() + .unwrap(); + + // Log in via the web interface + let _ = client + .post(&format!("{base_url}user/login")) + .form(&[("user_name", "TestingAdmin"), ("password", "password")]) + .send() + .await + .unwrap() + .error_for_status() + .unwrap(); + + // Load the authorization page + let response = client + .get(&format!( + "{base_url}login/oauth/authorize\ + ?client_id={client_id}\ + &redirect_uri=http%3A%2F%2F127.0.0.1%3A48879%2F\ + &response_type=code\ + &state=theyve" + )) + .send() + .await + .unwrap() + .error_for_status() + .unwrap(); + let csrf = response.cookies().find(|x| x.name() == "_csrf").unwrap(); + + // Authorize the new application via the web interface + let response = client + .post(&format!("{base_url}login/oauth/grant")) + .form(&[ + ("_csrf", csrf.value()), + ("client_id", &client_id), + ("state", "theyve"), + ("scope", ""), + ("nonce", ""), + ("redirect_uri", "http://127.0.0.1:48879/"), + ]) + .send() + .await + .unwrap() + .error_for_status() + .unwrap(); + + // Extract the code from the redirect url + let location = response.headers().get(reqwest::header::LOCATION).unwrap(); + let location = url::Url::parse(dbg!(location.to_str().unwrap())).unwrap(); + let mut code = None; + for (key, value) in location.query_pairs() { + if key == "code" { + code = Some(value.into_owned()); + } else if key == "error_description" { + panic!("{value}"); + } + } + let code = code.unwrap(); + + // Redeem the code and check it works + let url = url::Url::parse(&base_url).unwrap(); + let api = Forgejo::new(forgejo_api::Auth::None, url.clone()).unwrap(); + + let request = forgejo_api::structs::OAuthTokenRequest::Confidential { + client_id: &client_id, + client_secret: &client_secret, + code: &code, + redirect_uri: url::Url::parse("http://127.0.0.1:48879/").unwrap(), + }; + let token = api.oauth_get_access_token(request).await.unwrap(); + let token_api = + Forgejo::new(forgejo_api::Auth::OAuth2(&token.access_token), url.clone()).unwrap(); + let myself = token_api.user_get_current().await.unwrap(); + assert_eq!(myself.login.as_deref(), Some("TestingAdmin")); + + let request = forgejo_api::structs::OAuthTokenRequest::Refresh { + refresh_token: &token.refresh_token, + client_id: &client_id, + client_secret: &client_secret, + }; + let token = token_api.oauth_get_access_token(request).await.unwrap(); + let token_api = Forgejo::new(forgejo_api::Auth::OAuth2(&token.access_token), url).unwrap(); + let myself = token_api.user_get_current().await.unwrap(); + assert_eq!(myself.login.as_deref(), Some("TestingAdmin")); +} -- cgit v1.2.3 From f159316f031cdb5759bcb7f2b1ce75ac92f9a236 Mon Sep 17 00:00:00 2001 From: Cyborus Date: Tue, 14 May 2024 13:02:52 -0400 Subject: split tests into smaller tests --- tests/admin.rs | 88 +++++++++++++++++++++------ tests/common/mod.rs | 12 +++- tests/repo.rs | 167 ++++++++++++++++++++++++++++++---------------------- tests/user.rs | 78 +++++++++++++++++------- 4 files changed, 237 insertions(+), 108 deletions(-) diff --git a/tests/admin.rs b/tests/admin.rs index a8e7e1d..06aed66 100644 --- a/tests/admin.rs +++ b/tests/admin.rs @@ -3,8 +3,8 @@ use forgejo_api::structs::*; mod common; #[tokio::test] -async fn admin() { - let api = common::get_api(); +async fn user() { + let api = common::login(); let user_opt = CreateUserOption { created_at: None, @@ -48,6 +48,29 @@ async fn admin() { .is_some(), "could not find new user" ); +} + +#[tokio::test] +async fn org() { + let api = common::login(); + + let user_opt = CreateUserOption { + created_at: None, + email: "org-owner@noreply.example.org".into(), + full_name: None, + login_name: None, + must_change_password: None, + password: Some("userpass".into()), + restricted: Some(false), + send_notify: Some(true), + source_id: None, + username: "OrgOwner".into(), + visibility: Some("public".into()), + }; + let _ = api + .admin_create_user(user_opt) + .await + .expect("failed to create user"); let org_opt = CreateOrgOption { description: None, @@ -60,7 +83,7 @@ async fn admin() { website: None, }; let _ = api - .admin_create_org("Pipis", org_opt) + .admin_create_org("OrgOwner", org_opt) .await .expect("failed to create org"); let query = AdminGetAllOrgsQuery::default(); @@ -68,20 +91,6 @@ async fn admin() { !api.admin_get_all_orgs(query).await.unwrap().is_empty(), "org list empty" ); - - let key_opt = CreateKeyOption { - key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN68ehQAsbGEwlXPa2AxbAh1QxFQrtRel2jeC0hRlPc1 user@noreply.example.org".into(), - read_only: None, - title: "Example Key".into(), - }; - let key = api - .admin_create_public_key("Pipis", key_opt) - .await - .expect("failed to create key"); - api.admin_delete_user_public_key("Pipis", key.id.unwrap()) - .await - .expect("failed to delete key"); - let rename_opt = RenameUserOption { new_username: "Bepis".into(), }; @@ -97,6 +106,47 @@ async fn admin() { api.admin_delete_user("Ghost", query).await.is_err(), "deleting fake user should fail" ); +} + +#[tokio::test] +async fn key() { + let api = common::login(); + + let user_opt = CreateUserOption { + created_at: None, + email: "key-holder@noreply.example.org".into(), + full_name: None, + login_name: None, + must_change_password: None, + password: Some("userpass".into()), + restricted: Some(false), + send_notify: Some(true), + source_id: None, + username: "KeyHolder".into(), + visibility: Some("public".into()), + }; + let _ = api + .admin_create_user(user_opt) + .await + .expect("failed to create user"); + + let key_opt = CreateKeyOption { + key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN68ehQAsbGEwlXPa2AxbAh1QxFQrtRel2jeC0hRlPc1 user@noreply.example.org".into(), + read_only: None, + title: "Example Key".into(), + }; + let key = api + .admin_create_public_key("KeyHolder", key_opt) + .await + .expect("failed to create key"); + api.admin_delete_user_public_key("KeyHolder", key.id.unwrap()) + .await + .expect("failed to delete key"); +} + +#[tokio::test] +async fn cron() { + let api = common::login(); let query = AdminCronListQuery::default(); let crons = api @@ -106,7 +156,11 @@ async fn admin() { api.admin_cron_run(&crons.get(0).expect("no crons").name.as_ref().unwrap()) .await .expect("failed to run cron"); +} +#[tokio::test] +async fn hook() { + let api = common::login(); let hook_opt = CreateHookOption { active: None, authorization_header: None, diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 07d772f..63ae02c 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,7 +1,17 @@ use forgejo_api::Forgejo; -pub fn get_api() -> Forgejo { +pub fn login() -> Forgejo { let url = url::Url::parse(&std::env::var("FORGEJO_API_CI_INSTANCE_URL").unwrap()).unwrap(); let token = std::env::var("FORGEJO_API_CI_TOKEN").unwrap(); Forgejo::new(forgejo_api::Auth::Token(&token), url).unwrap() } + +pub fn login_pass(username: &str, password: &str) -> Forgejo { + let url = url::Url::parse(&std::env::var("FORGEJO_API_CI_INSTANCE_URL").unwrap()).unwrap(); + let auth = forgejo_api::Auth::Password { + username, + password, + mfa: None, + }; + Forgejo::new(auth, url).unwrap() +} diff --git a/tests/repo.rs b/tests/repo.rs index bce5d77..a4e3bf5 100644 --- a/tests/repo.rs +++ b/tests/repo.rs @@ -2,37 +2,34 @@ use forgejo_api::structs::*; mod common; -#[tokio::test] -async fn repo() { - let api = common::get_api(); +struct Git { + dir: &'static std::path::Path, +} + +impl Git { + fn new + ?Sized>(path: &'static T) -> Self { + let dir = path.as_ref(); + std::fs::create_dir_all(dir).unwrap(); + Self { dir } + } - tokio::fs::create_dir("./test_repo").await.unwrap(); - let git = || { + fn run(&self, args: &[impl AsRef]) { let mut cmd = std::process::Command::new("git"); - cmd.current_dir("./test_repo"); - cmd - }; - let _ = git() - .args(["config", "--global", "init.defaultBranch", "main"]) - .status() - .unwrap(); - let _ = git().args(["init"]).status().unwrap(); - let _ = git() - .args(["config", "user.name", "TestingAdmin"]) - .status() - .unwrap(); - let _ = git() - .args(["config", "user.email", "admin@noreply.example.org"]) - .status() - .unwrap(); - tokio::fs::write("./test_repo/README.md", "# Test\nThis is a test repo") + cmd.current_dir(self.dir); + let _ = cmd.args(args).status().unwrap(); + } +} + +async fn basic_repo(api: &forgejo_api::Forgejo, git: &Git, name: &str) -> Repository { + git.run(&["config", "--global", "init.defaultBranch", "main"]); + git.run(&["init"]); + git.run(&["config", "user.name", "TestingAdmin"]); + git.run(&["config", "user.email", "admin@noreply.example.org"]); + tokio::fs::write(&git.dir.join("README.md"), "# Test\nThis is a test repo") .await .unwrap(); - let _ = git().args(["add", "."]).status().unwrap(); - let _ = git() - .args(["commit", "-m", "initial commit"]) - .status() - .unwrap(); + git.run(&["add", "."]); + git.run(&["commit", "-m", "initial commit"]); let repo_opt = CreateRepoOption { auto_init: Some(false), @@ -41,7 +38,7 @@ async fn repo() { gitignores: Some("".into()), issue_labels: Some("".into()), license: Some("".into()), - name: "test".into(), + name: name.into(), object_format_name: None, private: Some(false), readme: None, @@ -58,36 +55,36 @@ async fn repo() { "repo owner is not \"TestingAdmin\"" ); assert!( - remote_repo.name.as_ref().unwrap() == "test", - "repo owner is not \"test\"" + remote_repo.name.as_ref().unwrap() == name, + "repo name is not \"{name}\"" ); - tokio::time::sleep(std::time::Duration::from_secs(3)).await; let mut remote_url = remote_repo.clone_url.clone().unwrap(); remote_url.set_username("TestingAdmin").unwrap(); remote_url.set_password(Some("password")).unwrap(); - let _ = git() - .args(["remote", "add", "origin", remote_url.as_str()]) - .status() - .unwrap(); - let _ = git() - .args(["push", "-u", "origin", "main"]) - .status() - .unwrap(); + git.run(&["remote", "add", "origin", remote_url.as_str()]); + git.run(&["push", "-u", "origin", "main"]); + + remote_repo +} + +#[tokio::test] +async fn pull_request() { + let api = common::login(); + + let git = Git::new("./test_repos/pr"); + let _ = basic_repo(&api, &git, "pr-test").await; + git.run(&["switch", "-c", "test"]); - let _ = git().args(["switch", "-c", "test"]).status().unwrap(); tokio::fs::write( - "./test_repo/example.rs", + "./test_repos/pr/example.rs", "fn add_one(x: u32) -> u32 { x + 1 }", ) .await .unwrap(); - let _ = git().args(["add", "."]).status().unwrap(); - let _ = git().args(["commit", "-m", "egg"]).status().unwrap(); - let _ = git() - .args(["push", "-u", "origin", "test"]) - .status() - .unwrap(); + git.run(&["add", "."]); + git.run(&["commit", "-m", "egg"]); + git.run(&["push", "-u", "origin", "test"]); let pr_opt = CreatePullRequestOption { assignee: None, @@ -101,20 +98,27 @@ async fn repo() { title: Some("test pr".into()), }; let pr = api - .repo_create_pull_request("TestingAdmin", "test", pr_opt) + .repo_create_pull_request("TestingAdmin", "pr-test", pr_opt) .await .expect("couldn't create pr"); - tokio::time::sleep(std::time::Duration::from_secs(3)).await; + let is_merged = api - .repo_pull_request_is_merged("TestingAdmin", "test", pr.number.unwrap()) + .repo_pull_request_is_merged("TestingAdmin", "pr-test", pr.number.unwrap()) .await .is_ok(); assert!(!is_merged, "pr should not yet be merged"); + let pr_files_query = RepoGetPullRequestFilesQuery::default(); let (_, _) = api - .repo_get_pull_request_files("TestingAdmin", "test", pr.number.unwrap(), pr_files_query) + .repo_get_pull_request_files( + "TestingAdmin", + "pr-test", + pr.number.unwrap(), + pr_files_query, + ) .await .unwrap(); + let merge_opt = MergePullRequestOption { r#do: MergePullRequestOptionDo::Merge, merge_commit_id: None, @@ -125,20 +129,27 @@ async fn repo() { head_commit_id: None, merge_when_checks_succeed: None, }; - api.repo_merge_pull_request("TestingAdmin", "test", pr.number.unwrap(), merge_opt) + + api.repo_merge_pull_request("TestingAdmin", "pr-test", pr.number.unwrap(), merge_opt) .await .expect("couldn't merge pr"); let is_merged = api - .repo_pull_request_is_merged("TestingAdmin", "test", pr.number.unwrap()) + .repo_pull_request_is_merged("TestingAdmin", "pr-test", pr.number.unwrap()) .await .is_ok(); assert!(is_merged, "pr should be merged"); - let _ = git().args(["fetch"]).status().unwrap(); - let _ = git().args(["pull"]).status().unwrap(); +} + +#[tokio::test] +async fn release() { + let api = common::login(); + + let git = Git::new("./test_repos/release"); + let _ = basic_repo(&api, &git, "release-test").await; let query = RepoListReleasesQuery::default(); assert!( - api.repo_list_releases("TestingAdmin", "test", query) + api.repo_list_releases("TestingAdmin", "release-test", query) .await .unwrap() .is_empty(), @@ -150,7 +161,7 @@ async fn repo() { tag_name: "v1.0".into(), target: None, }; - api.repo_create_tag("TestingAdmin", "test", tag_opt) + api.repo_create_tag("TestingAdmin", "release-test", tag_opt) .await .expect("failed to create tag"); @@ -163,7 +174,7 @@ async fn repo() { target_commitish: None, }; let release = api - .repo_create_release("TestingAdmin", "test", release_opt) + .repo_create_release("TestingAdmin", "release-test", release_opt) .await .expect("failed to create release"); let edit_release = EditReleaseOption { @@ -174,16 +185,21 @@ async fn repo() { tag_name: None, target_commitish: None, }; - api.repo_edit_release("TestingAdmin", "test", release.id.unwrap(), edit_release) - .await - .expect("failed to edit release"); + api.repo_edit_release( + "TestingAdmin", + "release-test", + release.id.unwrap(), + edit_release, + ) + .await + .expect("failed to edit release"); let release_by_tag = api - .repo_get_release_by_tag("TestingAdmin", "test", "v1.0") + .repo_get_release_by_tag("TestingAdmin", "release-test", "v1.0") .await .expect("failed to find release"); let release_latest = api - .repo_get_latest_release("TestingAdmin", "test") + .repo_get_latest_release("TestingAdmin", "release-test") .await .expect("failed to find latest release"); assert!(release_by_tag == release_latest, "releases not equal"); @@ -191,7 +207,7 @@ async fn repo() { let attachment = api .repo_create_release_attachment( "TestingAdmin", - "test", + "release-test", release.id.unwrap(), b"This is a file!".to_vec(), RepoCreateReleaseAttachmentQuery { @@ -204,7 +220,7 @@ async fn repo() { &*api .download_release_attachment( "TestingAdmin", - "test", + "release-test", release.id.unwrap(), attachment.id.unwrap() ) @@ -214,29 +230,40 @@ async fn repo() { "couldn't download attachment" ); let _zip_archive = api - .repo_get_archive("TestingAdmin", "test", "v1.0.zip") + .repo_get_archive("TestingAdmin", "release-test", "v1.0.zip") .await .unwrap(); let _tar_archive = api - .repo_get_archive("TestingAdmin", "test", "v1.0.tar.gz") + .repo_get_archive("TestingAdmin", "release-test", "v1.0.tar.gz") .await .unwrap(); // check these contents when their return value is fixed api.repo_delete_release_attachment( "TestingAdmin", - "test", + "release-test", release.id.unwrap(), attachment.id.unwrap(), ) .await .expect("failed to deleted attachment"); - api.repo_delete_release("TestingAdmin", "test", release.id.unwrap()) + api.repo_delete_release("TestingAdmin", "release-test", release.id.unwrap()) .await .expect("failed to delete release"); - api.repo_delete_tag("TestingAdmin", "test", "v1.0") + api.repo_delete_tag("TestingAdmin", "release-test", "v1.0") .await .expect("failed to delete release"); } + +#[tokio::test] +async fn delete_repo() { + let api = common::login(); + let git = Git::new("./test_repos/delete"); + let _ = basic_repo(&api, &git, "delete-test").await; + + api.repo_delete("TestingAdmin", "delete-test") + .await + .expect("failed to delete repo"); +} diff --git a/tests/user.rs b/tests/user.rs index 48e9d18..fb02088 100644 --- a/tests/user.rs +++ b/tests/user.rs @@ -1,10 +1,10 @@ -use forgejo_api::{structs::*, Forgejo}; +use forgejo_api::structs::*; mod common; #[tokio::test] -async fn user() { - let api = common::get_api(); +async fn myself() { + let api = common::login(); let myself = api.user_get_current().await.unwrap(); assert!(myself.is_admin.unwrap(), "user should be admin"); @@ -19,31 +19,67 @@ async fn user() { myself, myself_indirect, "result of `myself` does not match result of `get_user`" ); +} + +#[tokio::test] +async fn follow() { + let api = common::login(); let query = UserListFollowingQuery::default(); let following = api .user_list_following("TestingAdmin", query) .await .unwrap(); - assert_eq!(following, Vec::new(), "following list not empty"); + assert!(following.is_empty(), "following list not empty"); let query = UserListFollowersQuery::default(); let followers = api .user_list_followers("TestingAdmin", query) .await .unwrap(); - assert_eq!(followers, Vec::new(), "follower list not empty"); - - let url = url::Url::parse(&std::env::var("FORGEJO_API_CI_INSTANCE_URL").unwrap()).unwrap(); - let password_api = Forgejo::new( - forgejo_api::Auth::Password { - username: "TestingAdmin", - password: "password", - mfa: None, - }, - url, - ) - .expect("failed to log in using username and password"); + assert!(followers.is_empty(), "follower list not empty"); + + let option = CreateUserOption { + created_at: None, + email: "follower@testing".into(), + full_name: None, + login_name: None, + must_change_password: Some(false), + password: Some("password".into()), + restricted: None, + send_notify: None, + source_id: None, + username: "Follower".into(), + visibility: None, + }; + let _ = api.admin_create_user(option).await.unwrap(); + let new_user = common::login_pass("Follower", "password"); + + new_user + .user_current_put_follow("TestingAdmin") + .await + .unwrap(); + api.user_current_put_follow("Follower").await.unwrap(); + + let query = UserListFollowingQuery::default(); + let following = api + .user_list_following("TestingAdmin", query) + .await + .unwrap(); + assert!(!following.is_empty(), "following list empty"); + + let query = UserListFollowersQuery::default(); + let followers = api + .user_list_followers("TestingAdmin", query) + .await + .unwrap(); + assert!(!followers.is_empty(), "follower list empty"); +} + +#[tokio::test] +async fn password_login() { + let api = common::login(); + let password_api = common::login_pass("TestingAdmin", "password"); assert!( api.user_get_current().await.unwrap() == password_api.user_get_current().await.unwrap(), @@ -53,7 +89,7 @@ async fn user() { #[tokio::test] async fn oauth2_login() { - let api = common::get_api(); + let api = common::login(); let opt = forgejo_api::structs::CreateOAuth2ApplicationOptions { confidential_client: Some(true), name: Some("Test Application".into()), @@ -129,7 +165,7 @@ async fn oauth2_login() { // Redeem the code and check it works let url = url::Url::parse(&base_url).unwrap(); - let api = Forgejo::new(forgejo_api::Auth::None, url.clone()).unwrap(); + let api = forgejo_api::Forgejo::new(forgejo_api::Auth::None, url.clone()).unwrap(); let request = forgejo_api::structs::OAuthTokenRequest::Confidential { client_id: &client_id, @@ -139,7 +175,8 @@ async fn oauth2_login() { }; let token = api.oauth_get_access_token(request).await.unwrap(); let token_api = - Forgejo::new(forgejo_api::Auth::OAuth2(&token.access_token), url.clone()).unwrap(); + forgejo_api::Forgejo::new(forgejo_api::Auth::OAuth2(&token.access_token), url.clone()) + .unwrap(); let myself = token_api.user_get_current().await.unwrap(); assert_eq!(myself.login.as_deref(), Some("TestingAdmin")); @@ -149,7 +186,8 @@ async fn oauth2_login() { client_secret: &client_secret, }; let token = token_api.oauth_get_access_token(request).await.unwrap(); - let token_api = Forgejo::new(forgejo_api::Auth::OAuth2(&token.access_token), url).unwrap(); + let token_api = + forgejo_api::Forgejo::new(forgejo_api::Auth::OAuth2(&token.access_token), url).unwrap(); let myself = token_api.user_get_current().await.unwrap(); assert_eq!(myself.login.as_deref(), Some("TestingAdmin")); } -- cgit v1.2.3 From 1c3bd75c824d9abc4141f684b4f9821552f4049d Mon Sep 17 00:00:00 2001 From: Cyborus Date: Mon, 27 May 2024 12:30:04 -0400 Subject: add delays to allow forgejo's state to settle --- tests/repo.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/repo.rs b/tests/repo.rs index a4e3bf5..004cb8e 100644 --- a/tests/repo.rs +++ b/tests/repo.rs @@ -97,6 +97,9 @@ async fn pull_request() { milestone: None, title: Some("test pr".into()), }; + + // Wait for... something to happen, or else creating a PR will return 404 + tokio::time::sleep(std::time::Duration::from_secs(3)).await; let pr = api .repo_create_pull_request("TestingAdmin", "pr-test", pr_opt) .await @@ -147,6 +150,10 @@ async fn release() { let git = Git::new("./test_repos/release"); let _ = basic_repo(&api, &git, "release-test").await; + // Wait for the repo to be finished being populated, or else creating a + // release will return "422 repo is empty" + tokio::time::sleep(std::time::Duration::from_secs(3)).await; + let query = RepoListReleasesQuery::default(); assert!( api.repo_list_releases("TestingAdmin", "release-test", query) -- cgit v1.2.3 From 635a5b55dd8eff02c91a7c70ce6951c35e2b0667 Mon Sep 17 00:00:00 2001 From: Cyborus Date: Mon, 27 May 2024 13:09:01 -0400 Subject: fix follower account email Should be a valid email, but I guess Forgejo is stricter than that --- tests/user.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/user.rs b/tests/user.rs index fb02088..9ca808d 100644 --- a/tests/user.rs +++ b/tests/user.rs @@ -41,7 +41,7 @@ async fn follow() { let option = CreateUserOption { created_at: None, - email: "follower@testing".into(), + email: "follower@no-reply.example.org".into(), full_name: None, login_name: None, must_change_password: Some(false), -- cgit v1.2.3 From dc96dd55496db20187bf0d01b3dd88cd72165a0d Mon Sep 17 00:00:00 2001 From: Cyborus Date: Mon, 27 May 2024 13:09:51 -0400 Subject: fix basic auth base64 encoding length calculation --- src/lib.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a87a696..d9b877e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -99,11 +99,13 @@ impl Forgejo { password, mfa, } => { - let len = (((username.len() + password.len() + 1) + let unencoded_len = username.len() + password.len() + 1; + let unpadded_len = unencoded_len .checked_mul(4) - .ok_or(ForgejoError::AuthTooLong)?) - / 3) - + 1; + .ok_or(ForgejoError::AuthTooLong)? + .div_ceil(3); + // round up to next multiple of 4, to account for padding + let len = unpadded_len.div_ceil(4) * 4; let mut bytes = vec![0; len]; // panic safety: len cannot be zero -- cgit v1.2.3 From c9db701b09a2789e8daeba383e647c003db7a3b7 Mon Sep 17 00:00:00 2001 From: Cyborus Date: Mon, 27 May 2024 13:11:03 -0400 Subject: add `/test_repos` to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ea8c4bf..821a346 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +/test_repos -- cgit v1.2.3