aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/e2e/e2e_test.go11
-rw-r--r--tests/e2e/utils_e2e.ts11
-rw-r--r--tests/e2e/utils_e2e_test.go2
-rw-r--r--tests/fuzz/fuzz_test.go2
-rwxr-xr-xtests/gitea-repositories-meta/user2/git_hooks_test.git/hooks/pre-receive.d/pre-receive3
-rw-r--r--tests/gitea-repositories-meta/user2/test_commit_revert.git/HEAD1
-rw-r--r--tests/gitea-repositories-meta/user2/test_commit_revert.git/config8
-rw-r--r--tests/gitea-repositories-meta/user2/test_commit_revert.git/objects/pack/pack-91200c8e6707636a6cc3e0d8101fba08b19dcb91.idxbin1268 -> 0 bytes
-rw-r--r--tests/gitea-repositories-meta/user2/test_commit_revert.git/objects/pack/pack-91200c8e6707636a6cc3e0d8101fba08b19dcb91.packbin609 -> 0 bytes
-rw-r--r--tests/gitea-repositories-meta/user2/test_commit_revert.git/packed-refs3
-rw-r--r--tests/gitea-repositories-meta/user2/test_commit_revert.git/refs/heads/main1
-rw-r--r--tests/integration/actions_delete_run_test.go181
-rw-r--r--tests/integration/actions_job_test.go644
-rw-r--r--tests/integration/actions_log_test.go226
-rw-r--r--tests/integration/actions_runner_modify_test.go150
-rw-r--r--tests/integration/actions_runner_test.go156
-rw-r--r--tests/integration/actions_trigger_test.go1275
-rw-r--r--tests/integration/actions_variables_test.go148
-rw-r--r--tests/integration/admin_user_test.go42
-rw-r--r--tests/integration/api_actions_artifact_v4_test.go275
-rw-r--r--tests/integration/api_actions_run_test.go136
-rw-r--r--tests/integration/api_actions_runner_test.go342
-rw-r--r--tests/integration/api_activitypub_person_test.go60
-rw-r--r--tests/integration/api_admin_org_test.go53
-rw-r--r--tests/integration/api_admin_test.go14
-rw-r--r--tests/integration/api_branch_test.go67
-rw-r--r--tests/integration/api_comment_test.go8
-rw-r--r--tests/integration/api_fork_test.go41
-rw-r--r--tests/integration/api_gitignore_templates_test.go3
-rw-r--r--tests/integration/api_gpg_keys_test.go12
-rw-r--r--tests/integration/api_helper_for_declarative_test.go13
-rw-r--r--tests/integration/api_issue_label_test.go44
-rw-r--r--tests/integration/api_issue_lock_test.go74
-rw-r--r--tests/integration/api_issue_milestone_test.go2
-rw-r--r--tests/integration/api_issue_stopwatch_test.go10
-rw-r--r--tests/integration/api_issue_subscription_test.go8
-rw-r--r--tests/integration/api_issue_test.go16
-rw-r--r--tests/integration/api_issue_tracked_time_test.go6
-rw-r--r--tests/integration/api_keys_test.go4
-rw-r--r--tests/integration/api_label_templates_test.go3
-rw-r--r--tests/integration/api_license_templates_test.go3
-rw-r--r--tests/integration/api_nodeinfo_test.go34
-rw-r--r--tests/integration/api_notification_test.go8
-rw-r--r--tests/integration/api_oauth2_apps_test.go20
-rw-r--r--tests/integration/api_org_test.go232
-rw-r--r--tests/integration/api_packages_arch_test.go94
-rw-r--r--tests/integration/api_packages_cargo_test.go2
-rw-r--r--tests/integration/api_packages_chef_test.go12
-rw-r--r--tests/integration/api_packages_composer_test.go37
-rw-r--r--tests/integration/api_packages_conan_test.go54
-rw-r--r--tests/integration/api_packages_conda_test.go10
-rw-r--r--tests/integration/api_packages_container_test.go137
-rw-r--r--tests/integration/api_packages_cran_test.go8
-rw-r--r--tests/integration/api_packages_debian_test.go2
-rw-r--r--tests/integration/api_packages_generic_test.go43
-rw-r--r--tests/integration/api_packages_goproxy_test.go2
-rw-r--r--tests/integration/api_packages_helm_test.go4
-rw-r--r--tests/integration/api_packages_maven_test.go124
-rw-r--r--tests/integration/api_packages_npm_test.go49
-rw-r--r--tests/integration/api_packages_nuget_test.go201
-rw-r--r--tests/integration/api_packages_pub_test.go2
-rw-r--r--tests/integration/api_packages_pypi_test.go69
-rw-r--r--tests/integration/api_packages_rpm_test.go14
-rw-r--r--tests/integration/api_packages_rubygems_test.go8
-rw-r--r--tests/integration/api_packages_swift_test.go98
-rw-r--r--tests/integration/api_packages_test.go147
-rw-r--r--tests/integration/api_packages_vagrant_test.go4
-rw-r--r--tests/integration/api_private_serv_test.go4
-rw-r--r--tests/integration/api_pull_commits_test.go5
-rw-r--r--tests/integration/api_pull_review_test.go44
-rw-r--r--tests/integration/api_pull_test.go169
-rw-r--r--tests/integration/api_releases_test.go10
-rw-r--r--tests/integration/api_repo_archive_test.go21
-rw-r--r--tests/integration/api_repo_branch_test.go32
-rw-r--r--tests/integration/api_repo_collaborator_test.go188
-rw-r--r--tests/integration/api_repo_edit_test.go57
-rw-r--r--tests/integration/api_repo_file_create_test.go142
-rw-r--r--tests/integration/api_repo_file_delete_test.go32
-rw-r--r--tests/integration/api_repo_file_get_test.go2
-rw-r--r--tests/integration/api_repo_file_update_test.go89
-rw-r--r--tests/integration/api_repo_files_change_test.go118
-rw-r--r--tests/integration/api_repo_files_get_test.go157
-rw-r--r--tests/integration/api_repo_get_contents_list_test.go55
-rw-r--r--tests/integration/api_repo_get_contents_test.go226
-rw-r--r--tests/integration/api_repo_git_blobs_test.go4
-rw-r--r--tests/integration/api_repo_git_commits_test.go22
-rw-r--r--tests/integration/api_repo_git_hook_test.go343
-rw-r--r--tests/integration/api_repo_git_tags_test.go4
-rw-r--r--tests/integration/api_repo_git_trees_test.go28
-rw-r--r--tests/integration/api_repo_languages_test.go5
-rw-r--r--tests/integration/api_repo_lfs_locks_test.go8
-rw-r--r--tests/integration/api_repo_lfs_migrate_test.go2
-rw-r--r--tests/integration/api_repo_lfs_test.go7
-rw-r--r--tests/integration/api_repo_license_test.go6
-rw-r--r--tests/integration/api_repo_raw_test.go4
-rw-r--r--tests/integration/api_repo_secrets_test.go27
-rw-r--r--tests/integration/api_repo_tags_test.go10
-rw-r--r--tests/integration/api_repo_teams_test.go12
-rw-r--r--tests/integration/api_repo_test.go53
-rw-r--r--tests/integration/api_repo_topic_test.go10
-rw-r--r--tests/integration/api_repo_variables_test.go8
-rw-r--r--tests/integration/api_settings_test.go7
-rw-r--r--tests/integration/api_team_test.go24
-rw-r--r--tests/integration/api_team_user_test.go52
-rw-r--r--tests/integration/api_token_test.go2
-rw-r--r--tests/integration/api_twofa_test.go2
-rw-r--r--tests/integration/api_user_block_test.go18
-rw-r--r--tests/integration/api_user_email_test.go6
-rw-r--r--tests/integration/api_user_follow_test.go8
-rw-r--r--tests/integration/api_user_info_test.go9
-rw-r--r--tests/integration/api_user_search_test.go8
-rw-r--r--tests/integration/api_user_secrets_test.go7
-rw-r--r--tests/integration/api_user_star_test.go74
-rw-r--r--tests/integration/api_user_variables_test.go17
-rw-r--r--tests/integration/api_wiki_test.go24
-rw-r--r--tests/integration/auth_ldap_test.go22
-rw-r--r--tests/integration/benchmarks_test.go69
-rw-r--r--tests/integration/change_default_branch_test.go97
-rw-r--r--tests/integration/cmd_keys_test.go17
-rw-r--r--tests/integration/compare_test.go6
-rw-r--r--tests/integration/db_collation_test.go2
-rw-r--r--tests/integration/delete_user_test.go5
-rw-r--r--tests/integration/dump_restore_test.go31
-rw-r--r--tests/integration/editor_test.go532
-rw-r--r--tests/integration/empty_repo_test.go71
-rw-r--r--tests/integration/ephemeral_actions_runner_deletion_test.go77
-rw-r--r--tests/integration/feed_repo_test.go35
-rw-r--r--tests/integration/feed_user_test.go (renamed from tests/integration/api_feed_user_test.go)25
-rw-r--r--tests/integration/git_general_test.go263
-rw-r--r--tests/integration/git_helper_for_declarative_test.go33
-rw-r--r--tests/integration/git_lfs_ssh_test.go10
-rw-r--r--tests/integration/git_misc_test.go117
-rw-r--r--tests/integration/git_push_test.go20
-rw-r--r--tests/integration/git_smart_http_test.go64
-rw-r--r--tests/integration/gpg_ssh_git_test.go (renamed from tests/integration/gpg_git_test.go)99
-rw-r--r--tests/integration/html_helper.go13
-rw-r--r--tests/integration/incoming_email_test.go4
-rw-r--r--tests/integration/integration_test.go95
-rw-r--r--tests/integration/issue_test.go73
-rw-r--r--tests/integration/lfs_local_endpoint_test.go27
-rw-r--r--tests/integration/lfs_view_test.go18
-rw-r--r--tests/integration/linguist_test.go3
-rw-r--r--tests/integration/links_test.go81
-rw-r--r--tests/integration/markup_external_test.go14
-rw-r--r--tests/integration/migrate_test.go11
-rw-r--r--tests/integration/migration-test/migration_test.go28
-rw-r--r--tests/integration/mirror_pull_test.go37
-rw-r--r--tests/integration/mirror_push_test.go22
-rw-r--r--tests/integration/nonascii_branches_test.go40
-rw-r--r--tests/integration/oauth_test.go164
-rw-r--r--tests/integration/org_count_test.go11
-rw-r--r--tests/integration/org_profile_test.go132
-rw-r--r--tests/integration/org_team_invite_test.go21
-rw-r--r--tests/integration/org_test.go45
-rw-r--r--tests/integration/org_worktime_test.go293
-rw-r--r--tests/integration/project_test.go10
-rw-r--r--tests/integration/pull_commit_test.go41
-rw-r--r--tests/integration/pull_compare_test.go64
-rw-r--r--tests/integration/pull_create_test.go91
-rw-r--r--tests/integration/pull_diff_test.go4
-rw-r--r--tests/integration/pull_merge_test.go131
-rw-r--r--tests/integration/pull_review_test.go42
-rw-r--r--tests/integration/pull_status_test.go106
-rw-r--r--tests/integration/pull_update_test.go32
-rw-r--r--tests/integration/release_test.go48
-rw-r--r--tests/integration/rename_branch_test.go11
-rw-r--r--tests/integration/repo_activity_test.go13
-rw-r--r--tests/integration/repo_branch_test.go116
-rw-r--r--tests/integration/repo_commits_search_test.go2
-rw-r--r--tests/integration/repo_commits_test.go88
-rw-r--r--tests/integration/repo_fork_test.go20
-rw-r--r--tests/integration/repo_generate_test.go11
-rw-r--r--tests/integration/repo_merge_upstream_test.go183
-rw-r--r--tests/integration/repo_mergecommit_revert_test.go37
-rw-r--r--tests/integration/repo_search_test.go2
-rw-r--r--tests/integration/repo_tag_test.go22
-rw-r--r--tests/integration/repo_test.go313
-rw-r--r--tests/integration/repo_topic_test.go10
-rw-r--r--tests/integration/repo_webhook_test.go1254
-rw-r--r--tests/integration/repofiles_change_test.go320
-rw-r--r--tests/integration/session_test.go4
-rw-r--r--tests/integration/setting_test.go6
-rw-r--r--tests/integration/signin_test.go91
-rw-r--r--tests/integration/signup_test.go35
-rw-r--r--tests/integration/ssh_key_test.go6
-rw-r--r--tests/integration/timetracking_test.go22
-rw-r--r--tests/integration/user_avatar_test.go96
-rw-r--r--tests/integration/user_settings_test.go48
-rw-r--r--tests/integration/user_test.go29
-rw-r--r--tests/integration/view_test.go40
-rw-r--r--tests/integration/webfinger_test.go12
-rw-r--r--tests/integration/wiki_test.go10
-rw-r--r--tests/integration/workflow_run_api_check_test.go167
-rw-r--r--tests/integration/xss_test.go4
-rw-r--r--tests/mssql.ini.tmpl8
-rw-r--r--tests/mysql.ini.tmpl8
-rw-r--r--tests/pgsql.ini.tmpl8
-rw-r--r--tests/sqlite.ini.tmpl8
-rw-r--r--tests/test_utils.go15
199 files changed, 11046 insertions, 2904 deletions
diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go
index 78e42777bb..4a408dbd7b 100644
--- a/tests/e2e/e2e_test.go
+++ b/tests/e2e/e2e_test.go
@@ -4,7 +4,7 @@
// This is primarily coped from /tests/integration/integration_test.go
// TODO: Move common functions to shared file
-//nolint:forbidigo
+//nolint:forbidigo // use of print functions is allowed in tests
package e2e
import (
@@ -40,13 +40,6 @@ func TestMain(m *testing.M) {
tests.InitTest(false)
testE2eWebRoutes = routers.NormalRoutes()
- os.Unsetenv("GIT_AUTHOR_NAME")
- os.Unsetenv("GIT_AUTHOR_EMAIL")
- os.Unsetenv("GIT_AUTHOR_DATE")
- os.Unsetenv("GIT_COMMITTER_NAME")
- os.Unsetenv("GIT_COMMITTER_EMAIL")
- os.Unsetenv("GIT_COMMITTER_DATE")
-
err := unittest.InitFixtures(
unittest.FixturesOptions{
Dir: filepath.Join(filepath.Dir(setting.AppPath), "models/fixtures/"),
@@ -101,7 +94,7 @@ func TestE2e(t *testing.T) {
onGiteaRun(t, func(*testing.T, *url.URL) {
cmd := exec.Command(runArgs[0], runArgs...)
cmd.Env = os.Environ()
- cmd.Env = append(cmd.Env, fmt.Sprintf("GITEA_URL=%s", setting.AppURL))
+ cmd.Env = append(cmd.Env, "GITEA_URL="+setting.AppURL)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
diff --git a/tests/e2e/utils_e2e.ts b/tests/e2e/utils_e2e.ts
index 14ec836600..3e92e0d3c2 100644
--- a/tests/e2e/utils_e2e.ts
+++ b/tests/e2e/utils_e2e.ts
@@ -1,12 +1,13 @@
import {expect} from '@playwright/test';
import {env} from 'node:process';
+import type {Browser, Page, WorkerInfo} from '@playwright/test';
const ARTIFACTS_PATH = `tests/e2e/test-artifacts`;
const LOGIN_PASSWORD = 'password';
// log in user and store session info. This should generally be
// run in test.beforeAll(), then the session can be loaded in tests.
-export async function login_user(browser, workerInfo, user) {
+export async function login_user(browser: Browser, workerInfo: WorkerInfo, user: string) {
// Set up a new context
const context = await browser.newContext();
const page = await context.newPage();
@@ -17,8 +18,8 @@ export async function login_user(browser, workerInfo, user) {
expect(response?.status()).toBe(200); // Status OK
// Fill out form
- await page.type('input[name=user_name]', user);
- await page.type('input[name=password]', LOGIN_PASSWORD);
+ await page.locator('input[name=user_name]').fill(user);
+ await page.locator('input[name=password]').fill(LOGIN_PASSWORD);
await page.click('form button.ui.primary.button:visible');
await page.waitForLoadState('networkidle'); // eslint-disable-line playwright/no-networkidle
@@ -31,7 +32,7 @@ export async function login_user(browser, workerInfo, user) {
return context;
}
-export async function load_logged_in_context(browser, workerInfo, user) {
+export async function load_logged_in_context(browser: Browser, workerInfo: WorkerInfo, user: string) {
let context;
try {
context = await browser.newContext({storageState: `${ARTIFACTS_PATH}/state-${user}-${workerInfo.workerIndex}.json`});
@@ -43,7 +44,7 @@ export async function load_logged_in_context(browser, workerInfo, user) {
return context;
}
-export async function save_visual(page) {
+export async function save_visual(page: Page) {
// Optionally include visual testing
if (env.VISUAL_TEST) {
await page.waitForLoadState('networkidle'); // eslint-disable-line playwright/no-networkidle
diff --git a/tests/e2e/utils_e2e_test.go b/tests/e2e/utils_e2e_test.go
index efb4a6ba88..5ba05f3453 100644
--- a/tests/e2e/utils_e2e_test.go
+++ b/tests/e2e/utils_e2e_test.go
@@ -38,7 +38,7 @@ func onGiteaRunTB(t testing.TB, callback func(testing.TB, *url.URL), prepare ...
u.Host = listener.Addr().String()
defer func() {
- ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
+ ctx, cancel := context.WithTimeout(t.Context(), 2*time.Minute)
s.Shutdown(ctx)
cancel()
}()
diff --git a/tests/fuzz/fuzz_test.go b/tests/fuzz/fuzz_test.go
index 01d562d995..e7b832412a 100644
--- a/tests/fuzz/fuzz_test.go
+++ b/tests/fuzz/fuzz_test.go
@@ -19,6 +19,7 @@ func newFuzzRenderContext() *markup.RenderContext {
func FuzzMarkdownRenderRaw(f *testing.F) {
f.Fuzz(func(t *testing.T, data []byte) {
+ setting.IsInTesting = true
setting.AppURL = "http://localhost:3000/"
markdown.RenderRaw(newFuzzRenderContext(), bytes.NewReader(data), io.Discard)
})
@@ -26,6 +27,7 @@ func FuzzMarkdownRenderRaw(f *testing.F) {
func FuzzMarkupPostProcess(f *testing.F) {
f.Fuzz(func(t *testing.T, data []byte) {
+ setting.IsInTesting = true
setting.AppURL = "http://localhost:3000/"
markup.PostProcessDefault(newFuzzRenderContext(), bytes.NewReader(data), io.Discard)
})
diff --git a/tests/gitea-repositories-meta/user2/git_hooks_test.git/hooks/pre-receive.d/pre-receive b/tests/gitea-repositories-meta/user2/git_hooks_test.git/hooks/pre-receive.d/pre-receive
index b26a3b9b68..205086810d 100755
--- a/tests/gitea-repositories-meta/user2/git_hooks_test.git/hooks/pre-receive.d/pre-receive
+++ b/tests/gitea-repositories-meta/user2/git_hooks_test.git/hooks/pre-receive.d/pre-receive
@@ -1,3 +1,2 @@
#!/bin/bash
-
-echo Hello, World!
+echo "TestGitHookScript"
diff --git a/tests/gitea-repositories-meta/user2/test_commit_revert.git/HEAD b/tests/gitea-repositories-meta/user2/test_commit_revert.git/HEAD
deleted file mode 100644
index b870d82622..0000000000
--- a/tests/gitea-repositories-meta/user2/test_commit_revert.git/HEAD
+++ /dev/null
@@ -1 +0,0 @@
-ref: refs/heads/main
diff --git a/tests/gitea-repositories-meta/user2/test_commit_revert.git/config b/tests/gitea-repositories-meta/user2/test_commit_revert.git/config
deleted file mode 100644
index 57bbcba5be..0000000000
--- a/tests/gitea-repositories-meta/user2/test_commit_revert.git/config
+++ /dev/null
@@ -1,8 +0,0 @@
-[core]
- repositoryformatversion = 0
- filemode = true
- bare = true
- ignorecase = true
- precomposeunicode = true
-[remote "origin"]
- url = https://try.gitea.io/me-heer/test_commit_revert.git
diff --git a/tests/gitea-repositories-meta/user2/test_commit_revert.git/objects/pack/pack-91200c8e6707636a6cc3e0d8101fba08b19dcb91.idx b/tests/gitea-repositories-meta/user2/test_commit_revert.git/objects/pack/pack-91200c8e6707636a6cc3e0d8101fba08b19dcb91.idx
deleted file mode 100644
index 77bcbe7fb4..0000000000
--- a/tests/gitea-repositories-meta/user2/test_commit_revert.git/objects/pack/pack-91200c8e6707636a6cc3e0d8101fba08b19dcb91.idx
+++ /dev/null
Binary files differ
diff --git a/tests/gitea-repositories-meta/user2/test_commit_revert.git/objects/pack/pack-91200c8e6707636a6cc3e0d8101fba08b19dcb91.pack b/tests/gitea-repositories-meta/user2/test_commit_revert.git/objects/pack/pack-91200c8e6707636a6cc3e0d8101fba08b19dcb91.pack
deleted file mode 100644
index 7271cdaeb8..0000000000
--- a/tests/gitea-repositories-meta/user2/test_commit_revert.git/objects/pack/pack-91200c8e6707636a6cc3e0d8101fba08b19dcb91.pack
+++ /dev/null
Binary files differ
diff --git a/tests/gitea-repositories-meta/user2/test_commit_revert.git/packed-refs b/tests/gitea-repositories-meta/user2/test_commit_revert.git/packed-refs
deleted file mode 100644
index 1f546d7fd5..0000000000
--- a/tests/gitea-repositories-meta/user2/test_commit_revert.git/packed-refs
+++ /dev/null
@@ -1,3 +0,0 @@
-# pack-refs with: peeled fully-peeled sorted
-46aa6ab2c881ae90e15d9ccfc947d1625c892ce5 refs/heads/develop
-deebcbc752e540bab4ce3ee713d3fc8fdc35b2f7 refs/heads/main
diff --git a/tests/gitea-repositories-meta/user2/test_commit_revert.git/refs/heads/main b/tests/gitea-repositories-meta/user2/test_commit_revert.git/refs/heads/main
deleted file mode 100644
index ab80ca3ca6..0000000000
--- a/tests/gitea-repositories-meta/user2/test_commit_revert.git/refs/heads/main
+++ /dev/null
@@ -1 +0,0 @@
-deebcbc752e540bab4ce3ee713d3fc8fdc35b2f7
diff --git a/tests/integration/actions_delete_run_test.go b/tests/integration/actions_delete_run_test.go
new file mode 100644
index 0000000000..22f9a1f740
--- /dev/null
+++ b/tests/integration/actions_delete_run_test.go
@@ -0,0 +1,181 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package integration
+
+import (
+ "fmt"
+ "net/http"
+ "net/url"
+ "testing"
+ "time"
+
+ actions_model "code.gitea.io/gitea/models/actions"
+ auth_model "code.gitea.io/gitea/models/auth"
+ "code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/json"
+ "code.gitea.io/gitea/routers/web/repo/actions"
+
+ runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
+ "github.com/stretchr/testify/assert"
+ "google.golang.org/protobuf/types/known/timestamppb"
+)
+
+func TestActionsDeleteRun(t *testing.T) {
+ now := time.Now()
+ testCase := struct {
+ treePath string
+ fileContent string
+ outcomes map[string]*mockTaskOutcome
+ expectedStatuses map[string]string
+ }{
+ treePath: ".gitea/workflows/test1.yml",
+ fileContent: `name: test1
+on:
+ push:
+ paths:
+ - .gitea/workflows/test1.yml
+jobs:
+ job1:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo job1
+ job2:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo job2
+ job3:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo job3
+`,
+ outcomes: map[string]*mockTaskOutcome{
+ "job1": {
+ result: runnerv1.Result_RESULT_SUCCESS,
+ logRows: []*runnerv1.LogRow{
+ {
+ Time: timestamppb.New(now.Add(4 * time.Second)),
+ Content: " \U0001F433 docker create image",
+ },
+ {
+ Time: timestamppb.New(now.Add(5 * time.Second)),
+ Content: "job1",
+ },
+ {
+ Time: timestamppb.New(now.Add(6 * time.Second)),
+ Content: "\U0001F3C1 Job succeeded",
+ },
+ },
+ },
+ "job2": {
+ result: runnerv1.Result_RESULT_SUCCESS,
+ logRows: []*runnerv1.LogRow{
+ {
+ Time: timestamppb.New(now.Add(4 * time.Second)),
+ Content: " \U0001F433 docker create image",
+ },
+ {
+ Time: timestamppb.New(now.Add(5 * time.Second)),
+ Content: "job2",
+ },
+ {
+ Time: timestamppb.New(now.Add(6 * time.Second)),
+ Content: "\U0001F3C1 Job succeeded",
+ },
+ },
+ },
+ "job3": {
+ result: runnerv1.Result_RESULT_SUCCESS,
+ logRows: []*runnerv1.LogRow{
+ {
+ Time: timestamppb.New(now.Add(4 * time.Second)),
+ Content: " \U0001F433 docker create image",
+ },
+ {
+ Time: timestamppb.New(now.Add(5 * time.Second)),
+ Content: "job3",
+ },
+ {
+ Time: timestamppb.New(now.Add(6 * time.Second)),
+ Content: "\U0001F3C1 Job succeeded",
+ },
+ },
+ },
+ },
+ expectedStatuses: map[string]string{
+ "job1": actions_model.StatusSuccess.String(),
+ "job2": actions_model.StatusSuccess.String(),
+ "job3": actions_model.StatusSuccess.String(),
+ },
+ }
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ session := loginUser(t, user2.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
+
+ apiRepo := createActionsTestRepo(t, token, "actions-delete-run-test", false)
+ runner := newMockRunner()
+ runner.registerAsRepoRunner(t, user2.Name, apiRepo.Name, "mock-runner", []string{"ubuntu-latest"}, false)
+
+ opts := getWorkflowCreateFileOptions(user2, apiRepo.DefaultBranch, "create "+testCase.treePath, testCase.fileContent)
+ createWorkflowFile(t, token, user2.Name, apiRepo.Name, testCase.treePath, opts)
+
+ runIndex := ""
+ for i := 0; i < len(testCase.outcomes); i++ {
+ task := runner.fetchTask(t)
+ jobName := getTaskJobNameByTaskID(t, token, user2.Name, apiRepo.Name, task.Id)
+ outcome := testCase.outcomes[jobName]
+ assert.NotNil(t, outcome)
+ runner.execTask(t, task, outcome)
+ runIndex = task.Context.GetFields()["run_number"].GetStringValue()
+ assert.Equal(t, "1", runIndex)
+ }
+
+ for i := 0; i < len(testCase.outcomes); i++ {
+ req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/actions/runs/%s/jobs/%d", user2.Name, apiRepo.Name, runIndex, i), map[string]string{
+ "_csrf": GetUserCSRFToken(t, session),
+ })
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ var listResp actions.ViewResponse
+ err := json.Unmarshal(resp.Body.Bytes(), &listResp)
+ assert.NoError(t, err)
+ assert.Len(t, listResp.State.Run.Jobs, 3)
+
+ req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/actions/runs/%s/jobs/%d/logs", user2.Name, apiRepo.Name, runIndex, i)).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusOK)
+ }
+
+ req := NewRequestWithValues(t, "GET", fmt.Sprintf("/%s/%s/actions/runs/%s", user2.Name, apiRepo.Name, runIndex), map[string]string{
+ "_csrf": GetUserCSRFToken(t, session),
+ })
+ session.MakeRequest(t, req, http.StatusOK)
+
+ req = NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/actions/runs/%s/delete", user2.Name, apiRepo.Name, runIndex), map[string]string{
+ "_csrf": GetUserCSRFToken(t, session),
+ })
+ session.MakeRequest(t, req, http.StatusOK)
+
+ req = NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/actions/runs/%s/delete", user2.Name, apiRepo.Name, runIndex), map[string]string{
+ "_csrf": GetUserCSRFToken(t, session),
+ })
+ session.MakeRequest(t, req, http.StatusNotFound)
+
+ req = NewRequestWithValues(t, "GET", fmt.Sprintf("/%s/%s/actions/runs/%s", user2.Name, apiRepo.Name, runIndex), map[string]string{
+ "_csrf": GetUserCSRFToken(t, session),
+ })
+ session.MakeRequest(t, req, http.StatusNotFound)
+
+ for i := 0; i < len(testCase.outcomes); i++ {
+ req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/actions/runs/%s/jobs/%d", user2.Name, apiRepo.Name, runIndex, i), map[string]string{
+ "_csrf": GetUserCSRFToken(t, session),
+ })
+ session.MakeRequest(t, req, http.StatusNotFound)
+
+ req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s/actions/runs/%s/jobs/%d/logs", user2.Name, apiRepo.Name, runIndex, i)).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNotFound)
+ }
+ })
+}
diff --git a/tests/integration/actions_job_test.go b/tests/integration/actions_job_test.go
new file mode 100644
index 0000000000..4f4456a4e5
--- /dev/null
+++ b/tests/integration/actions_job_test.go
@@ -0,0 +1,644 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package integration
+
+import (
+ "encoding/base64"
+ "fmt"
+ "net/http"
+ "net/url"
+ "reflect"
+ "strconv"
+ "testing"
+ "time"
+
+ actions_model "code.gitea.io/gitea/models/actions"
+ auth_model "code.gitea.io/gitea/models/auth"
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/json"
+ "code.gitea.io/gitea/modules/setting"
+ api "code.gitea.io/gitea/modules/structs"
+ actions_service "code.gitea.io/gitea/services/actions"
+
+ runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
+ "connectrpc.com/connect"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestJobWithNeeds(t *testing.T) {
+ testCases := []struct {
+ treePath string
+ fileContent string
+ outcomes map[string]*mockTaskOutcome
+ expectedStatuses map[string]string
+ }{
+ {
+ treePath: ".gitea/workflows/job-with-needs.yml",
+ fileContent: `name: job-with-needs
+on:
+ push:
+ paths:
+ - '.gitea/workflows/job-with-needs.yml'
+jobs:
+ job1:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo job1
+ job2:
+ runs-on: ubuntu-latest
+ needs: [job1]
+ steps:
+ - run: echo job2
+`,
+ outcomes: map[string]*mockTaskOutcome{
+ "job1": {
+ result: runnerv1.Result_RESULT_SUCCESS,
+ },
+ "job2": {
+ result: runnerv1.Result_RESULT_SUCCESS,
+ },
+ },
+ expectedStatuses: map[string]string{
+ "job1": actions_model.StatusSuccess.String(),
+ "job2": actions_model.StatusSuccess.String(),
+ },
+ },
+ {
+ treePath: ".gitea/workflows/job-with-needs-fail.yml",
+ fileContent: `name: job-with-needs-fail
+on:
+ push:
+ paths:
+ - '.gitea/workflows/job-with-needs-fail.yml'
+jobs:
+ job1:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo job1
+ job2:
+ runs-on: ubuntu-latest
+ needs: [job1]
+ steps:
+ - run: echo job2
+`,
+ outcomes: map[string]*mockTaskOutcome{
+ "job1": {
+ result: runnerv1.Result_RESULT_FAILURE,
+ },
+ },
+ expectedStatuses: map[string]string{
+ "job1": actions_model.StatusFailure.String(),
+ "job2": actions_model.StatusSkipped.String(),
+ },
+ },
+ {
+ treePath: ".gitea/workflows/job-with-needs-fail-if.yml",
+ fileContent: `name: job-with-needs-fail-if
+on:
+ push:
+ paths:
+ - '.gitea/workflows/job-with-needs-fail-if.yml'
+jobs:
+ job1:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo job1
+ job2:
+ runs-on: ubuntu-latest
+ if: ${{ always() }}
+ needs: [job1]
+ steps:
+ - run: echo job2
+`,
+ outcomes: map[string]*mockTaskOutcome{
+ "job1": {
+ result: runnerv1.Result_RESULT_FAILURE,
+ },
+ "job2": {
+ result: runnerv1.Result_RESULT_SUCCESS,
+ },
+ },
+ expectedStatuses: map[string]string{
+ "job1": actions_model.StatusFailure.String(),
+ "job2": actions_model.StatusSuccess.String(),
+ },
+ },
+ }
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ session := loginUser(t, user2.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
+
+ apiRepo := createActionsTestRepo(t, token, "actions-jobs-with-needs", false)
+ runner := newMockRunner()
+ runner.registerAsRepoRunner(t, user2.Name, apiRepo.Name, "mock-runner", []string{"ubuntu-latest"}, false)
+
+ for _, tc := range testCases {
+ t.Run("test "+tc.treePath, func(t *testing.T) {
+ // create the workflow file
+ opts := getWorkflowCreateFileOptions(user2, apiRepo.DefaultBranch, "create "+tc.treePath, tc.fileContent)
+ fileResp := createWorkflowFile(t, token, user2.Name, apiRepo.Name, tc.treePath, opts)
+
+ // fetch and execute task
+ for i := 0; i < len(tc.outcomes); i++ {
+ task := runner.fetchTask(t)
+ jobName := getTaskJobNameByTaskID(t, token, user2.Name, apiRepo.Name, task.Id)
+ outcome := tc.outcomes[jobName]
+ assert.NotNil(t, outcome)
+ runner.execTask(t, task, outcome)
+ }
+
+ // check result
+ req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/actions/tasks", user2.Name, apiRepo.Name)).
+ AddTokenAuth(token)
+ resp := MakeRequest(t, req, http.StatusOK)
+ var actionTaskRespAfter api.ActionTaskResponse
+ DecodeJSON(t, resp, &actionTaskRespAfter)
+ for _, apiTask := range actionTaskRespAfter.Entries {
+ if apiTask.HeadSHA != fileResp.Commit.SHA {
+ continue
+ }
+ status := apiTask.Status
+ assert.Equal(t, status, tc.expectedStatuses[apiTask.Name])
+ }
+ })
+ }
+ })
+}
+
+func TestJobNeedsMatrix(t *testing.T) {
+ testCases := []struct {
+ treePath string
+ fileContent string
+ outcomes map[string]*mockTaskOutcome
+ expectedTaskNeeds map[string]*runnerv1.TaskNeed // jobID => TaskNeed
+ }{
+ {
+ treePath: ".gitea/workflows/jobs-outputs-with-matrix.yml",
+ fileContent: `name: jobs-outputs-with-matrix
+on:
+ push:
+ paths:
+ - '.gitea/workflows/jobs-outputs-with-matrix.yml'
+jobs:
+ job1:
+ runs-on: ubuntu-latest
+ outputs:
+ output_1: ${{ steps.gen_output.outputs.output_1 }}
+ output_2: ${{ steps.gen_output.outputs.output_2 }}
+ output_3: ${{ steps.gen_output.outputs.output_3 }}
+ strategy:
+ matrix:
+ version: [1, 2, 3]
+ steps:
+ - name: Generate output
+ id: gen_output
+ run: |
+ version="${{ matrix.version }}"
+ echo "output_${version}=${version}" >> "$GITHUB_OUTPUT"
+ job2:
+ runs-on: ubuntu-latest
+ needs: [job1]
+ steps:
+ - run: echo '${{ toJSON(needs.job1.outputs) }}'
+`,
+ outcomes: map[string]*mockTaskOutcome{
+ "job1 (1)": {
+ result: runnerv1.Result_RESULT_SUCCESS,
+ outputs: map[string]string{
+ "output_1": "1",
+ "output_2": "",
+ "output_3": "",
+ },
+ },
+ "job1 (2)": {
+ result: runnerv1.Result_RESULT_SUCCESS,
+ outputs: map[string]string{
+ "output_1": "",
+ "output_2": "2",
+ "output_3": "",
+ },
+ },
+ "job1 (3)": {
+ result: runnerv1.Result_RESULT_SUCCESS,
+ outputs: map[string]string{
+ "output_1": "",
+ "output_2": "",
+ "output_3": "3",
+ },
+ },
+ },
+ expectedTaskNeeds: map[string]*runnerv1.TaskNeed{
+ "job1": {
+ Result: runnerv1.Result_RESULT_SUCCESS,
+ Outputs: map[string]string{
+ "output_1": "1",
+ "output_2": "2",
+ "output_3": "3",
+ },
+ },
+ },
+ },
+ {
+ treePath: ".gitea/workflows/jobs-outputs-with-matrix-failure.yml",
+ fileContent: `name: jobs-outputs-with-matrix-failure
+on:
+ push:
+ paths:
+ - '.gitea/workflows/jobs-outputs-with-matrix-failure.yml'
+jobs:
+ job1:
+ runs-on: ubuntu-latest
+ outputs:
+ output_1: ${{ steps.gen_output.outputs.output_1 }}
+ output_2: ${{ steps.gen_output.outputs.output_2 }}
+ output_3: ${{ steps.gen_output.outputs.output_3 }}
+ strategy:
+ matrix:
+ version: [1, 2, 3]
+ steps:
+ - name: Generate output
+ id: gen_output
+ run: |
+ version="${{ matrix.version }}"
+ echo "output_${version}=${version}" >> "$GITHUB_OUTPUT"
+ job2:
+ runs-on: ubuntu-latest
+ if: ${{ always() }}
+ needs: [job1]
+ steps:
+ - run: echo '${{ toJSON(needs.job1.outputs) }}'
+`,
+ outcomes: map[string]*mockTaskOutcome{
+ "job1 (1)": {
+ result: runnerv1.Result_RESULT_SUCCESS,
+ outputs: map[string]string{
+ "output_1": "1",
+ "output_2": "",
+ "output_3": "",
+ },
+ },
+ "job1 (2)": {
+ result: runnerv1.Result_RESULT_FAILURE,
+ outputs: map[string]string{
+ "output_1": "",
+ "output_2": "",
+ "output_3": "",
+ },
+ },
+ "job1 (3)": {
+ result: runnerv1.Result_RESULT_SUCCESS,
+ outputs: map[string]string{
+ "output_1": "",
+ "output_2": "",
+ "output_3": "3",
+ },
+ },
+ },
+ expectedTaskNeeds: map[string]*runnerv1.TaskNeed{
+ "job1": {
+ Result: runnerv1.Result_RESULT_FAILURE,
+ Outputs: map[string]string{
+ "output_1": "1",
+ "output_2": "",
+ "output_3": "3",
+ },
+ },
+ },
+ },
+ }
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ session := loginUser(t, user2.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
+
+ apiRepo := createActionsTestRepo(t, token, "actions-jobs-outputs-with-matrix", false)
+ runner := newMockRunner()
+ runner.registerAsRepoRunner(t, user2.Name, apiRepo.Name, "mock-runner", []string{"ubuntu-latest"}, false)
+
+ for _, tc := range testCases {
+ t.Run("test "+tc.treePath, func(t *testing.T) {
+ opts := getWorkflowCreateFileOptions(user2, apiRepo.DefaultBranch, "create "+tc.treePath, tc.fileContent)
+ createWorkflowFile(t, token, user2.Name, apiRepo.Name, tc.treePath, opts)
+
+ for i := 0; i < len(tc.outcomes); i++ {
+ task := runner.fetchTask(t)
+ jobName := getTaskJobNameByTaskID(t, token, user2.Name, apiRepo.Name, task.Id)
+ outcome := tc.outcomes[jobName]
+ assert.NotNil(t, outcome)
+ runner.execTask(t, task, outcome)
+ }
+
+ task := runner.fetchTask(t)
+ actualTaskNeeds := task.Needs
+ assert.Len(t, actualTaskNeeds, len(tc.expectedTaskNeeds))
+ for jobID, tn := range tc.expectedTaskNeeds {
+ actualNeed := actualTaskNeeds[jobID]
+ assert.Equal(t, tn.Result, actualNeed.Result)
+ assert.Len(t, actualNeed.Outputs, len(tn.Outputs))
+ for outputKey, outputValue := range tn.Outputs {
+ assert.Equal(t, outputValue, actualNeed.Outputs[outputKey])
+ }
+ }
+ })
+ }
+ })
+}
+
+func TestActionsGiteaContext(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ user2Session := loginUser(t, user2.Name)
+ user2Token := getTokenForLoggedInUser(t, user2Session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
+
+ apiBaseRepo := createActionsTestRepo(t, user2Token, "actions-gitea-context", false)
+ baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiBaseRepo.ID})
+ user2APICtx := NewAPITestContext(t, baseRepo.OwnerName, baseRepo.Name, auth_model.AccessTokenScopeWriteRepository)
+
+ runner := newMockRunner()
+ runner.registerAsRepoRunner(t, baseRepo.OwnerName, baseRepo.Name, "mock-runner", []string{"ubuntu-latest"}, false)
+
+ // init the workflow
+ wfTreePath := ".gitea/workflows/pull.yml"
+ wfFileContent := `name: Pull Request
+on: pull_request
+jobs:
+ wf1-job:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo 'test the pull'
+`
+ opts := getWorkflowCreateFileOptions(user2, baseRepo.DefaultBranch, "create "+wfTreePath, wfFileContent)
+ createWorkflowFile(t, user2Token, baseRepo.OwnerName, baseRepo.Name, wfTreePath, opts)
+ // user2 creates a pull request
+ doAPICreateFile(user2APICtx, "user2-patch.txt", &api.CreateFileOptions{
+ FileOptions: api.FileOptions{
+ NewBranchName: "user2/patch-1",
+ Message: "create user2-patch.txt",
+ Author: api.Identity{
+ Name: user2.Name,
+ Email: user2.Email,
+ },
+ Committer: api.Identity{
+ Name: user2.Name,
+ Email: user2.Email,
+ },
+ Dates: api.CommitDateOptions{
+ Author: time.Now(),
+ Committer: time.Now(),
+ },
+ },
+ ContentBase64: base64.StdEncoding.EncodeToString([]byte("user2-fix")),
+ })(t)
+ apiPull, err := doAPICreatePullRequest(user2APICtx, baseRepo.OwnerName, baseRepo.Name, baseRepo.DefaultBranch, "user2/patch-1")(t)
+ assert.NoError(t, err)
+ task := runner.fetchTask(t)
+ gtCtx := task.Context.GetFields()
+ actionTask := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: task.Id})
+ actionRunJob := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{ID: actionTask.JobID})
+ actionRun := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: actionRunJob.RunID})
+ assert.NoError(t, actionRun.LoadAttributes(t.Context()))
+
+ assert.Equal(t, user2.Name, gtCtx["actor"].GetStringValue())
+ assert.Equal(t, setting.AppURL+"api/v1", gtCtx["api_url"].GetStringValue())
+ assert.Equal(t, apiPull.Base.Ref, gtCtx["base_ref"].GetStringValue())
+ runEvent := map[string]any{}
+ assert.NoError(t, json.Unmarshal([]byte(actionRun.EventPayload), &runEvent))
+ assert.True(t, reflect.DeepEqual(gtCtx["event"].GetStructValue().AsMap(), runEvent))
+ assert.Equal(t, actionRun.TriggerEvent, gtCtx["event_name"].GetStringValue())
+ assert.Equal(t, apiPull.Head.Ref, gtCtx["head_ref"].GetStringValue())
+ assert.Equal(t, actionRunJob.JobID, gtCtx["job"].GetStringValue())
+ assert.Equal(t, actionRun.Ref, gtCtx["ref"].GetStringValue())
+ assert.Equal(t, (git.RefName(actionRun.Ref)).ShortName(), gtCtx["ref_name"].GetStringValue())
+ assert.False(t, gtCtx["ref_protected"].GetBoolValue())
+ assert.Equal(t, string((git.RefName(actionRun.Ref)).RefType()), gtCtx["ref_type"].GetStringValue())
+ assert.Equal(t, actionRun.Repo.OwnerName+"/"+actionRun.Repo.Name, gtCtx["repository"].GetStringValue())
+ assert.Equal(t, actionRun.Repo.OwnerName, gtCtx["repository_owner"].GetStringValue())
+ assert.Equal(t, actionRun.Repo.HTMLURL(), gtCtx["repositoryUrl"].GetStringValue())
+ assert.Equal(t, strconv.FormatInt(actionRunJob.RunID, 10), gtCtx["run_id"].GetStringValue())
+ assert.Equal(t, strconv.FormatInt(actionRun.Index, 10), gtCtx["run_number"].GetStringValue())
+ assert.Equal(t, strconv.FormatInt(actionRunJob.Attempt, 10), gtCtx["run_attempt"].GetStringValue())
+ assert.Equal(t, "Actions", gtCtx["secret_source"].GetStringValue())
+ assert.Equal(t, setting.AppURL, gtCtx["server_url"].GetStringValue())
+ assert.Equal(t, actionRun.CommitSHA, gtCtx["sha"].GetStringValue())
+ assert.Equal(t, actionRun.WorkflowID, gtCtx["workflow"].GetStringValue())
+ assert.Equal(t, setting.Actions.DefaultActionsURL.URL(), gtCtx["gitea_default_actions_url"].GetStringValue())
+ token := gtCtx["token"].GetStringValue()
+ assert.Equal(t, actionTask.TokenLastEight, token[len(token)-8:])
+ })
+}
+
+// Ephemeral
+func TestActionsGiteaContextEphemeral(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ user2Session := loginUser(t, user2.Name)
+ user2Token := getTokenForLoggedInUser(t, user2Session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
+
+ apiBaseRepo := createActionsTestRepo(t, user2Token, "actions-gitea-context", false)
+ baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiBaseRepo.ID})
+ user2APICtx := NewAPITestContext(t, baseRepo.OwnerName, baseRepo.Name, auth_model.AccessTokenScopeWriteRepository)
+
+ runner := newMockRunner()
+ runner.registerAsRepoRunner(t, baseRepo.OwnerName, baseRepo.Name, "mock-runner", []string{"ubuntu-latest"}, true)
+
+ // verify CleanupEphemeralRunners does not remove this runner
+ err := actions_service.CleanupEphemeralRunners(t.Context())
+ assert.NoError(t, err)
+
+ // init the workflow
+ wfTreePath := ".gitea/workflows/pull.yml"
+ wfFileContent := `name: Pull Request
+on: pull_request
+jobs:
+ wf1-job:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo 'test the pull'
+ wf2-job:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo 'test the pull'
+`
+ opts := getWorkflowCreateFileOptions(user2, baseRepo.DefaultBranch, "create "+wfTreePath, wfFileContent)
+ createWorkflowFile(t, user2Token, baseRepo.OwnerName, baseRepo.Name, wfTreePath, opts)
+ // user2 creates a pull request
+ doAPICreateFile(user2APICtx, "user2-patch.txt", &api.CreateFileOptions{
+ FileOptions: api.FileOptions{
+ NewBranchName: "user2/patch-1",
+ Message: "create user2-patch.txt",
+ Author: api.Identity{
+ Name: user2.Name,
+ Email: user2.Email,
+ },
+ Committer: api.Identity{
+ Name: user2.Name,
+ Email: user2.Email,
+ },
+ Dates: api.CommitDateOptions{
+ Author: time.Now(),
+ Committer: time.Now(),
+ },
+ },
+ ContentBase64: base64.StdEncoding.EncodeToString([]byte("user2-fix")),
+ })(t)
+ apiPull, err := doAPICreatePullRequest(user2APICtx, baseRepo.OwnerName, baseRepo.Name, baseRepo.DefaultBranch, "user2/patch-1")(t)
+ assert.NoError(t, err)
+ task := runner.fetchTask(t)
+ gtCtx := task.Context.GetFields()
+ actionTask := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: task.Id})
+ actionRunJob := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{ID: actionTask.JobID})
+ actionRun := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: actionRunJob.RunID})
+ assert.NoError(t, actionRun.LoadAttributes(t.Context()))
+
+ assert.Equal(t, user2.Name, gtCtx["actor"].GetStringValue())
+ assert.Equal(t, setting.AppURL+"api/v1", gtCtx["api_url"].GetStringValue())
+ assert.Equal(t, apiPull.Base.Ref, gtCtx["base_ref"].GetStringValue())
+ runEvent := map[string]any{}
+ assert.NoError(t, json.Unmarshal([]byte(actionRun.EventPayload), &runEvent))
+ assert.True(t, reflect.DeepEqual(gtCtx["event"].GetStructValue().AsMap(), runEvent))
+ assert.Equal(t, actionRun.TriggerEvent, gtCtx["event_name"].GetStringValue())
+ assert.Equal(t, apiPull.Head.Ref, gtCtx["head_ref"].GetStringValue())
+ assert.Equal(t, actionRunJob.JobID, gtCtx["job"].GetStringValue())
+ assert.Equal(t, actionRun.Ref, gtCtx["ref"].GetStringValue())
+ assert.Equal(t, (git.RefName(actionRun.Ref)).ShortName(), gtCtx["ref_name"].GetStringValue())
+ assert.False(t, gtCtx["ref_protected"].GetBoolValue())
+ assert.Equal(t, string((git.RefName(actionRun.Ref)).RefType()), gtCtx["ref_type"].GetStringValue())
+ assert.Equal(t, actionRun.Repo.OwnerName+"/"+actionRun.Repo.Name, gtCtx["repository"].GetStringValue())
+ assert.Equal(t, actionRun.Repo.OwnerName, gtCtx["repository_owner"].GetStringValue())
+ assert.Equal(t, actionRun.Repo.HTMLURL(), gtCtx["repositoryUrl"].GetStringValue())
+ assert.Equal(t, strconv.FormatInt(actionRunJob.RunID, 10), gtCtx["run_id"].GetStringValue())
+ assert.Equal(t, strconv.FormatInt(actionRun.Index, 10), gtCtx["run_number"].GetStringValue())
+ assert.Equal(t, strconv.FormatInt(actionRunJob.Attempt, 10), gtCtx["run_attempt"].GetStringValue())
+ assert.Equal(t, "Actions", gtCtx["secret_source"].GetStringValue())
+ assert.Equal(t, setting.AppURL, gtCtx["server_url"].GetStringValue())
+ assert.Equal(t, actionRun.CommitSHA, gtCtx["sha"].GetStringValue())
+ assert.Equal(t, actionRun.WorkflowID, gtCtx["workflow"].GetStringValue())
+ assert.Equal(t, setting.Actions.DefaultActionsURL.URL(), gtCtx["gitea_default_actions_url"].GetStringValue())
+ token := gtCtx["token"].GetStringValue()
+ assert.Equal(t, actionTask.TokenLastEight, token[len(token)-8:])
+
+ // verify CleanupEphemeralRunners does not remove this runner
+ err = actions_service.CleanupEphemeralRunners(t.Context())
+ assert.NoError(t, err)
+
+ resp, err := runner.client.runnerServiceClient.FetchTask(t.Context(), connect.NewRequest(&runnerv1.FetchTaskRequest{
+ TasksVersion: 0,
+ }))
+ assert.NoError(t, err)
+ assert.Nil(t, resp.Msg.Task)
+
+ // verify CleanupEphemeralRunners does not remove this runner
+ err = actions_service.CleanupEphemeralRunners(t.Context())
+ assert.NoError(t, err)
+
+ _, err = runner.client.runnerServiceClient.UpdateTask(t.Context(), connect.NewRequest(&runnerv1.UpdateTaskRequest{
+ State: &runnerv1.TaskState{
+ Id: actionTask.ID,
+ Result: runnerv1.Result_RESULT_SUCCESS,
+ },
+ }))
+ assert.NoError(t, err)
+
+ resp, err = runner.client.runnerServiceClient.FetchTask(t.Context(), connect.NewRequest(&runnerv1.FetchTaskRequest{
+ TasksVersion: 0,
+ }))
+ assert.Error(t, err)
+ assert.Nil(t, resp)
+
+ resp, err = runner.client.runnerServiceClient.FetchTask(t.Context(), connect.NewRequest(&runnerv1.FetchTaskRequest{
+ TasksVersion: 0,
+ }))
+ assert.Error(t, err)
+ assert.Nil(t, resp)
+
+ // create a runner that picks a job and get force cancelled
+ runnerToBeRemoved := newMockRunner()
+ runnerToBeRemoved.registerAsRepoRunner(t, baseRepo.OwnerName, baseRepo.Name, "mock-runner-to-be-removed", []string{"ubuntu-latest"}, true)
+
+ taskToStopAPIObj := runnerToBeRemoved.fetchTask(t)
+
+ taskToStop := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: taskToStopAPIObj.Id})
+
+ // verify CleanupEphemeralRunners does not remove the custom crafted runner
+ err = actions_service.CleanupEphemeralRunners(t.Context())
+ assert.NoError(t, err)
+
+ runnerToRemove := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{ID: taskToStop.RunnerID})
+
+ err = actions_model.StopTask(t.Context(), taskToStop.ID, actions_model.StatusFailure)
+ assert.NoError(t, err)
+
+ // verify CleanupEphemeralRunners does remove the custom crafted runner
+ err = actions_service.CleanupEphemeralRunners(t.Context())
+ assert.NoError(t, err)
+
+ unittest.AssertNotExistsBean(t, &actions_model.ActionRunner{ID: runnerToRemove.ID})
+ })
+}
+
+func createActionsTestRepo(t *testing.T, authToken, repoName string, isPrivate bool) *api.Repository {
+ req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos", &api.CreateRepoOption{
+ Name: repoName,
+ Private: isPrivate,
+ Readme: "Default",
+ AutoInit: true,
+ DefaultBranch: "main",
+ }).AddTokenAuth(authToken)
+ resp := MakeRequest(t, req, http.StatusCreated)
+ var apiRepo api.Repository
+ DecodeJSON(t, resp, &apiRepo)
+ return &apiRepo
+}
+
+func getWorkflowCreateFileOptions(u *user_model.User, branch, msg, content string) *api.CreateFileOptions {
+ return &api.CreateFileOptions{
+ FileOptions: api.FileOptions{
+ BranchName: branch,
+ Message: msg,
+ Author: api.Identity{
+ Name: u.Name,
+ Email: u.Email,
+ },
+ Committer: api.Identity{
+ Name: u.Name,
+ Email: u.Email,
+ },
+ Dates: api.CommitDateOptions{
+ Author: time.Now(),
+ Committer: time.Now(),
+ },
+ },
+ ContentBase64: base64.StdEncoding.EncodeToString([]byte(content)),
+ }
+}
+
+func createWorkflowFile(t *testing.T, authToken, ownerName, repoName, treePath string, opts *api.CreateFileOptions) *api.FileResponse {
+ req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", ownerName, repoName, treePath), opts).
+ AddTokenAuth(authToken)
+ resp := MakeRequest(t, req, http.StatusCreated)
+ var fileResponse api.FileResponse
+ DecodeJSON(t, resp, &fileResponse)
+ return &fileResponse
+}
+
+// getTaskJobNameByTaskID get the job name of the task by task ID
+// there is currently not an API for querying a task by ID so we have to list all the tasks
+func getTaskJobNameByTaskID(t *testing.T, authToken, ownerName, repoName string, taskID int64) string {
+ // FIXME: we may need to query several pages
+ req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/actions/tasks", ownerName, repoName)).
+ AddTokenAuth(authToken)
+ resp := MakeRequest(t, req, http.StatusOK)
+ var taskRespBefore api.ActionTaskResponse
+ DecodeJSON(t, resp, &taskRespBefore)
+ for _, apiTask := range taskRespBefore.Entries {
+ if apiTask.ID == taskID {
+ return apiTask.Name
+ }
+ }
+ return ""
+}
diff --git a/tests/integration/actions_log_test.go b/tests/integration/actions_log_test.go
new file mode 100644
index 0000000000..503bda97c9
--- /dev/null
+++ b/tests/integration/actions_log_test.go
@@ -0,0 +1,226 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package integration
+
+import (
+ "fmt"
+ "net/http"
+ "net/url"
+ "strconv"
+ "strings"
+ "testing"
+ "time"
+
+ actions_model "code.gitea.io/gitea/models/actions"
+ auth_model "code.gitea.io/gitea/models/auth"
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/storage"
+ "code.gitea.io/gitea/modules/test"
+
+ runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
+ "github.com/stretchr/testify/assert"
+ "google.golang.org/protobuf/types/known/timestamppb"
+)
+
+func TestDownloadTaskLogs(t *testing.T) {
+ now := time.Now()
+ testCases := []struct {
+ treePath string
+ fileContent string
+ outcome []*mockTaskOutcome
+ zstdEnabled bool
+ }{
+ {
+ treePath: ".gitea/workflows/download-task-logs-zstd.yml",
+ fileContent: `name: download-task-logs-zstd
+on:
+ push:
+ paths:
+ - '.gitea/workflows/download-task-logs-zstd.yml'
+jobs:
+ job1:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo job1 with zstd enabled
+ job2:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo job2 with zstd enabled
+`,
+ outcome: []*mockTaskOutcome{
+ {
+ result: runnerv1.Result_RESULT_SUCCESS,
+ logRows: []*runnerv1.LogRow{
+ {
+ Time: timestamppb.New(now.Add(1 * time.Second)),
+ Content: " \U0001F433 docker create image",
+ },
+ {
+ Time: timestamppb.New(now.Add(2 * time.Second)),
+ Content: "job1 zstd enabled",
+ },
+ {
+ Time: timestamppb.New(now.Add(3 * time.Second)),
+ Content: "\U0001F3C1 Job succeeded",
+ },
+ },
+ },
+ {
+ result: runnerv1.Result_RESULT_SUCCESS,
+ logRows: []*runnerv1.LogRow{
+ {
+ Time: timestamppb.New(now.Add(1 * time.Second)),
+ Content: " \U0001F433 docker create image",
+ },
+ {
+ Time: timestamppb.New(now.Add(2 * time.Second)),
+ Content: "job2 zstd enabled",
+ },
+ {
+ Time: timestamppb.New(now.Add(3 * time.Second)),
+ Content: "\U0001F3C1 Job succeeded",
+ },
+ },
+ },
+ },
+ zstdEnabled: true,
+ },
+ {
+ treePath: ".gitea/workflows/download-task-logs-no-zstd.yml",
+ fileContent: `name: download-task-logs-no-zstd
+on:
+ push:
+ paths:
+ - '.gitea/workflows/download-task-logs-no-zstd.yml'
+jobs:
+ job1:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo job1 with zstd disabled
+ job2:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo job2 with zstd disabled
+`,
+ outcome: []*mockTaskOutcome{
+ {
+ result: runnerv1.Result_RESULT_SUCCESS,
+ logRows: []*runnerv1.LogRow{
+ {
+ Time: timestamppb.New(now.Add(4 * time.Second)),
+ Content: " \U0001F433 docker create image",
+ },
+ {
+ Time: timestamppb.New(now.Add(5 * time.Second)),
+ Content: "job1 zstd disabled",
+ },
+ {
+ Time: timestamppb.New(now.Add(6 * time.Second)),
+ Content: "\U0001F3C1 Job succeeded",
+ },
+ },
+ },
+ {
+ result: runnerv1.Result_RESULT_SUCCESS,
+ logRows: []*runnerv1.LogRow{
+ {
+ Time: timestamppb.New(now.Add(4 * time.Second)),
+ Content: " \U0001F433 docker create image",
+ },
+ {
+ Time: timestamppb.New(now.Add(5 * time.Second)),
+ Content: "job2 zstd disabled",
+ },
+ {
+ Time: timestamppb.New(now.Add(6 * time.Second)),
+ Content: "\U0001F3C1 Job succeeded",
+ },
+ },
+ },
+ },
+ zstdEnabled: false,
+ },
+ }
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ session := loginUser(t, user2.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
+
+ apiRepo := createActionsTestRepo(t, token, "actions-download-task-logs", false)
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiRepo.ID})
+ runner := newMockRunner()
+ runner.registerAsRepoRunner(t, user2.Name, repo.Name, "mock-runner", []string{"ubuntu-latest"}, false)
+
+ for _, tc := range testCases {
+ t.Run("test "+tc.treePath, func(t *testing.T) {
+ var resetFunc func()
+ if tc.zstdEnabled {
+ resetFunc = test.MockVariableValue(&setting.Actions.LogCompression, "zstd")
+ assert.True(t, setting.Actions.LogCompression.IsZstd())
+ } else {
+ resetFunc = test.MockVariableValue(&setting.Actions.LogCompression, "none")
+ assert.False(t, setting.Actions.LogCompression.IsZstd())
+ }
+
+ // create the workflow file
+ opts := getWorkflowCreateFileOptions(user2, repo.DefaultBranch, "create "+tc.treePath, tc.fileContent)
+ createWorkflowFile(t, token, user2.Name, repo.Name, tc.treePath, opts)
+
+ // fetch and execute tasks
+ for jobIndex, outcome := range tc.outcome {
+ task := runner.fetchTask(t)
+ runner.execTask(t, task, outcome)
+
+ // check whether the log file exists
+ logFileName := fmt.Sprintf("%s/%02x/%d.log", repo.FullName(), task.Id%256, task.Id)
+ if setting.Actions.LogCompression.IsZstd() {
+ logFileName += ".zst"
+ }
+ _, err := storage.Actions.Stat(logFileName)
+ assert.NoError(t, err)
+
+ // download task logs and check content
+ runIndex := task.Context.GetFields()["run_number"].GetStringValue()
+ req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/actions/runs/%s/jobs/%d/logs", user2.Name, repo.Name, runIndex, jobIndex)).
+ AddTokenAuth(token)
+ resp := MakeRequest(t, req, http.StatusOK)
+ logTextLines := strings.Split(strings.TrimSpace(resp.Body.String()), "\n")
+ assert.Len(t, logTextLines, len(outcome.logRows))
+ for idx, lr := range outcome.logRows {
+ assert.Equal(
+ t,
+ fmt.Sprintf("%s %s", lr.Time.AsTime().Format("2006-01-02T15:04:05.0000000Z07:00"), lr.Content),
+ logTextLines[idx],
+ )
+ }
+
+ runID, _ := strconv.ParseInt(task.Context.GetFields()["run_id"].GetStringValue(), 10, 64)
+
+ jobs, err := actions_model.GetRunJobsByRunID(t.Context(), runID)
+ assert.NoError(t, err)
+ assert.Len(t, jobs, len(tc.outcome))
+ jobID := jobs[jobIndex].ID
+
+ // download task logs from API and check content
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/actions/jobs/%d/logs", user2.Name, repo.Name, jobID)).
+ AddTokenAuth(token)
+ resp = MakeRequest(t, req, http.StatusOK)
+ logTextLines = strings.Split(strings.TrimSpace(resp.Body.String()), "\n")
+ assert.Len(t, logTextLines, len(outcome.logRows))
+ for idx, lr := range outcome.logRows {
+ assert.Equal(
+ t,
+ fmt.Sprintf("%s %s", lr.Time.AsTime().Format("2006-01-02T15:04:05.0000000Z07:00"), lr.Content),
+ logTextLines[idx],
+ )
+ }
+ }
+ resetFunc()
+ })
+ }
+ })
+}
diff --git a/tests/integration/actions_runner_modify_test.go b/tests/integration/actions_runner_modify_test.go
new file mode 100644
index 0000000000..7d711bae49
--- /dev/null
+++ b/tests/integration/actions_runner_modify_test.go
@@ -0,0 +1,150 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package integration
+
+import (
+ "fmt"
+ "net/http"
+ "testing"
+
+ actions_model "code.gitea.io/gitea/models/actions"
+ "code.gitea.io/gitea/models/db"
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/tests"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestActionsRunnerModify(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+
+ ctx := t.Context()
+
+ require.NoError(t, db.DeleteAllRecords("action_runner"))
+
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ _ = actions_model.CreateRunner(ctx, &actions_model.ActionRunner{OwnerID: user2.ID, Name: "user2-runner", TokenHash: "a", UUID: "a"})
+ user2Runner := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{OwnerID: user2.ID, Name: "user2-runner"})
+ userWebURL := "/user/settings/actions/runners"
+
+ org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3, Type: user_model.UserTypeOrganization})
+ require.NoError(t, actions_model.CreateRunner(ctx, &actions_model.ActionRunner{OwnerID: org3.ID, Name: "org3-runner", TokenHash: "b", UUID: "b"}))
+ org3Runner := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{OwnerID: org3.ID, Name: "org3-runner"})
+ orgWebURL := "/org/org3/settings/actions/runners"
+
+ repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+ _ = actions_model.CreateRunner(ctx, &actions_model.ActionRunner{RepoID: repo1.ID, Name: "repo1-runner", TokenHash: "c", UUID: "c"})
+ repo1Runner := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{RepoID: repo1.ID, Name: "repo1-runner"})
+ repoWebURL := "/user2/repo1/settings/actions/runners"
+
+ _ = actions_model.CreateRunner(ctx, &actions_model.ActionRunner{Name: "global-runner", TokenHash: "d", UUID: "d"})
+ globalRunner := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{Name: "global-runner"})
+ adminWebURL := "/-/admin/actions/runners"
+
+ sessionAdmin := loginUser(t, "user1")
+ sessionUser2 := loginUser(t, user2.Name)
+
+ doUpdate := func(t *testing.T, sess *TestSession, baseURL string, id int64, description string, expectedStatus int) {
+ req := NewRequestWithValues(t, "POST", fmt.Sprintf("%s/%d", baseURL, id), map[string]string{
+ "_csrf": GetUserCSRFToken(t, sess),
+ "description": description,
+ })
+ sess.MakeRequest(t, req, expectedStatus)
+ }
+
+ doDelete := func(t *testing.T, sess *TestSession, baseURL string, id int64, expectedStatus int) {
+ req := NewRequestWithValues(t, "POST", fmt.Sprintf("%s/%d/delete", baseURL, id), map[string]string{
+ "_csrf": GetUserCSRFToken(t, sess),
+ })
+ sess.MakeRequest(t, req, expectedStatus)
+ }
+
+ assertDenied := func(t *testing.T, sess *TestSession, baseURL string, id int64) {
+ doUpdate(t, sess, baseURL, id, "ChangedDescription", http.StatusNotFound)
+ doDelete(t, sess, baseURL, id, http.StatusNotFound)
+ v := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{ID: id})
+ assert.Empty(t, v.Description)
+ }
+
+ assertSuccess := func(t *testing.T, sess *TestSession, baseURL string, id int64) {
+ doUpdate(t, sess, baseURL, id, "ChangedDescription", http.StatusSeeOther)
+ v := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunner{ID: id})
+ assert.Equal(t, "ChangedDescription", v.Description)
+ doDelete(t, sess, baseURL, id, http.StatusOK)
+ unittest.AssertNotExistsBean(t, &actions_model.ActionRunner{ID: id})
+ }
+
+ t.Run("UpdateUserRunner", func(t *testing.T) {
+ theRunner := user2Runner
+ t.Run("FromOrg", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, orgWebURL, theRunner.ID)
+ })
+ t.Run("FromRepo", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, repoWebURL, theRunner.ID)
+ })
+ t.Run("FromAdmin", func(t *testing.T) {
+ t.Skip("Admin can update any runner (not right but not too bad)")
+ assertDenied(t, sessionAdmin, adminWebURL, theRunner.ID)
+ })
+ })
+
+ t.Run("UpdateOrgRunner", func(t *testing.T) {
+ theRunner := org3Runner
+ t.Run("FromRepo", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, repoWebURL, theRunner.ID)
+ })
+ t.Run("FromUser", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, userWebURL, theRunner.ID)
+ })
+ t.Run("FromAdmin", func(t *testing.T) {
+ t.Skip("Admin can update any runner (not right but not too bad)")
+ assertDenied(t, sessionAdmin, adminWebURL, theRunner.ID)
+ })
+ })
+
+ t.Run("UpdateRepoRunner", func(t *testing.T) {
+ theRunner := repo1Runner
+ t.Run("FromOrg", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, orgWebURL, theRunner.ID)
+ })
+ t.Run("FromUser", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, userWebURL, theRunner.ID)
+ })
+ t.Run("FromAdmin", func(t *testing.T) {
+ t.Skip("Admin can update any runner (not right but not too bad)")
+ assertDenied(t, sessionAdmin, adminWebURL, theRunner.ID)
+ })
+ })
+
+ t.Run("UpdateGlobalRunner", func(t *testing.T) {
+ theRunner := globalRunner
+ t.Run("FromOrg", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, orgWebURL, theRunner.ID)
+ })
+ t.Run("FromUser", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, userWebURL, theRunner.ID)
+ })
+ t.Run("FromRepo", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, repoWebURL, theRunner.ID)
+ })
+ })
+
+ t.Run("UpdateSuccess", func(t *testing.T) {
+ t.Run("User", func(t *testing.T) {
+ assertSuccess(t, sessionUser2, userWebURL, user2Runner.ID)
+ })
+ t.Run("Org", func(t *testing.T) {
+ assertSuccess(t, sessionAdmin, orgWebURL, org3Runner.ID)
+ })
+ t.Run("Repo", func(t *testing.T) {
+ assertSuccess(t, sessionUser2, repoWebURL, repo1Runner.ID)
+ })
+ t.Run("Admin", func(t *testing.T) {
+ assertSuccess(t, sessionAdmin, adminWebURL, globalRunner.ID)
+ })
+ })
+}
diff --git a/tests/integration/actions_runner_test.go b/tests/integration/actions_runner_test.go
new file mode 100644
index 0000000000..6cc5a10e0f
--- /dev/null
+++ b/tests/integration/actions_runner_test.go
@@ -0,0 +1,156 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package integration
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "testing"
+ "time"
+
+ auth_model "code.gitea.io/gitea/models/auth"
+ "code.gitea.io/gitea/modules/setting"
+
+ pingv1 "code.gitea.io/actions-proto-go/ping/v1"
+ "code.gitea.io/actions-proto-go/ping/v1/pingv1connect"
+ runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
+ "code.gitea.io/actions-proto-go/runner/v1/runnerv1connect"
+ "connectrpc.com/connect"
+ "github.com/stretchr/testify/assert"
+ "google.golang.org/protobuf/types/known/timestamppb"
+)
+
+type mockRunner struct {
+ client *mockRunnerClient
+}
+
+type mockRunnerClient struct {
+ pingServiceClient pingv1connect.PingServiceClient
+ runnerServiceClient runnerv1connect.RunnerServiceClient
+}
+
+func newMockRunner() *mockRunner {
+ client := newMockRunnerClient("", "")
+ return &mockRunner{client: client}
+}
+
+func newMockRunnerClient(uuid, token string) *mockRunnerClient {
+ baseURL := setting.AppURL + "api/actions"
+
+ opt := connect.WithInterceptors(connect.UnaryInterceptorFunc(func(next connect.UnaryFunc) connect.UnaryFunc {
+ return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
+ if uuid != "" {
+ req.Header().Set("x-runner-uuid", uuid)
+ }
+ if token != "" {
+ req.Header().Set("x-runner-token", token)
+ }
+ return next(ctx, req)
+ }
+ }))
+
+ client := &mockRunnerClient{
+ pingServiceClient: pingv1connect.NewPingServiceClient(http.DefaultClient, baseURL, opt),
+ runnerServiceClient: runnerv1connect.NewRunnerServiceClient(http.DefaultClient, baseURL, opt),
+ }
+
+ return client
+}
+
+func (r *mockRunner) doPing(t *testing.T) {
+ resp, err := r.client.pingServiceClient.Ping(t.Context(), connect.NewRequest(&pingv1.PingRequest{
+ Data: "mock-runner",
+ }))
+ assert.NoError(t, err)
+ assert.Equal(t, "Hello, mock-runner!", resp.Msg.Data)
+}
+
+func (r *mockRunner) doRegister(t *testing.T, name, token string, labels []string, ephemeral bool) {
+ r.doPing(t)
+ resp, err := r.client.runnerServiceClient.Register(t.Context(), connect.NewRequest(&runnerv1.RegisterRequest{
+ Name: name,
+ Token: token,
+ Version: "mock-runner-version",
+ Labels: labels,
+ Ephemeral: ephemeral,
+ }))
+ assert.NoError(t, err)
+ r.client = newMockRunnerClient(resp.Msg.Runner.Uuid, resp.Msg.Runner.Token)
+}
+
+func (r *mockRunner) registerAsRepoRunner(t *testing.T, ownerName, repoName, runnerName string, labels []string, ephemeral bool) {
+ session := loginUser(t, ownerName)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+ req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/actions/runners/registration-token", ownerName, repoName)).AddTokenAuth(token)
+ resp := MakeRequest(t, req, http.StatusOK)
+ var registrationToken struct {
+ Token string `json:"token"`
+ }
+ DecodeJSON(t, resp, &registrationToken)
+ r.doRegister(t, runnerName, registrationToken.Token, labels, ephemeral)
+}
+
+func (r *mockRunner) fetchTask(t *testing.T, timeout ...time.Duration) *runnerv1.Task {
+ fetchTimeout := 10 * time.Second
+ if len(timeout) > 0 {
+ fetchTimeout = timeout[0]
+ }
+ ddl := time.Now().Add(fetchTimeout)
+ var task *runnerv1.Task
+ for time.Now().Before(ddl) {
+ resp, err := r.client.runnerServiceClient.FetchTask(t.Context(), connect.NewRequest(&runnerv1.FetchTaskRequest{
+ TasksVersion: 0,
+ }))
+ assert.NoError(t, err)
+ if resp.Msg.Task != nil {
+ task = resp.Msg.Task
+ break
+ }
+ time.Sleep(time.Second)
+ }
+ assert.NotNil(t, task, "failed to fetch a task")
+ return task
+}
+
+type mockTaskOutcome struct {
+ result runnerv1.Result
+ outputs map[string]string
+ logRows []*runnerv1.LogRow
+}
+
+func (r *mockRunner) execTask(t *testing.T, task *runnerv1.Task, outcome *mockTaskOutcome) {
+ for idx, lr := range outcome.logRows {
+ resp, err := r.client.runnerServiceClient.UpdateLog(t.Context(), connect.NewRequest(&runnerv1.UpdateLogRequest{
+ TaskId: task.Id,
+ Index: int64(idx),
+ Rows: []*runnerv1.LogRow{lr},
+ NoMore: idx == len(outcome.logRows)-1,
+ }))
+ assert.NoError(t, err)
+ assert.EqualValues(t, idx+1, resp.Msg.AckIndex)
+ }
+ sentOutputKeys := make([]string, 0, len(outcome.outputs))
+ for outputKey, outputValue := range outcome.outputs {
+ resp, err := r.client.runnerServiceClient.UpdateTask(t.Context(), connect.NewRequest(&runnerv1.UpdateTaskRequest{
+ State: &runnerv1.TaskState{
+ Id: task.Id,
+ Result: runnerv1.Result_RESULT_UNSPECIFIED,
+ },
+ Outputs: map[string]string{outputKey: outputValue},
+ }))
+ assert.NoError(t, err)
+ sentOutputKeys = append(sentOutputKeys, outputKey)
+ assert.ElementsMatch(t, sentOutputKeys, resp.Msg.SentOutputs)
+ }
+ resp, err := r.client.runnerServiceClient.UpdateTask(t.Context(), connect.NewRequest(&runnerv1.UpdateTaskRequest{
+ State: &runnerv1.TaskState{
+ Id: task.Id,
+ Result: outcome.result,
+ StoppedAt: timestamppb.Now(),
+ },
+ }))
+ assert.NoError(t, err)
+ assert.Equal(t, outcome.result, resp.Msg.State.Result)
+}
diff --git a/tests/integration/actions_trigger_test.go b/tests/integration/actions_trigger_test.go
index 4718aa7e73..088491d570 100644
--- a/tests/integration/actions_trigger_test.go
+++ b/tests/integration/actions_trigger_test.go
@@ -4,7 +4,9 @@
package integration
import (
+ "encoding/base64"
"fmt"
+ "net/http"
"net/url"
"strings"
"testing"
@@ -17,17 +19,23 @@ import (
issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
- unit_model "code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
actions_module "code.gitea.io/gitea/modules/actions"
+ "code.gitea.io/gitea/modules/commitstatus"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
+ "code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/setting"
+ api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/test"
+ "code.gitea.io/gitea/modules/timeutil"
+ "code.gitea.io/gitea/modules/util"
+ issue_service "code.gitea.io/gitea/services/issue"
pull_service "code.gitea.io/gitea/services/pull"
release_service "code.gitea.io/gitea/services/release"
repo_service "code.gitea.io/gitea/services/repository"
+ commitstatus_service "code.gitea.io/gitea/services/repository/commitstatus"
files_service "code.gitea.io/gitea/services/repository/files"
"github.com/stretchr/testify/assert"
@@ -52,13 +60,6 @@ func TestPullRequestTargetEvent(t *testing.T) {
assert.NoError(t, err)
assert.NotEmpty(t, baseRepo)
- // enable actions
- err = repo_service.UpdateRepositoryUnits(db.DefaultContext, baseRepo, []repo_model.RepoUnit{{
- RepoID: baseRepo.ID,
- Type: unit_model.TypeActions,
- }}, nil)
- assert.NoError(t, err)
-
// add user4 as the collaborator
ctx := NewAPITestContext(t, baseRepo.OwnerName, baseRepo.Name, auth_model.AccessTokenScopeWriteRepository)
t.Run("AddUser4AsCollaboratorWithReadAccess", doAPIAddCollaborator(ctx, "user4", perm.AccessModeRead))
@@ -76,21 +77,31 @@ func TestPullRequestTargetEvent(t *testing.T) {
addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, baseRepo, user2, &files_service.ChangeRepoFilesOptions{
Files: []*files_service.ChangeRepoFile{
{
- Operation: "create",
- TreePath: ".gitea/workflows/pr.yml",
- ContentReader: strings.NewReader("name: test\non:\n pull_request_target:\n paths:\n - 'file_*.txt'\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - run: echo helloworld\n"),
+ Operation: "create",
+ TreePath: ".gitea/workflows/pr.yml",
+ ContentReader: strings.NewReader(`name: test
+on:
+ pull_request_target:
+ paths:
+ - 'file_*.txt'
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo helloworld
+`),
},
},
Message: "add workflow",
OldBranch: "main",
NewBranch: "main",
Author: &files_service.IdentityOptions{
- Name: user2.Name,
- Email: user2.Email,
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
},
Committer: &files_service.IdentityOptions{
- Name: user2.Name,
- Email: user2.Email,
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
},
Dates: &files_service.CommitDateOptions{
Author: time.Now(),
@@ -113,12 +124,12 @@ func TestPullRequestTargetEvent(t *testing.T) {
OldBranch: "main",
NewBranch: "fork-branch-1",
Author: &files_service.IdentityOptions{
- Name: user4.Name,
- Email: user4.Email,
+ GitUserName: user4.Name,
+ GitUserEmail: user4.Email,
},
Committer: &files_service.IdentityOptions{
- Name: user4.Name,
- Email: user4.Email,
+ GitUserName: user4.Name,
+ GitUserEmail: user4.Email,
},
Dates: &files_service.CommitDateOptions{
Author: time.Now(),
@@ -168,12 +179,12 @@ func TestPullRequestTargetEvent(t *testing.T) {
OldBranch: "main",
NewBranch: "fork-branch-2",
Author: &files_service.IdentityOptions{
- Name: user4.Name,
- Email: user4.Email,
+ GitUserName: user4.Name,
+ GitUserEmail: user4.Email,
},
Committer: &files_service.IdentityOptions{
- Name: user4.Name,
- Email: user4.Email,
+ GitUserName: user4.Name,
+ GitUserEmail: user4.Email,
},
Dates: &files_service.CommitDateOptions{
Author: time.Now(),
@@ -228,32 +239,35 @@ func TestSkipCI(t *testing.T) {
assert.NoError(t, err)
assert.NotEmpty(t, repo)
- // enable actions
- err = repo_service.UpdateRepositoryUnits(db.DefaultContext, repo, []repo_model.RepoUnit{{
- RepoID: repo.ID,
- Type: unit_model.TypeActions,
- }}, nil)
- assert.NoError(t, err)
-
// add workflow file to the repo
addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{
Files: []*files_service.ChangeRepoFile{
{
- Operation: "create",
- TreePath: ".gitea/workflows/pr.yml",
- ContentReader: strings.NewReader("name: test\non:\n push:\n branches: [master]\n pull_request:\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - run: echo helloworld\n"),
+ Operation: "create",
+ TreePath: ".gitea/workflows/pr.yml",
+ ContentReader: strings.NewReader(`name: test
+on:
+ push:
+ branches: [master]
+ pull_request:
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo helloworld
+`),
},
},
Message: "add workflow",
OldBranch: "master",
NewBranch: "master",
Author: &files_service.IdentityOptions{
- Name: user2.Name,
- Email: user2.Email,
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
},
Committer: &files_service.IdentityOptions{
- Name: user2.Name,
- Email: user2.Email,
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
},
Dates: &files_service.CommitDateOptions{
Author: time.Now(),
@@ -275,16 +289,16 @@ func TestSkipCI(t *testing.T) {
ContentReader: strings.NewReader("bar"),
},
},
- Message: fmt.Sprintf("%s add bar", setting.Actions.SkipWorkflowStrings[0]),
+ Message: setting.Actions.SkipWorkflowStrings[0] + " add bar",
OldBranch: "master",
NewBranch: "master",
Author: &files_service.IdentityOptions{
- Name: user2.Name,
- Email: user2.Email,
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
},
Committer: &files_service.IdentityOptions{
- Name: user2.Name,
- Email: user2.Email,
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
},
Dates: &files_service.CommitDateOptions{
Author: time.Now(),
@@ -310,12 +324,12 @@ func TestSkipCI(t *testing.T) {
OldBranch: "master",
NewBranch: "test-skip-ci",
Author: &files_service.IdentityOptions{
- Name: user2.Name,
- Email: user2.Email,
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
},
Committer: &files_service.IdentityOptions{
- Name: user2.Name,
- Email: user2.Email,
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
},
Dates: &files_service.CommitDateOptions{
Author: time.Now(),
@@ -354,32 +368,33 @@ func TestCreateDeleteRefEvent(t *testing.T) {
assert.NoError(t, err)
assert.NotEmpty(t, repo)
- // enable actions
- err = repo_service.UpdateRepositoryUnits(db.DefaultContext, repo, []repo_model.RepoUnit{{
- RepoID: repo.ID,
- Type: unit_model.TypeActions,
- }}, nil)
- assert.NoError(t, err)
-
// add workflow file to the repo
addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{
Files: []*files_service.ChangeRepoFile{
{
- Operation: "create",
- TreePath: ".gitea/workflows/createdelete.yml",
- ContentReader: strings.NewReader("name: test\non:\n [create,delete]\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - run: echo helloworld\n"),
+ Operation: "create",
+ TreePath: ".gitea/workflows/createdelete.yml",
+ ContentReader: strings.NewReader(`name: test
+on:
+ [create,delete]
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo helloworld
+`),
},
},
Message: "add workflow",
OldBranch: "main",
NewBranch: "main",
Author: &files_service.IdentityOptions{
- Name: user2.Name,
- Email: user2.Email,
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
},
Committer: &files_service.IdentityOptions{
- Name: user2.Name,
- Email: user2.Email,
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
},
Dates: &files_service.CommitDateOptions{
Author: time.Now(),
@@ -423,7 +438,7 @@ func TestCreateDeleteRefEvent(t *testing.T) {
assert.NotNil(t, run)
// delete the branch
- err = repo_service.DeleteBranch(db.DefaultContext, user2, repo, gitRepo, "test-create-branch")
+ err = repo_service.DeleteBranch(db.DefaultContext, user2, repo, gitRepo, "test-create-branch", nil)
assert.NoError(t, err)
run = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{
Title: "add workflow",
@@ -451,3 +466,1141 @@ func TestCreateDeleteRefEvent(t *testing.T) {
assert.NotNil(t, run)
})
}
+
+func TestPullRequestCommitStatusEvent(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo
+ user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // contributor of the repo
+
+ // create a repo
+ repo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{
+ Name: "repo-pull-request",
+ Description: "test pull-request event",
+ AutoInit: true,
+ Gitignores: "Go",
+ License: "MIT",
+ Readme: "Default",
+ DefaultBranch: "main",
+ IsPrivate: false,
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, repo)
+
+ // add user4 as the collaborator
+ ctx := NewAPITestContext(t, repo.OwnerName, repo.Name, auth_model.AccessTokenScopeWriteRepository)
+ t.Run("AddUser4AsCollaboratorWithReadAccess", doAPIAddCollaborator(ctx, "user4", perm.AccessModeRead))
+
+ // add the workflow file to the repo
+ addWorkflow, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{
+ Files: []*files_service.ChangeRepoFile{
+ {
+ Operation: "create",
+ TreePath: ".gitea/workflows/pr.yml",
+ ContentReader: strings.NewReader(`name: test
+on:
+ pull_request:
+ types: [assigned, unassigned, labeled, unlabeled, opened, edited, closed, reopened, synchronize, milestoned, demilestoned, review_requested, review_request_removed]
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo helloworld
+`),
+ },
+ },
+ Message: "add workflow",
+ OldBranch: "main",
+ NewBranch: "main",
+ Author: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Committer: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Dates: &files_service.CommitDateOptions{
+ Author: time.Now(),
+ Committer: time.Now(),
+ },
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, addWorkflow)
+ sha := addWorkflow.Commit.SHA
+
+ // create a new branch
+ testBranch := "test-branch"
+ gitRepo, err := git.OpenRepository(git.DefaultContext, ".")
+ assert.NoError(t, err)
+ err = repo_service.CreateNewBranch(git.DefaultContext, user2, repo, gitRepo, "main", testBranch)
+ assert.NoError(t, err)
+
+ // create Pull
+ pullIssue := &issues_model.Issue{
+ RepoID: repo.ID,
+ Title: "A test PR",
+ PosterID: user2.ID,
+ Poster: user2,
+ IsPull: true,
+ }
+ pullRequest := &issues_model.PullRequest{
+ HeadRepoID: repo.ID,
+ BaseRepoID: repo.ID,
+ HeadBranch: testBranch,
+ BaseBranch: "main",
+ HeadRepo: repo,
+ BaseRepo: repo,
+ Type: issues_model.PullRequestGitea,
+ }
+ prOpts := &pull_service.NewPullRequestOptions{Repo: repo, Issue: pullIssue, PullRequest: pullRequest}
+ err = pull_service.NewPullRequest(db.DefaultContext, prOpts)
+ assert.NoError(t, err)
+
+ // opened
+ checkCommitStatusAndInsertFakeStatus(t, repo, sha)
+
+ // edited
+ err = issue_service.ChangeContent(db.DefaultContext, pullIssue, user2, "test", 0)
+ assert.NoError(t, err)
+ checkCommitStatusAndInsertFakeStatus(t, repo, sha)
+
+ // closed
+ err = issue_service.CloseIssue(db.DefaultContext, pullIssue, user2, "")
+ assert.NoError(t, err)
+ checkCommitStatusAndInsertFakeStatus(t, repo, sha)
+
+ // reopened
+ err = issue_service.ReopenIssue(db.DefaultContext, pullIssue, user2, "")
+ assert.NoError(t, err)
+ checkCommitStatusAndInsertFakeStatus(t, repo, sha)
+
+ // assign
+ removed, _, err := issue_service.ToggleAssigneeWithNotify(db.DefaultContext, pullIssue, user2, user4.ID)
+ assert.False(t, removed)
+ assert.NoError(t, err)
+ checkCommitStatusAndInsertFakeStatus(t, repo, sha)
+
+ // unassign
+ removed, _, err = issue_service.ToggleAssigneeWithNotify(db.DefaultContext, pullIssue, user2, user4.ID)
+ assert.True(t, removed)
+ assert.NoError(t, err)
+ checkCommitStatusAndInsertFakeStatus(t, repo, sha)
+
+ // labeled
+ label := &issues_model.Label{
+ RepoID: repo.ID,
+ Name: "test",
+ Exclusive: false,
+ Description: "test",
+ Color: "#e11d21",
+ }
+ err = issues_model.NewLabel(db.DefaultContext, label)
+ assert.NoError(t, err)
+ err = issue_service.AddLabel(db.DefaultContext, pullIssue, user2, label)
+ assert.NoError(t, err)
+ checkCommitStatusAndInsertFakeStatus(t, repo, sha)
+
+ // unlabeled
+ err = issue_service.RemoveLabel(db.DefaultContext, pullIssue, user2, label)
+ assert.NoError(t, err)
+ checkCommitStatusAndInsertFakeStatus(t, repo, sha)
+
+ // synchronize
+ addFileResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{
+ Files: []*files_service.ChangeRepoFile{
+ {
+ Operation: "create",
+ TreePath: "test.txt",
+ ContentReader: strings.NewReader("test"),
+ },
+ },
+ Message: "add file",
+ OldBranch: testBranch,
+ NewBranch: testBranch,
+ Author: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Committer: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Dates: &files_service.CommitDateOptions{
+ Author: time.Now(),
+ Committer: time.Now(),
+ },
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, addFileResp)
+ sha = addFileResp.Commit.SHA
+ assert.Eventually(t, func() bool {
+ latestCommitStatuses, err := git_model.GetLatestCommitStatus(db.DefaultContext, repo.ID, sha, db.ListOptionsAll)
+ assert.NoError(t, err)
+ if len(latestCommitStatuses) == 0 {
+ return false
+ }
+ if latestCommitStatuses[0].State == commitstatus.CommitStatusPending {
+ insertFakeStatus(t, repo, sha, latestCommitStatuses[0].TargetURL, latestCommitStatuses[0].Context)
+ return true
+ }
+ return false
+ }, 1*time.Second, 100*time.Millisecond)
+
+ // milestoned
+ milestone := &issues_model.Milestone{
+ RepoID: repo.ID,
+ Name: "test",
+ Content: "test",
+ DeadlineUnix: timeutil.TimeStampNow(),
+ }
+ err = issues_model.NewMilestone(db.DefaultContext, milestone)
+ assert.NoError(t, err)
+ err = issue_service.ChangeMilestoneAssign(db.DefaultContext, pullIssue, user2, milestone.ID)
+ assert.NoError(t, err)
+ checkCommitStatusAndInsertFakeStatus(t, repo, sha)
+
+ // demilestoned
+ err = issue_service.ChangeMilestoneAssign(db.DefaultContext, pullIssue, user2, milestone.ID)
+ assert.NoError(t, err)
+ checkCommitStatusAndInsertFakeStatus(t, repo, sha)
+
+ // review_requested
+ _, err = issue_service.ReviewRequest(db.DefaultContext, pullIssue, user2, nil, user4, true)
+ assert.NoError(t, err)
+ checkCommitStatusAndInsertFakeStatus(t, repo, sha)
+
+ // review_request_removed
+ _, err = issue_service.ReviewRequest(db.DefaultContext, pullIssue, user2, nil, user4, false)
+ assert.NoError(t, err)
+ checkCommitStatusAndInsertFakeStatus(t, repo, sha)
+ })
+}
+
+func checkCommitStatusAndInsertFakeStatus(t *testing.T, repo *repo_model.Repository, sha string) {
+ latestCommitStatuses, err := git_model.GetLatestCommitStatus(db.DefaultContext, repo.ID, sha, db.ListOptionsAll)
+ assert.NoError(t, err)
+ assert.Len(t, latestCommitStatuses, 1)
+ assert.Equal(t, commitstatus.CommitStatusPending, latestCommitStatuses[0].State)
+
+ insertFakeStatus(t, repo, sha, latestCommitStatuses[0].TargetURL, latestCommitStatuses[0].Context)
+}
+
+func insertFakeStatus(t *testing.T, repo *repo_model.Repository, sha, targetURL, context string) {
+ err := commitstatus_service.CreateCommitStatus(db.DefaultContext, repo, user_model.NewActionsUser(), sha, &git_model.CommitStatus{
+ State: commitstatus.CommitStatusSuccess,
+ TargetURL: targetURL,
+ Context: context,
+ })
+ assert.NoError(t, err)
+}
+
+func TestWorkflowDispatchPublicApi(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ session := loginUser(t, user2.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ // create the repo
+ repo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{
+ Name: "workflow-dispatch-event",
+ Description: "test workflow-dispatch ci event",
+ AutoInit: true,
+ Gitignores: "Go",
+ License: "MIT",
+ Readme: "Default",
+ DefaultBranch: "main",
+ IsPrivate: false,
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, repo)
+
+ // add workflow file to the repo
+ addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{
+ Files: []*files_service.ChangeRepoFile{
+ {
+ Operation: "create",
+ TreePath: ".gitea/workflows/dispatch.yml",
+ ContentReader: strings.NewReader(`
+on:
+ workflow_dispatch
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo helloworld
+`),
+ },
+ },
+ Message: "add workflow",
+ OldBranch: "main",
+ NewBranch: "main",
+ Author: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Committer: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Dates: &files_service.CommitDateOptions{
+ Author: time.Now(),
+ Committer: time.Now(),
+ },
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, addWorkflowToBaseResp)
+
+ // Get the commit ID of the default branch
+ gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo)
+ assert.NoError(t, err)
+ defer gitRepo.Close()
+ branch, err := git_model.GetBranch(db.DefaultContext, repo.ID, repo.DefaultBranch)
+ assert.NoError(t, err)
+ values := url.Values{}
+ values.Set("ref", "main")
+ req := NewRequestWithURLValues(t, "POST", fmt.Sprintf("/api/v1/repos/%s/actions/workflows/dispatch.yml/dispatches", repo.FullName()), values).
+ AddTokenAuth(token)
+ _ = MakeRequest(t, req, http.StatusNoContent)
+
+ run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{
+ Title: "add workflow",
+ RepoID: repo.ID,
+ Event: "workflow_dispatch",
+ Ref: "refs/heads/main",
+ WorkflowID: "dispatch.yml",
+ CommitSHA: branch.CommitID,
+ })
+ assert.NotNil(t, run)
+ })
+}
+
+func TestWorkflowDispatchPublicApiWithInputs(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ session := loginUser(t, user2.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ // create the repo
+ repo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{
+ Name: "workflow-dispatch-event",
+ Description: "test workflow-dispatch ci event",
+ AutoInit: true,
+ Gitignores: "Go",
+ License: "MIT",
+ Readme: "Default",
+ DefaultBranch: "main",
+ IsPrivate: false,
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, repo)
+
+ // add workflow file to the repo
+ addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{
+ Files: []*files_service.ChangeRepoFile{
+ {
+ Operation: "create",
+ TreePath: ".gitea/workflows/dispatch.yml",
+ ContentReader: strings.NewReader(`
+on:
+ workflow_dispatch: { inputs: { myinput: { default: def }, myinput2: { default: def2 }, myinput3: { type: boolean, default: false } } }
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo helloworld
+`),
+ },
+ },
+ Message: "add workflow",
+ OldBranch: "main",
+ NewBranch: "main",
+ Author: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Committer: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Dates: &files_service.CommitDateOptions{
+ Author: time.Now(),
+ Committer: time.Now(),
+ },
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, addWorkflowToBaseResp)
+
+ // Get the commit ID of the default branch
+ gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo)
+ assert.NoError(t, err)
+ defer gitRepo.Close()
+ branch, err := git_model.GetBranch(db.DefaultContext, repo.ID, repo.DefaultBranch)
+ assert.NoError(t, err)
+ values := url.Values{}
+ values.Set("ref", "main")
+ values.Set("inputs[myinput]", "val0")
+ values.Set("inputs[myinput3]", "true")
+ req := NewRequestWithURLValues(t, "POST", fmt.Sprintf("/api/v1/repos/%s/actions/workflows/dispatch.yml/dispatches", repo.FullName()), values).
+ AddTokenAuth(token)
+ _ = MakeRequest(t, req, http.StatusNoContent)
+
+ run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{
+ Title: "add workflow",
+ RepoID: repo.ID,
+ Event: "workflow_dispatch",
+ Ref: "refs/heads/main",
+ WorkflowID: "dispatch.yml",
+ CommitSHA: branch.CommitID,
+ })
+ assert.NotNil(t, run)
+ dispatchPayload := &api.WorkflowDispatchPayload{}
+ err = json.Unmarshal([]byte(run.EventPayload), dispatchPayload)
+ assert.NoError(t, err)
+ assert.Contains(t, dispatchPayload.Inputs, "myinput")
+ assert.Contains(t, dispatchPayload.Inputs, "myinput2")
+ assert.Contains(t, dispatchPayload.Inputs, "myinput3")
+ assert.Equal(t, "val0", dispatchPayload.Inputs["myinput"])
+ assert.Equal(t, "def2", dispatchPayload.Inputs["myinput2"])
+ assert.Equal(t, "true", dispatchPayload.Inputs["myinput3"])
+ })
+}
+
+func TestWorkflowDispatchPublicApiJSON(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ session := loginUser(t, user2.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ // create the repo
+ repo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{
+ Name: "workflow-dispatch-event",
+ Description: "test workflow-dispatch ci event",
+ AutoInit: true,
+ Gitignores: "Go",
+ License: "MIT",
+ Readme: "Default",
+ DefaultBranch: "main",
+ IsPrivate: false,
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, repo)
+
+ // add workflow file to the repo
+ addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{
+ Files: []*files_service.ChangeRepoFile{
+ {
+ Operation: "create",
+ TreePath: ".gitea/workflows/dispatch.yml",
+ ContentReader: strings.NewReader(`
+on:
+ workflow_dispatch: { inputs: { myinput: { default: def }, myinput2: { default: def2 }, myinput3: { type: boolean, default: false } } }
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo helloworld
+`),
+ },
+ },
+ Message: "add workflow",
+ OldBranch: "main",
+ NewBranch: "main",
+ Author: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Committer: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Dates: &files_service.CommitDateOptions{
+ Author: time.Now(),
+ Committer: time.Now(),
+ },
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, addWorkflowToBaseResp)
+
+ // Get the commit ID of the default branch
+ gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo)
+ assert.NoError(t, err)
+ defer gitRepo.Close()
+ branch, err := git_model.GetBranch(db.DefaultContext, repo.ID, repo.DefaultBranch)
+ assert.NoError(t, err)
+ inputs := &api.CreateActionWorkflowDispatch{
+ Ref: "main",
+ Inputs: map[string]string{
+ "myinput": "val0",
+ "myinput3": "true",
+ },
+ }
+
+ req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/actions/workflows/dispatch.yml/dispatches", repo.FullName()), inputs).
+ AddTokenAuth(token)
+ _ = MakeRequest(t, req, http.StatusNoContent)
+
+ run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{
+ Title: "add workflow",
+ RepoID: repo.ID,
+ Event: "workflow_dispatch",
+ Ref: "refs/heads/main",
+ WorkflowID: "dispatch.yml",
+ CommitSHA: branch.CommitID,
+ })
+ assert.NotNil(t, run)
+ })
+}
+
+func TestWorkflowDispatchPublicApiWithInputsJSON(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ session := loginUser(t, user2.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ // create the repo
+ repo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{
+ Name: "workflow-dispatch-event",
+ Description: "test workflow-dispatch ci event",
+ AutoInit: true,
+ Gitignores: "Go",
+ License: "MIT",
+ Readme: "Default",
+ DefaultBranch: "main",
+ IsPrivate: false,
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, repo)
+
+ // add workflow file to the repo
+ addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{
+ Files: []*files_service.ChangeRepoFile{
+ {
+ Operation: "create",
+ TreePath: ".gitea/workflows/dispatch.yml",
+ ContentReader: strings.NewReader(`
+on:
+ workflow_dispatch: { inputs: { myinput: { default: def }, myinput2: { default: def2 }, myinput3: { type: boolean, default: false } } }
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo helloworld
+`),
+ },
+ },
+ Message: "add workflow",
+ OldBranch: "main",
+ NewBranch: "main",
+ Author: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Committer: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Dates: &files_service.CommitDateOptions{
+ Author: time.Now(),
+ Committer: time.Now(),
+ },
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, addWorkflowToBaseResp)
+
+ // Get the commit ID of the default branch
+ gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo)
+ assert.NoError(t, err)
+ defer gitRepo.Close()
+ branch, err := git_model.GetBranch(db.DefaultContext, repo.ID, repo.DefaultBranch)
+ assert.NoError(t, err)
+ inputs := &api.CreateActionWorkflowDispatch{
+ Ref: "main",
+ Inputs: map[string]string{
+ "myinput": "val0",
+ "myinput3": "true",
+ },
+ }
+ req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/actions/workflows/dispatch.yml/dispatches", repo.FullName()), inputs).
+ AddTokenAuth(token)
+ _ = MakeRequest(t, req, http.StatusNoContent)
+
+ run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{
+ Title: "add workflow",
+ RepoID: repo.ID,
+ Event: "workflow_dispatch",
+ Ref: "refs/heads/main",
+ WorkflowID: "dispatch.yml",
+ CommitSHA: branch.CommitID,
+ })
+ assert.NotNil(t, run)
+ dispatchPayload := &api.WorkflowDispatchPayload{}
+ err = json.Unmarshal([]byte(run.EventPayload), dispatchPayload)
+ assert.NoError(t, err)
+ assert.Contains(t, dispatchPayload.Inputs, "myinput")
+ assert.Contains(t, dispatchPayload.Inputs, "myinput2")
+ assert.Contains(t, dispatchPayload.Inputs, "myinput3")
+ assert.Equal(t, "val0", dispatchPayload.Inputs["myinput"])
+ assert.Equal(t, "def2", dispatchPayload.Inputs["myinput2"])
+ assert.Equal(t, "true", dispatchPayload.Inputs["myinput3"])
+ })
+}
+
+func TestWorkflowDispatchPublicApiWithInputsNonDefaultBranchJSON(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ session := loginUser(t, user2.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ // create the repo
+ repo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{
+ Name: "workflow-dispatch-event",
+ Description: "test workflow-dispatch ci event",
+ AutoInit: true,
+ Gitignores: "Go",
+ License: "MIT",
+ Readme: "Default",
+ DefaultBranch: "main",
+ IsPrivate: false,
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, repo)
+
+ // add workflow file to the repo
+ addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{
+ Files: []*files_service.ChangeRepoFile{
+ {
+ Operation: "create",
+ TreePath: ".gitea/workflows/dispatch.yml",
+ ContentReader: strings.NewReader(`
+on:
+ workflow_dispatch
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo helloworld
+`),
+ },
+ },
+ Message: "add workflow",
+ OldBranch: "main",
+ NewBranch: "main",
+ Author: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Committer: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Dates: &files_service.CommitDateOptions{
+ Author: time.Now(),
+ Committer: time.Now(),
+ },
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, addWorkflowToBaseResp)
+
+ // add workflow file to the repo
+ addWorkflowToBaseResp, err = files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{
+ Files: []*files_service.ChangeRepoFile{
+ {
+ Operation: "update",
+ TreePath: ".gitea/workflows/dispatch.yml",
+ ContentReader: strings.NewReader(`
+on:
+ workflow_dispatch: { inputs: { myinput: { default: def }, myinput2: { default: def2 }, myinput3: { type: boolean, default: false } } }
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo helloworld
+`),
+ },
+ },
+ Message: "add workflow",
+ OldBranch: "main",
+ NewBranch: "dispatch",
+ Author: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Committer: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Dates: &files_service.CommitDateOptions{
+ Author: time.Now(),
+ Committer: time.Now(),
+ },
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, addWorkflowToBaseResp)
+
+ // Get the commit ID of the dispatch branch
+ gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo)
+ assert.NoError(t, err)
+ defer gitRepo.Close()
+ commit, err := gitRepo.GetBranchCommit("dispatch")
+ assert.NoError(t, err)
+ inputs := &api.CreateActionWorkflowDispatch{
+ Ref: "refs/heads/dispatch",
+ Inputs: map[string]string{
+ "myinput": "val0",
+ "myinput3": "true",
+ },
+ }
+ req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/actions/workflows/dispatch.yml/dispatches", repo.FullName()), inputs).
+ AddTokenAuth(token)
+ _ = MakeRequest(t, req, http.StatusNoContent)
+
+ run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{
+ Title: "add workflow",
+ RepoID: repo.ID,
+ Repo: repo,
+ Event: "workflow_dispatch",
+ Ref: "refs/heads/dispatch",
+ WorkflowID: "dispatch.yml",
+ CommitSHA: commit.ID.String(),
+ })
+ assert.NotNil(t, run)
+ dispatchPayload := &api.WorkflowDispatchPayload{}
+ err = json.Unmarshal([]byte(run.EventPayload), dispatchPayload)
+ assert.NoError(t, err)
+ assert.Contains(t, dispatchPayload.Inputs, "myinput")
+ assert.Contains(t, dispatchPayload.Inputs, "myinput2")
+ assert.Contains(t, dispatchPayload.Inputs, "myinput3")
+ assert.Equal(t, "val0", dispatchPayload.Inputs["myinput"])
+ assert.Equal(t, "def2", dispatchPayload.Inputs["myinput2"])
+ assert.Equal(t, "true", dispatchPayload.Inputs["myinput3"])
+ })
+}
+
+func TestWorkflowApi(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ session := loginUser(t, user2.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ // create the repo
+ repo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{
+ Name: "workflow-api",
+ Description: "test workflow apis",
+ AutoInit: true,
+ Gitignores: "Go",
+ License: "MIT",
+ Readme: "Default",
+ DefaultBranch: "main",
+ IsPrivate: false,
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, repo)
+
+ req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/workflows", repo.FullName())).
+ AddTokenAuth(token)
+ resp := MakeRequest(t, req, http.StatusOK)
+ workflows := &api.ActionWorkflowResponse{}
+ json.NewDecoder(resp.Body).Decode(workflows)
+ assert.Empty(t, workflows.Workflows)
+
+ // add workflow file to the repo
+ addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{
+ Files: []*files_service.ChangeRepoFile{
+ {
+ Operation: "create",
+ TreePath: ".gitea/workflows/dispatch.yml",
+ ContentReader: strings.NewReader(`
+on:
+ workflow_dispatch: { inputs: { myinput: { default: def }, myinput2: { default: def2 }, myinput3: { type: boolean, default: false } } }
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo helloworld
+`),
+ },
+ },
+ Message: "add workflow",
+ OldBranch: "main",
+ NewBranch: "main",
+ Author: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Committer: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Dates: &files_service.CommitDateOptions{
+ Author: time.Now(),
+ Committer: time.Now(),
+ },
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, addWorkflowToBaseResp)
+
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/workflows", repo.FullName())).
+ AddTokenAuth(token)
+ resp = MakeRequest(t, req, http.StatusOK)
+ json.NewDecoder(resp.Body).Decode(workflows)
+ assert.Len(t, workflows.Workflows, 1)
+ assert.Equal(t, "dispatch.yml", workflows.Workflows[0].Name)
+ assert.Equal(t, ".gitea/workflows/dispatch.yml", workflows.Workflows[0].Path)
+ assert.Equal(t, ".gitea/workflows/dispatch.yml", workflows.Workflows[0].Path)
+ assert.Equal(t, "active", workflows.Workflows[0].State)
+
+ // Use a hardcoded api path
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/workflows/%s", repo.FullName(), workflows.Workflows[0].ID)).
+ AddTokenAuth(token)
+ resp = MakeRequest(t, req, http.StatusOK)
+ workflow := &api.ActionWorkflow{}
+ json.NewDecoder(resp.Body).Decode(workflow)
+ assert.Equal(t, workflows.Workflows[0].ID, workflow.ID)
+ assert.Equal(t, workflows.Workflows[0].Path, workflow.Path)
+ assert.Equal(t, workflows.Workflows[0].URL, workflow.URL)
+ assert.Equal(t, workflows.Workflows[0].HTMLURL, workflow.HTMLURL)
+ assert.Equal(t, workflows.Workflows[0].Name, workflow.Name)
+ assert.Equal(t, workflows.Workflows[0].State, workflow.State)
+
+ // Use the provided url instead of the hardcoded one
+ req = NewRequest(t, "GET", workflows.Workflows[0].URL).
+ AddTokenAuth(token)
+ resp = MakeRequest(t, req, http.StatusOK)
+ workflow = &api.ActionWorkflow{}
+ json.NewDecoder(resp.Body).Decode(workflow)
+ assert.Equal(t, workflows.Workflows[0].ID, workflow.ID)
+ assert.Equal(t, workflows.Workflows[0].Path, workflow.Path)
+ assert.Equal(t, workflows.Workflows[0].URL, workflow.URL)
+ assert.Equal(t, workflows.Workflows[0].HTMLURL, workflow.HTMLURL)
+ assert.Equal(t, workflows.Workflows[0].Name, workflow.Name)
+ assert.Equal(t, workflows.Workflows[0].State, workflow.State)
+
+ // Disable the workflow
+ req = NewRequest(t, "PUT", workflows.Workflows[0].URL+"/disable").
+ AddTokenAuth(token)
+ _ = MakeRequest(t, req, http.StatusNoContent)
+
+ // Use the provided url instead of the hardcoded one
+ req = NewRequest(t, "GET", workflows.Workflows[0].URL).
+ AddTokenAuth(token)
+ resp = MakeRequest(t, req, http.StatusOK)
+ workflow = &api.ActionWorkflow{}
+ json.NewDecoder(resp.Body).Decode(workflow)
+ assert.Equal(t, workflows.Workflows[0].ID, workflow.ID)
+ assert.Equal(t, workflows.Workflows[0].Path, workflow.Path)
+ assert.Equal(t, workflows.Workflows[0].URL, workflow.URL)
+ assert.Equal(t, workflows.Workflows[0].HTMLURL, workflow.HTMLURL)
+ assert.Equal(t, workflows.Workflows[0].Name, workflow.Name)
+ assert.Equal(t, "disabled_manually", workflow.State)
+
+ inputs := &api.CreateActionWorkflowDispatch{
+ Ref: "main",
+ Inputs: map[string]string{
+ "myinput": "val0",
+ "myinput3": "true",
+ },
+ }
+ // Since the workflow is disabled, so the response code is 403 forbidden
+ req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/actions/workflows/dispatch.yml/dispatches", repo.FullName()), inputs).
+ AddTokenAuth(token)
+ _ = MakeRequest(t, req, http.StatusForbidden)
+
+ // Enable the workflow again
+ req = NewRequest(t, "PUT", workflows.Workflows[0].URL+"/enable").
+ AddTokenAuth(token)
+ _ = MakeRequest(t, req, http.StatusNoContent)
+
+ // Use the provided url instead of the hardcoded one
+ req = NewRequest(t, "GET", workflows.Workflows[0].URL).
+ AddTokenAuth(token)
+ resp = MakeRequest(t, req, http.StatusOK)
+ workflow = &api.ActionWorkflow{}
+ json.NewDecoder(resp.Body).Decode(workflow)
+ assert.Equal(t, workflows.Workflows[0].ID, workflow.ID)
+ assert.Equal(t, workflows.Workflows[0].Path, workflow.Path)
+ assert.Equal(t, workflows.Workflows[0].URL, workflow.URL)
+ assert.Equal(t, workflows.Workflows[0].HTMLURL, workflow.HTMLURL)
+ assert.Equal(t, workflows.Workflows[0].Name, workflow.Name)
+ assert.Equal(t, workflows.Workflows[0].State, workflow.State)
+
+ req = NewRequest(t, "GET", workflows.Workflows[0].URL).
+ AddTokenAuth(token)
+ resp = MakeRequest(t, req, http.StatusOK)
+ workflow = &api.ActionWorkflow{}
+ json.NewDecoder(resp.Body).Decode(workflow)
+ assert.Equal(t, workflows.Workflows[0].ID, workflow.ID)
+ assert.Equal(t, workflows.Workflows[0].Path, workflow.Path)
+ assert.Equal(t, workflows.Workflows[0].URL, workflow.URL)
+ assert.Equal(t, workflows.Workflows[0].HTMLURL, workflow.HTMLURL)
+ assert.Equal(t, workflows.Workflows[0].Name, workflow.Name)
+ assert.Equal(t, workflows.Workflows[0].State, workflow.State)
+
+ // Get the commit ID of the default branch
+ gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo)
+ assert.NoError(t, err)
+ defer gitRepo.Close()
+ branch, err := git_model.GetBranch(db.DefaultContext, repo.ID, repo.DefaultBranch)
+ assert.NoError(t, err)
+ inputs = &api.CreateActionWorkflowDispatch{
+ Ref: "main",
+ Inputs: map[string]string{
+ "myinput": "val0",
+ "myinput3": "true",
+ },
+ }
+ req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/actions/workflows/dispatch.yml/dispatches", repo.FullName()), inputs).
+ AddTokenAuth(token)
+ _ = MakeRequest(t, req, http.StatusNoContent)
+
+ run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{
+ Title: "add workflow",
+ RepoID: repo.ID,
+ Event: "workflow_dispatch",
+ Ref: "refs/heads/main",
+ WorkflowID: "dispatch.yml",
+ CommitSHA: branch.CommitID,
+ })
+ assert.NotNil(t, run)
+ dispatchPayload := &api.WorkflowDispatchPayload{}
+ err = json.Unmarshal([]byte(run.EventPayload), dispatchPayload)
+ assert.NoError(t, err)
+ assert.Contains(t, dispatchPayload.Inputs, "myinput")
+ assert.Contains(t, dispatchPayload.Inputs, "myinput2")
+ assert.Contains(t, dispatchPayload.Inputs, "myinput3")
+ assert.Equal(t, "val0", dispatchPayload.Inputs["myinput"])
+ assert.Equal(t, "def2", dispatchPayload.Inputs["myinput2"])
+ assert.Equal(t, "true", dispatchPayload.Inputs["myinput3"])
+ })
+}
+
+func TestClosePullRequestWithPath(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ // user2 is the owner of the base repo
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ user2Token := getTokenForLoggedInUser(t, loginUser(t, user2.Name), auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
+ // user4 is the owner of the fork repo
+ user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
+ user4Token := getTokenForLoggedInUser(t, loginUser(t, user4.Name), auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
+
+ // create the base repo
+ apiBaseRepo := createActionsTestRepo(t, user2Token, "close-pull-request-with-path", false)
+ baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiBaseRepo.ID})
+ user2APICtx := NewAPITestContext(t, baseRepo.OwnerName, baseRepo.Name, auth_model.AccessTokenScopeWriteRepository)
+
+ // init the workflow
+ wfTreePath := ".gitea/workflows/pull.yml"
+ wfFileContent := `name: Pull Request
+on:
+ pull_request:
+ types:
+ - closed
+ paths:
+ - 'app/**'
+jobs:
+ echo:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo 'Hello World'
+`
+ opts1 := getWorkflowCreateFileOptions(user2, baseRepo.DefaultBranch, "create "+wfTreePath, wfFileContent)
+ createWorkflowFile(t, user2Token, baseRepo.OwnerName, baseRepo.Name, wfTreePath, opts1)
+
+ // user4 forks the repo
+ req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/forks", baseRepo.OwnerName, baseRepo.Name),
+ &api.CreateForkOption{
+ Name: util.ToPointer("close-pull-request-with-path-fork"),
+ }).AddTokenAuth(user4Token)
+ resp := MakeRequest(t, req, http.StatusAccepted)
+ var apiForkRepo api.Repository
+ DecodeJSON(t, resp, &apiForkRepo)
+ forkRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiForkRepo.ID})
+ user4APICtx := NewAPITestContext(t, user4.Name, forkRepo.Name, auth_model.AccessTokenScopeWriteRepository)
+
+ // user4 creates a pull request to add file "app/main.go"
+ doAPICreateFile(user4APICtx, "app/main.go", &api.CreateFileOptions{
+ FileOptions: api.FileOptions{
+ NewBranchName: "user4/add-main",
+ Message: "create main.go",
+ Author: api.Identity{
+ Name: user4.Name,
+ Email: user4.Email,
+ },
+ Committer: api.Identity{
+ Name: user4.Name,
+ Email: user4.Email,
+ },
+ Dates: api.CommitDateOptions{
+ Author: time.Now(),
+ Committer: time.Now(),
+ },
+ },
+ ContentBase64: base64.StdEncoding.EncodeToString([]byte("// main.go")),
+ })(t)
+ apiPull, err := doAPICreatePullRequest(user4APICtx, baseRepo.OwnerName, baseRepo.Name, baseRepo.DefaultBranch, user4.Name+":user4/add-main")(t)
+ assert.NoError(t, err)
+
+ doAPIMergePullRequest(user2APICtx, baseRepo.OwnerName, baseRepo.Name, apiPull.Index)(t)
+
+ pullRequest := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: apiPull.ID})
+
+ // load and compare ActionRun
+ assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: baseRepo.ID}))
+ actionRun := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{RepoID: baseRepo.ID})
+ assert.Equal(t, actions_module.GithubEventPullRequest, actionRun.TriggerEvent)
+ assert.Equal(t, pullRequest.MergedCommitID, actionRun.CommitSHA)
+ })
+}
+
+func TestActionRunNameWithContextVariables(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+
+ // create the repo
+ repo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{
+ Name: "action-run-name-with-variables",
+ Description: "test action run name",
+ AutoInit: true,
+ Gitignores: "Go",
+ License: "MIT",
+ Readme: "Default",
+ DefaultBranch: "main",
+ IsPrivate: false,
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, repo)
+
+ // add workflow file to the repo
+ addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{
+ Files: []*files_service.ChangeRepoFile{
+ {
+ Operation: "create",
+ TreePath: ".gitea/workflows/runname.yml",
+ ContentReader: strings.NewReader(`name: test
+on:
+ [create,delete]
+run-name: ${{ gitea.actor }} is running this workflow
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo helloworld
+`),
+ },
+ },
+ Message: "add workflow with run-name",
+ OldBranch: "main",
+ NewBranch: "main",
+ Author: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Committer: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Dates: &files_service.CommitDateOptions{
+ Author: time.Now(),
+ Committer: time.Now(),
+ },
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, addWorkflowToBaseResp)
+
+ // Get the commit ID of the default branch
+ gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo)
+ assert.NoError(t, err)
+ defer gitRepo.Close()
+ branch, err := git_model.GetBranch(db.DefaultContext, repo.ID, repo.DefaultBranch)
+ assert.NoError(t, err)
+
+ // create a branch
+ err = repo_service.CreateNewBranchFromCommit(db.DefaultContext, user2, repo, gitRepo, branch.CommitID, "test-action-run-name-with-variables")
+ assert.NoError(t, err)
+ run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{
+ Title: user2.LoginName + " is running this workflow",
+ RepoID: repo.ID,
+ Event: "create",
+ Ref: "refs/heads/test-action-run-name-with-variables",
+ WorkflowID: "runname.yml",
+ CommitSHA: branch.CommitID,
+ })
+ assert.NotNil(t, run)
+ })
+}
+
+func TestActionRunName(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+
+ // create the repo
+ repo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{
+ Name: "action-run-name",
+ Description: "test action run-name",
+ AutoInit: true,
+ Gitignores: "Go",
+ License: "MIT",
+ Readme: "Default",
+ DefaultBranch: "main",
+ IsPrivate: false,
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, repo)
+
+ // add workflow file to the repo
+ addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{
+ Files: []*files_service.ChangeRepoFile{
+ {
+ Operation: "create",
+ TreePath: ".gitea/workflows/runname.yml",
+ ContentReader: strings.NewReader(`name: test
+on:
+ [create,delete]
+run-name: run name without variables
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo helloworld
+`),
+ },
+ },
+ Message: "add workflow with run name",
+ OldBranch: "main",
+ NewBranch: "main",
+ Author: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Committer: &files_service.IdentityOptions{
+ GitUserName: user2.Name,
+ GitUserEmail: user2.Email,
+ },
+ Dates: &files_service.CommitDateOptions{
+ Author: time.Now(),
+ Committer: time.Now(),
+ },
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, addWorkflowToBaseResp)
+
+ // Get the commit ID of the default branch
+ gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo)
+ assert.NoError(t, err)
+ defer gitRepo.Close()
+ branch, err := git_model.GetBranch(db.DefaultContext, repo.ID, repo.DefaultBranch)
+ assert.NoError(t, err)
+
+ // create a branch
+ err = repo_service.CreateNewBranchFromCommit(db.DefaultContext, user2, repo, gitRepo, branch.CommitID, "test-action-run-name")
+ assert.NoError(t, err)
+ run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{
+ Title: "run name without variables",
+ RepoID: repo.ID,
+ Event: "create",
+ Ref: "refs/heads/test-action-run-name",
+ WorkflowID: "runname.yml",
+ CommitSHA: branch.CommitID,
+ })
+ assert.NotNil(t, run)
+ })
+}
diff --git a/tests/integration/actions_variables_test.go b/tests/integration/actions_variables_test.go
new file mode 100644
index 0000000000..c0d0bd371b
--- /dev/null
+++ b/tests/integration/actions_variables_test.go
@@ -0,0 +1,148 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package integration
+
+import (
+ "fmt"
+ "net/http"
+ "testing"
+
+ actions_model "code.gitea.io/gitea/models/actions"
+ "code.gitea.io/gitea/models/db"
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/tests"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestActionsVariables(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+
+ ctx := t.Context()
+
+ require.NoError(t, db.DeleteAllRecords("action_variable"))
+
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ _, _ = actions_model.InsertVariable(ctx, user2.ID, 0, "VAR", "user2-var", "user2-var-description")
+ user2Var := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionVariable{OwnerID: user2.ID, Name: "VAR"})
+ userWebURL := "/user/settings/actions/variables"
+
+ org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3, Type: user_model.UserTypeOrganization})
+ _, _ = actions_model.InsertVariable(ctx, org3.ID, 0, "VAR", "org3-var", "org3-var-description")
+ org3Var := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionVariable{OwnerID: org3.ID, Name: "VAR"})
+ orgWebURL := "/org/org3/settings/actions/variables"
+
+ repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+ _, _ = actions_model.InsertVariable(ctx, 0, repo1.ID, "VAR", "repo1-var", "repo1-var-description")
+ repo1Var := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionVariable{RepoID: repo1.ID, Name: "VAR"})
+ repoWebURL := "/user2/repo1/settings/actions/variables"
+
+ _, _ = actions_model.InsertVariable(ctx, 0, 0, "VAR", "global-var", "global-var-description")
+ globalVar := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionVariable{Name: "VAR", Data: "global-var"})
+ adminWebURL := "/-/admin/actions/variables"
+
+ sessionAdmin := loginUser(t, "user1")
+ sessionUser2 := loginUser(t, user2.Name)
+
+ doUpdate := func(t *testing.T, sess *TestSession, baseURL string, id int64, data string, expectedStatus int) {
+ req := NewRequestWithValues(t, "POST", fmt.Sprintf("%s/%d/edit", baseURL, id), map[string]string{
+ "_csrf": GetUserCSRFToken(t, sess),
+ "name": "VAR",
+ "data": data,
+ })
+ sess.MakeRequest(t, req, expectedStatus)
+ }
+
+ doDelete := func(t *testing.T, sess *TestSession, baseURL string, id int64, expectedStatus int) {
+ req := NewRequestWithValues(t, "POST", fmt.Sprintf("%s/%d/delete", baseURL, id), map[string]string{
+ "_csrf": GetUserCSRFToken(t, sess),
+ })
+ sess.MakeRequest(t, req, expectedStatus)
+ }
+
+ assertDenied := func(t *testing.T, sess *TestSession, baseURL string, id int64) {
+ doUpdate(t, sess, baseURL, id, "ChangedData", http.StatusNotFound)
+ doDelete(t, sess, baseURL, id, http.StatusNotFound)
+ v := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionVariable{ID: id})
+ assert.Contains(t, v.Data, "-var")
+ }
+
+ assertSuccess := func(t *testing.T, sess *TestSession, baseURL string, id int64) {
+ doUpdate(t, sess, baseURL, id, "ChangedData", http.StatusOK)
+ v := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionVariable{ID: id})
+ assert.Equal(t, "ChangedData", v.Data)
+ doDelete(t, sess, baseURL, id, http.StatusOK)
+ unittest.AssertNotExistsBean(t, &actions_model.ActionVariable{ID: id})
+ }
+
+ t.Run("UpdateUserVar", func(t *testing.T) {
+ theVar := user2Var
+ t.Run("FromOrg", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, orgWebURL, theVar.ID)
+ })
+ t.Run("FromRepo", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, repoWebURL, theVar.ID)
+ })
+ t.Run("FromAdmin", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, adminWebURL, theVar.ID)
+ })
+ })
+
+ t.Run("UpdateOrgVar", func(t *testing.T) {
+ theVar := org3Var
+ t.Run("FromRepo", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, repoWebURL, theVar.ID)
+ })
+ t.Run("FromUser", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, userWebURL, theVar.ID)
+ })
+ t.Run("FromAdmin", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, adminWebURL, theVar.ID)
+ })
+ })
+
+ t.Run("UpdateRepoVar", func(t *testing.T) {
+ theVar := repo1Var
+ t.Run("FromOrg", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, orgWebURL, theVar.ID)
+ })
+ t.Run("FromUser", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, userWebURL, theVar.ID)
+ })
+ t.Run("FromAdmin", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, adminWebURL, theVar.ID)
+ })
+ })
+
+ t.Run("UpdateGlobalVar", func(t *testing.T) {
+ theVar := globalVar
+ t.Run("FromOrg", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, orgWebURL, theVar.ID)
+ })
+ t.Run("FromUser", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, userWebURL, theVar.ID)
+ })
+ t.Run("FromRepo", func(t *testing.T) {
+ assertDenied(t, sessionAdmin, repoWebURL, theVar.ID)
+ })
+ })
+
+ t.Run("UpdateSuccess", func(t *testing.T) {
+ t.Run("User", func(t *testing.T) {
+ assertSuccess(t, sessionUser2, userWebURL, user2Var.ID)
+ })
+ t.Run("Org", func(t *testing.T) {
+ assertSuccess(t, sessionAdmin, orgWebURL, org3Var.ID)
+ })
+ t.Run("Repo", func(t *testing.T) {
+ assertSuccess(t, sessionUser2, repoWebURL, repo1Var.ID)
+ })
+ t.Run("Admin", func(t *testing.T) {
+ assertSuccess(t, sessionAdmin, adminWebURL, globalVar.ID)
+ })
+ })
+}
diff --git a/tests/integration/admin_user_test.go b/tests/integration/admin_user_test.go
index d5d7e70bc7..95e03ab750 100644
--- a/tests/integration/admin_user_test.go
+++ b/tests/integration/admin_user_test.go
@@ -4,6 +4,7 @@
package integration
import (
+ "fmt"
"net/http"
"strconv"
"testing"
@@ -72,12 +73,37 @@ func TestAdminDeleteUser(t *testing.T) {
session := loginUser(t, "user1")
- csrf := GetUserCSRFToken(t, session)
- req := NewRequestWithValues(t, "POST", "/-/admin/users/8/delete", map[string]string{
- "_csrf": csrf,
- })
- session.MakeRequest(t, req, http.StatusSeeOther)
-
- assertUserDeleted(t, 8)
- unittest.CheckConsistencyFor(t, &user_model.User{})
+ usersToDelete := []struct {
+ userID int64
+ purge bool
+ }{
+ {
+ userID: 2,
+ purge: true,
+ },
+ {
+ userID: 8,
+ },
+ }
+
+ for _, entry := range usersToDelete {
+ t.Run(fmt.Sprintf("DeleteUser%d", entry.userID), func(t *testing.T) {
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: entry.userID})
+ assert.NotNil(t, user)
+
+ var query string
+ if entry.purge {
+ query = "?purge=true"
+ }
+
+ csrf := GetUserCSRFToken(t, session)
+ req := NewRequestWithValues(t, "POST", fmt.Sprintf("/-/admin/users/%d/delete%s", entry.userID, query), map[string]string{
+ "_csrf": csrf,
+ })
+ session.MakeRequest(t, req, http.StatusSeeOther)
+
+ assertUserDeleted(t, entry.userID)
+ unittest.CheckConsistencyFor(t, &user_model.User{})
+ })
+ }
}
diff --git a/tests/integration/api_actions_artifact_v4_test.go b/tests/integration/api_actions_artifact_v4_test.go
index 8821472801..3db8bbb82e 100644
--- a/tests/integration/api_actions_artifact_v4_test.go
+++ b/tests/integration/api_actions_artifact_v4_test.go
@@ -8,13 +8,20 @@ import (
"crypto/sha256"
"encoding/hex"
"encoding/xml"
+ "fmt"
"io"
"net/http"
"strings"
"testing"
"time"
+ auth_model "code.gitea.io/gitea/models/auth"
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/storage"
+ api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/routers/api/actions"
actions_service "code.gitea.io/gitea/services/actions"
@@ -334,6 +341,206 @@ func TestActionsArtifactV4DownloadSingle(t *testing.T) {
assert.Equal(t, body, resp.Body.String())
}
+func TestActionsArtifactV4RunDownloadSinglePublicApi(t *testing.T) {
+ defer prepareTestEnvActionsArtifacts(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+ session := loginUser(t, user.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ // confirm artifact can be listed and found by name
+ req := NewRequestWithBody(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/runs/792/artifacts?name=artifact-v4-download", repo.FullName()), nil).
+ AddTokenAuth(token)
+ resp := MakeRequest(t, req, http.StatusOK)
+ var listResp api.ActionArtifactsResponse
+ err := json.Unmarshal(resp.Body.Bytes(), &listResp)
+ assert.NoError(t, err)
+ assert.NotEmpty(t, listResp.Entries[0].ArchiveDownloadURL)
+ assert.Equal(t, "artifact-v4-download", listResp.Entries[0].Name)
+
+ // confirm artifact blob storage url can be retrieved
+ req = NewRequestWithBody(t, "GET", listResp.Entries[0].ArchiveDownloadURL, nil).
+ AddTokenAuth(token)
+
+ resp = MakeRequest(t, req, http.StatusFound)
+
+ // confirm artifact can be downloaded and has expected content
+ req = NewRequestWithBody(t, "GET", resp.Header().Get("Location"), nil).
+ AddTokenAuth(token)
+ resp = MakeRequest(t, req, http.StatusOK)
+
+ body := strings.Repeat("D", 1024)
+ assert.Equal(t, body, resp.Body.String())
+}
+
+func TestActionsArtifactV4DownloadSinglePublicApi(t *testing.T) {
+ defer prepareTestEnvActionsArtifacts(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+ session := loginUser(t, user.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ // confirm artifact can be listed and found by name
+ req := NewRequestWithBody(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/artifacts?name=artifact-v4-download", repo.FullName()), nil).
+ AddTokenAuth(token)
+ resp := MakeRequest(t, req, http.StatusOK)
+ var listResp api.ActionArtifactsResponse
+ err := json.Unmarshal(resp.Body.Bytes(), &listResp)
+ assert.NoError(t, err)
+ assert.NotEmpty(t, listResp.Entries[0].ArchiveDownloadURL)
+ assert.Equal(t, "artifact-v4-download", listResp.Entries[0].Name)
+
+ // confirm artifact blob storage url can be retrieved
+ req = NewRequestWithBody(t, "GET", listResp.Entries[0].ArchiveDownloadURL, nil).
+ AddTokenAuth(token)
+
+ resp = MakeRequest(t, req, http.StatusFound)
+
+ blobLocation := resp.Header().Get("Location")
+
+ // confirm artifact can be downloaded without token and has expected content
+ req = NewRequestWithBody(t, "GET", blobLocation, nil)
+ resp = MakeRequest(t, req, http.StatusOK)
+ body := strings.Repeat("D", 1024)
+ assert.Equal(t, body, resp.Body.String())
+
+ // confirm artifact can not be downloaded without query
+ req = NewRequestWithBody(t, "GET", blobLocation, nil)
+ req.URL.RawQuery = ""
+ _ = MakeRequest(t, req, http.StatusUnauthorized)
+}
+
+func TestActionsArtifactV4DownloadSinglePublicApiPrivateRepo(t *testing.T) {
+ defer prepareTestEnvActionsArtifacts(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+ session := loginUser(t, user.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ // confirm artifact can be listed and found by name
+ req := NewRequestWithBody(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/artifacts?name=artifact-v4-download", repo.FullName()), nil).
+ AddTokenAuth(token)
+ resp := MakeRequest(t, req, http.StatusOK)
+ var listResp api.ActionArtifactsResponse
+ err := json.Unmarshal(resp.Body.Bytes(), &listResp)
+ assert.NoError(t, err)
+ assert.Equal(t, int64(23), listResp.Entries[0].ID)
+ assert.NotEmpty(t, listResp.Entries[0].ArchiveDownloadURL)
+ assert.Equal(t, "artifact-v4-download", listResp.Entries[0].Name)
+
+ // confirm artifact blob storage url can be retrieved
+ req = NewRequestWithBody(t, "GET", listResp.Entries[0].ArchiveDownloadURL, nil).
+ AddTokenAuth(token)
+
+ resp = MakeRequest(t, req, http.StatusFound)
+
+ blobLocation := resp.Header().Get("Location")
+ // confirm artifact can be downloaded without token and has expected content
+ req = NewRequestWithBody(t, "GET", blobLocation, nil)
+ resp = MakeRequest(t, req, http.StatusOK)
+ body := strings.Repeat("D", 1024)
+ assert.Equal(t, body, resp.Body.String())
+
+ // confirm artifact can not be downloaded without query
+ req = NewRequestWithBody(t, "GET", blobLocation, nil)
+ req.URL.RawQuery = ""
+ _ = MakeRequest(t, req, http.StatusUnauthorized)
+}
+
+func TestActionsArtifactV4ListAndGetPublicApi(t *testing.T) {
+ defer prepareTestEnvActionsArtifacts(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+ session := loginUser(t, user.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ // confirm artifact can be listed
+ req := NewRequestWithBody(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/artifacts", repo.FullName()), nil).
+ AddTokenAuth(token)
+ resp := MakeRequest(t, req, http.StatusOK)
+ var listResp api.ActionArtifactsResponse
+ err := json.Unmarshal(resp.Body.Bytes(), &listResp)
+ assert.NoError(t, err)
+
+ for _, artifact := range listResp.Entries {
+ assert.Contains(t, artifact.URL, fmt.Sprintf("/api/v1/repos/%s/actions/artifacts/%d", repo.FullName(), artifact.ID))
+ assert.Contains(t, artifact.ArchiveDownloadURL, fmt.Sprintf("/api/v1/repos/%s/actions/artifacts/%d/zip", repo.FullName(), artifact.ID))
+ req = NewRequestWithBody(t, "GET", listResp.Entries[0].URL, nil).
+ AddTokenAuth(token)
+
+ resp = MakeRequest(t, req, http.StatusOK)
+ var artifactResp api.ActionArtifact
+ err := json.Unmarshal(resp.Body.Bytes(), &artifactResp)
+ assert.NoError(t, err)
+
+ assert.Equal(t, artifact.ID, artifactResp.ID)
+ assert.Equal(t, artifact.Name, artifactResp.Name)
+ assert.Equal(t, artifact.SizeInBytes, artifactResp.SizeInBytes)
+ assert.Equal(t, artifact.URL, artifactResp.URL)
+ assert.Equal(t, artifact.ArchiveDownloadURL, artifactResp.ArchiveDownloadURL)
+ }
+}
+
+func TestActionsArtifactV4GetArtifactMismatchedRepoNotFound(t *testing.T) {
+ defer prepareTestEnvActionsArtifacts(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+ session := loginUser(t, user.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ // confirm artifacts of wrong repo is not visible
+ req := NewRequestWithBody(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/artifacts/%d", repo.FullName(), 22), nil).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNotFound)
+}
+
+func TestActionsArtifactV4DownloadArtifactMismatchedRepoNotFound(t *testing.T) {
+ defer prepareTestEnvActionsArtifacts(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+ session := loginUser(t, user.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ // confirm artifacts of wrong repo is not visible
+ req := NewRequestWithBody(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/artifacts/%d/zip", repo.FullName(), 22), nil).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNotFound)
+}
+
+func TestActionsArtifactV4DownloadArtifactCorrectRepoFound(t *testing.T) {
+ defer prepareTestEnvActionsArtifacts(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+ session := loginUser(t, user.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ // confirm artifacts of correct repo is visible
+ req := NewRequestWithBody(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/artifacts/%d/zip", repo.FullName(), 22), nil).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusFound)
+}
+
+func TestActionsArtifactV4DownloadRawArtifactCorrectRepoMissingSignatureUnauthorized(t *testing.T) {
+ defer prepareTestEnvActionsArtifacts(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+ session := loginUser(t, user.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ // confirm cannot use the raw artifact endpoint even with a correct access token
+ req := NewRequestWithBody(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/artifacts/%d/zip/raw", repo.FullName(), 22), nil).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusUnauthorized)
+}
+
func TestActionsArtifactV4Delete(t *testing.T) {
defer prepareTestEnvActionsArtifacts(t)()
@@ -350,4 +557,72 @@ func TestActionsArtifactV4Delete(t *testing.T) {
var deleteResp actions.DeleteArtifactResponse
protojson.Unmarshal(resp.Body.Bytes(), &deleteResp)
assert.True(t, deleteResp.Ok)
+
+ // confirm artifact is no longer accessible by GetSignedArtifactURL
+ req = NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/GetSignedArtifactURL", toProtoJSON(&actions.GetSignedArtifactURLRequest{
+ Name: "artifact-v4-download",
+ WorkflowRunBackendId: "792",
+ WorkflowJobRunBackendId: "193",
+ })).
+ AddTokenAuth(token)
+ _ = MakeRequest(t, req, http.StatusNotFound)
+
+ // confirm artifact is no longer enumerateable by ListArtifacts and returns length == 0 without error
+ req = NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/ListArtifacts", toProtoJSON(&actions.ListArtifactsRequest{
+ NameFilter: wrapperspb.String("artifact-v4-download"),
+ WorkflowRunBackendId: "792",
+ WorkflowJobRunBackendId: "193",
+ })).AddTokenAuth(token)
+ resp = MakeRequest(t, req, http.StatusOK)
+ var listResp actions.ListArtifactsResponse
+ protojson.Unmarshal(resp.Body.Bytes(), &listResp)
+ assert.Empty(t, listResp.Artifacts)
+}
+
+func TestActionsArtifactV4DeletePublicApi(t *testing.T) {
+ defer prepareTestEnvActionsArtifacts(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+ session := loginUser(t, user.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ // confirm artifacts exists
+ req := NewRequestWithBody(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/artifacts/%d", repo.FullName(), 22), nil).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusOK)
+
+ // delete artifact by id
+ req = NewRequestWithBody(t, "DELETE", fmt.Sprintf("/api/v1/repos/%s/actions/artifacts/%d", repo.FullName(), 22), nil).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNoContent)
+
+ // confirm artifacts has been deleted
+ req = NewRequestWithBody(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/artifacts/%d", repo.FullName(), 22), nil).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNotFound)
+}
+
+func TestActionsArtifactV4DeletePublicApiNotAllowedReadScope(t *testing.T) {
+ defer prepareTestEnvActionsArtifacts(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+ session := loginUser(t, user.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository)
+
+ // confirm artifacts exists
+ req := NewRequestWithBody(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/artifacts/%d", repo.FullName(), 22), nil).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusOK)
+
+ // try delete artifact by id
+ req = NewRequestWithBody(t, "DELETE", fmt.Sprintf("/api/v1/repos/%s/actions/artifacts/%d", repo.FullName(), 22), nil).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusForbidden)
+
+ // confirm artifacts has not been deleted
+ req = NewRequestWithBody(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/artifacts/%d", repo.FullName(), 22), nil).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusOK)
}
diff --git a/tests/integration/api_actions_run_test.go b/tests/integration/api_actions_run_test.go
new file mode 100644
index 0000000000..a0292f8f8b
--- /dev/null
+++ b/tests/integration/api_actions_run_test.go
@@ -0,0 +1,136 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package integration
+
+import (
+ "fmt"
+ "net/http"
+ "testing"
+
+ auth_model "code.gitea.io/gitea/models/auth"
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/json"
+ api "code.gitea.io/gitea/modules/structs"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestAPIActionsGetWorkflowRun(t *testing.T) {
+ defer prepareTestEnvActionsArtifacts(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+ session := loginUser(t, user.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/runs/802802", repo.FullName())).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNotFound)
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/runs/802", repo.FullName())).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNotFound)
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/runs/803", repo.FullName())).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusOK)
+}
+
+func TestAPIActionsGetWorkflowJob(t *testing.T) {
+ defer prepareTestEnvActionsArtifacts(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+ session := loginUser(t, user.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/jobs/198198", repo.FullName())).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNotFound)
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/jobs/198", repo.FullName())).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusOK)
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/jobs/196", repo.FullName())).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNotFound)
+}
+
+func TestAPIActionsDeleteRunCheckPermission(t *testing.T) {
+ defer prepareTestEnvActionsArtifacts(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+ session := loginUser(t, user.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+ testAPIActionsDeleteRun(t, repo, token, http.StatusNotFound)
+}
+
+func TestAPIActionsDeleteRun(t *testing.T) {
+ defer prepareTestEnvActionsArtifacts(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+ session := loginUser(t, user.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ testAPIActionsDeleteRunListArtifacts(t, repo, token, 2)
+ testAPIActionsDeleteRunListTasks(t, repo, token, true)
+ testAPIActionsDeleteRun(t, repo, token, http.StatusNoContent)
+
+ testAPIActionsDeleteRunListArtifacts(t, repo, token, 0)
+ testAPIActionsDeleteRunListTasks(t, repo, token, false)
+ testAPIActionsDeleteRun(t, repo, token, http.StatusNotFound)
+}
+
+func TestAPIActionsDeleteRunRunning(t *testing.T) {
+ defer prepareTestEnvActionsArtifacts(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+ session := loginUser(t, user.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/repos/%s/actions/runs/793", repo.FullName())).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusBadRequest)
+}
+
+func testAPIActionsDeleteRun(t *testing.T, repo *repo_model.Repository, token string, expected int) {
+ req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/repos/%s/actions/runs/795", repo.FullName())).
+ AddTokenAuth(token)
+ MakeRequest(t, req, expected)
+}
+
+func testAPIActionsDeleteRunListArtifacts(t *testing.T, repo *repo_model.Repository, token string, artifacts int) {
+ req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/runs/795/artifacts", repo.FullName())).
+ AddTokenAuth(token)
+ resp := MakeRequest(t, req, http.StatusOK)
+ var listResp api.ActionArtifactsResponse
+ err := json.Unmarshal(resp.Body.Bytes(), &listResp)
+ assert.NoError(t, err)
+ assert.Len(t, listResp.Entries, artifacts)
+}
+
+func testAPIActionsDeleteRunListTasks(t *testing.T, repo *repo_model.Repository, token string, expected bool) {
+ req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/tasks", repo.FullName())).
+ AddTokenAuth(token)
+ resp := MakeRequest(t, req, http.StatusOK)
+ var listResp api.ActionTaskResponse
+ err := json.Unmarshal(resp.Body.Bytes(), &listResp)
+ assert.NoError(t, err)
+ findTask1 := false
+ findTask2 := false
+ for _, entry := range listResp.Entries {
+ if entry.ID == 53 {
+ findTask1 = true
+ continue
+ }
+ if entry.ID == 54 {
+ findTask2 = true
+ continue
+ }
+ }
+ assert.Equal(t, expected, findTask1)
+ assert.Equal(t, expected, findTask2)
+}
diff --git a/tests/integration/api_actions_runner_test.go b/tests/integration/api_actions_runner_test.go
new file mode 100644
index 0000000000..fb9ba5b0c2
--- /dev/null
+++ b/tests/integration/api_actions_runner_test.go
@@ -0,0 +1,342 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package integration
+
+import (
+ "fmt"
+ "net/http"
+ "slices"
+ "testing"
+
+ auth_model "code.gitea.io/gitea/models/auth"
+ api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/tests"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestAPIActionsRunner(t *testing.T) {
+ t.Run("AdminRunner", testActionsRunnerAdmin)
+ t.Run("UserRunner", testActionsRunnerUser)
+ t.Run("OwnerRunner", testActionsRunnerOwner)
+ t.Run("RepoRunner", testActionsRunnerRepo)
+}
+
+func testActionsRunnerAdmin(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+ adminUsername := "user1"
+ token := getUserToken(t, adminUsername, auth_model.AccessTokenScopeWriteAdmin)
+ req := NewRequest(t, "POST", "/api/v1/admin/actions/runners/registration-token").AddTokenAuth(token)
+ tokenResp := MakeRequest(t, req, http.StatusOK)
+ var registrationToken struct {
+ Token string `json:"token"`
+ }
+ DecodeJSON(t, tokenResp, &registrationToken)
+ assert.NotEmpty(t, registrationToken.Token)
+
+ req = NewRequest(t, "GET", "/api/v1/admin/actions/runners").AddTokenAuth(token)
+ runnerListResp := MakeRequest(t, req, http.StatusOK)
+ runnerList := api.ActionRunnersResponse{}
+ DecodeJSON(t, runnerListResp, &runnerList)
+
+ idx := slices.IndexFunc(runnerList.Entries, func(e *api.ActionRunner) bool { return e.ID == 34349 })
+ require.NotEqual(t, -1, idx)
+ expectedRunner := runnerList.Entries[idx]
+ assert.Equal(t, "runner_to_be_deleted", expectedRunner.Name)
+ assert.False(t, expectedRunner.Ephemeral)
+ assert.Len(t, expectedRunner.Labels, 2)
+ assert.Equal(t, "runner_to_be_deleted", expectedRunner.Labels[0].Name)
+ assert.Equal(t, "linux", expectedRunner.Labels[1].Name)
+
+ // Verify all returned runners can be requested and deleted
+ for _, runnerEntry := range runnerList.Entries {
+ // Verify get the runner by id
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/admin/actions/runners/%d", runnerEntry.ID)).AddTokenAuth(token)
+ runnerResp := MakeRequest(t, req, http.StatusOK)
+
+ runner := api.ActionRunner{}
+ DecodeJSON(t, runnerResp, &runner)
+
+ assert.Equal(t, runnerEntry.Name, runner.Name)
+ assert.Equal(t, runnerEntry.ID, runner.ID)
+ assert.Equal(t, runnerEntry.Ephemeral, runner.Ephemeral)
+ assert.ElementsMatch(t, runnerEntry.Labels, runner.Labels)
+
+ req = NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/admin/actions/runners/%d", runnerEntry.ID)).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNoContent)
+
+ // Verify runner deletion
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/admin/actions/runners/%d", runnerEntry.ID)).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNotFound)
+ }
+}
+
+func testActionsRunnerUser(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+ userUsername := "user1"
+ token := getUserToken(t, userUsername, auth_model.AccessTokenScopeWriteUser)
+ req := NewRequest(t, "POST", "/api/v1/user/actions/runners/registration-token").AddTokenAuth(token)
+ tokenResp := MakeRequest(t, req, http.StatusOK)
+ var registrationToken struct {
+ Token string `json:"token"`
+ }
+ DecodeJSON(t, tokenResp, &registrationToken)
+ assert.NotEmpty(t, registrationToken.Token)
+
+ req = NewRequest(t, "GET", "/api/v1/user/actions/runners").AddTokenAuth(token)
+ runnerListResp := MakeRequest(t, req, http.StatusOK)
+ runnerList := api.ActionRunnersResponse{}
+ DecodeJSON(t, runnerListResp, &runnerList)
+
+ assert.Len(t, runnerList.Entries, 1)
+ assert.Equal(t, "runner_to_be_deleted-user", runnerList.Entries[0].Name)
+ assert.Equal(t, int64(34346), runnerList.Entries[0].ID)
+ assert.False(t, runnerList.Entries[0].Ephemeral)
+ assert.Len(t, runnerList.Entries[0].Labels, 2)
+ assert.Equal(t, "runner_to_be_deleted", runnerList.Entries[0].Labels[0].Name)
+ assert.Equal(t, "linux", runnerList.Entries[0].Labels[1].Name)
+
+ // Verify get the runner by id
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/user/actions/runners/%d", runnerList.Entries[0].ID)).AddTokenAuth(token)
+ runnerResp := MakeRequest(t, req, http.StatusOK)
+
+ runner := api.ActionRunner{}
+ DecodeJSON(t, runnerResp, &runner)
+
+ assert.Equal(t, "runner_to_be_deleted-user", runner.Name)
+ assert.Equal(t, int64(34346), runner.ID)
+ assert.False(t, runner.Ephemeral)
+ assert.Len(t, runner.Labels, 2)
+ assert.Equal(t, "runner_to_be_deleted", runner.Labels[0].Name)
+ assert.Equal(t, "linux", runner.Labels[1].Name)
+
+ // Verify delete the runner by id
+ req = NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/user/actions/runners/%d", runnerList.Entries[0].ID)).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNoContent)
+
+ // Verify runner deletion
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/user/actions/runners/%d", runnerList.Entries[0].ID)).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNotFound)
+}
+
+func testActionsRunnerOwner(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+
+ t.Run("GetRunner", func(t *testing.T) {
+ userUsername := "user2"
+ token := getUserToken(t, userUsername, auth_model.AccessTokenScopeReadOrganization)
+ // Verify get the runner by id with read scope
+ req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/orgs/org3/actions/runners/%d", 34347)).AddTokenAuth(token)
+ runnerResp := MakeRequest(t, req, http.StatusOK)
+
+ runner := api.ActionRunner{}
+ DecodeJSON(t, runnerResp, &runner)
+
+ assert.Equal(t, "runner_to_be_deleted-org", runner.Name)
+ assert.Equal(t, int64(34347), runner.ID)
+ assert.False(t, runner.Ephemeral)
+ assert.Len(t, runner.Labels, 2)
+ assert.Equal(t, "runner_to_be_deleted", runner.Labels[0].Name)
+ assert.Equal(t, "linux", runner.Labels[1].Name)
+ })
+
+ t.Run("Access", func(t *testing.T) {
+ userUsername := "user2"
+ token := getUserToken(t, userUsername, auth_model.AccessTokenScopeWriteOrganization)
+ req := NewRequest(t, "POST", "/api/v1/orgs/org3/actions/runners/registration-token").AddTokenAuth(token)
+ tokenResp := MakeRequest(t, req, http.StatusOK)
+ var registrationToken struct {
+ Token string `json:"token"`
+ }
+ DecodeJSON(t, tokenResp, &registrationToken)
+ assert.NotEmpty(t, registrationToken.Token)
+
+ req = NewRequest(t, "GET", "/api/v1/orgs/org3/actions/runners").AddTokenAuth(token)
+ runnerListResp := MakeRequest(t, req, http.StatusOK)
+ runnerList := api.ActionRunnersResponse{}
+ DecodeJSON(t, runnerListResp, &runnerList)
+
+ idx := slices.IndexFunc(runnerList.Entries, func(e *api.ActionRunner) bool { return e.ID == 34347 })
+ require.NotEqual(t, -1, idx)
+ expectedRunner := runnerList.Entries[idx]
+
+ require.NotNil(t, expectedRunner)
+ assert.Equal(t, "runner_to_be_deleted-org", expectedRunner.Name)
+ assert.Equal(t, int64(34347), expectedRunner.ID)
+ assert.False(t, expectedRunner.Ephemeral)
+ assert.Len(t, expectedRunner.Labels, 2)
+ assert.Equal(t, "runner_to_be_deleted", expectedRunner.Labels[0].Name)
+ assert.Equal(t, "linux", expectedRunner.Labels[1].Name)
+
+ // Verify get the runner by id
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/orgs/org3/actions/runners/%d", expectedRunner.ID)).AddTokenAuth(token)
+ runnerResp := MakeRequest(t, req, http.StatusOK)
+
+ runner := api.ActionRunner{}
+ DecodeJSON(t, runnerResp, &runner)
+
+ assert.Equal(t, "runner_to_be_deleted-org", runner.Name)
+ assert.Equal(t, int64(34347), runner.ID)
+ assert.False(t, runner.Ephemeral)
+ assert.Len(t, runner.Labels, 2)
+ assert.Equal(t, "runner_to_be_deleted", runner.Labels[0].Name)
+ assert.Equal(t, "linux", runner.Labels[1].Name)
+
+ // Verify delete the runner by id
+ req = NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/orgs/org3/actions/runners/%d", expectedRunner.ID)).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNoContent)
+
+ // Verify runner deletion
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/orgs/org3/actions/runners/%d", expectedRunner.ID)).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNotFound)
+ })
+
+ t.Run("DeleteReadScopeForbidden", func(t *testing.T) {
+ userUsername := "user2"
+ token := getUserToken(t, userUsername, auth_model.AccessTokenScopeReadOrganization)
+
+ // Verify delete the runner by id is forbidden with read scope
+ req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/orgs/org3/actions/runners/%d", 34347)).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusForbidden)
+ })
+
+ t.Run("GetRepoScopeForbidden", func(t *testing.T) {
+ userUsername := "user2"
+ token := getUserToken(t, userUsername, auth_model.AccessTokenScopeReadRepository)
+ // Verify get the runner by id with read scope
+ req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/orgs/org3/actions/runners/%d", 34347)).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusForbidden)
+ })
+
+ t.Run("GetAdminRunner", func(t *testing.T) {
+ userUsername := "user2"
+ token := getUserToken(t, userUsername, auth_model.AccessTokenScopeReadOrganization)
+ // Verify get a runner by id of different entity is not found
+ // runner.EditableInContext(ownerID, repoID) false
+ req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/orgs/org3/actions/runners/%d", 34349)).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNotFound)
+ })
+
+ t.Run("DeleteAdminRunner", func(t *testing.T) {
+ userUsername := "user2"
+ token := getUserToken(t, userUsername, auth_model.AccessTokenScopeWriteOrganization)
+ // Verify delete a runner by id of different entity is not found
+ // runner.EditableInContext(ownerID, repoID) false
+ req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/orgs/org3/actions/runners/%d", 34349)).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNotFound)
+ })
+}
+
+func testActionsRunnerRepo(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+
+ t.Run("GetRunner", func(t *testing.T) {
+ userUsername := "user2"
+ token := getUserToken(t, userUsername, auth_model.AccessTokenScopeReadRepository)
+ // Verify get the runner by id with read scope
+ req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/user2/repo1/actions/runners/%d", 34348)).AddTokenAuth(token)
+ runnerResp := MakeRequest(t, req, http.StatusOK)
+
+ runner := api.ActionRunner{}
+ DecodeJSON(t, runnerResp, &runner)
+
+ assert.Equal(t, "runner_to_be_deleted-repo1", runner.Name)
+ assert.Equal(t, int64(34348), runner.ID)
+ assert.False(t, runner.Ephemeral)
+ assert.Len(t, runner.Labels, 2)
+ assert.Equal(t, "runner_to_be_deleted", runner.Labels[0].Name)
+ assert.Equal(t, "linux", runner.Labels[1].Name)
+ })
+
+ t.Run("Access", func(t *testing.T) {
+ userUsername := "user2"
+ token := getUserToken(t, userUsername, auth_model.AccessTokenScopeWriteRepository)
+ req := NewRequest(t, "POST", "/api/v1/repos/user2/repo1/actions/runners/registration-token").AddTokenAuth(token)
+ tokenResp := MakeRequest(t, req, http.StatusOK)
+ var registrationToken struct {
+ Token string `json:"token"`
+ }
+ DecodeJSON(t, tokenResp, &registrationToken)
+ assert.NotEmpty(t, registrationToken.Token)
+
+ req = NewRequest(t, "GET", "/api/v1/repos/user2/repo1/actions/runners").AddTokenAuth(token)
+ runnerListResp := MakeRequest(t, req, http.StatusOK)
+ runnerList := api.ActionRunnersResponse{}
+ DecodeJSON(t, runnerListResp, &runnerList)
+
+ assert.Len(t, runnerList.Entries, 1)
+ assert.Equal(t, "runner_to_be_deleted-repo1", runnerList.Entries[0].Name)
+ assert.Equal(t, int64(34348), runnerList.Entries[0].ID)
+ assert.False(t, runnerList.Entries[0].Ephemeral)
+ assert.Len(t, runnerList.Entries[0].Labels, 2)
+ assert.Equal(t, "runner_to_be_deleted", runnerList.Entries[0].Labels[0].Name)
+ assert.Equal(t, "linux", runnerList.Entries[0].Labels[1].Name)
+
+ // Verify get the runner by id
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/user2/repo1/actions/runners/%d", runnerList.Entries[0].ID)).AddTokenAuth(token)
+ runnerResp := MakeRequest(t, req, http.StatusOK)
+
+ runner := api.ActionRunner{}
+ DecodeJSON(t, runnerResp, &runner)
+
+ assert.Equal(t, "runner_to_be_deleted-repo1", runner.Name)
+ assert.Equal(t, int64(34348), runner.ID)
+ assert.False(t, runner.Ephemeral)
+ assert.Len(t, runner.Labels, 2)
+ assert.Equal(t, "runner_to_be_deleted", runner.Labels[0].Name)
+ assert.Equal(t, "linux", runner.Labels[1].Name)
+
+ // Verify delete the runner by id
+ req = NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/repos/user2/repo1/actions/runners/%d", runnerList.Entries[0].ID)).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNoContent)
+
+ // Verify runner deletion
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/user2/repo1/actions/runners/%d", runnerList.Entries[0].ID)).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNotFound)
+ })
+
+ t.Run("DeleteReadScopeForbidden", func(t *testing.T) {
+ userUsername := "user2"
+ token := getUserToken(t, userUsername, auth_model.AccessTokenScopeReadRepository)
+
+ // Verify delete the runner by id is forbidden with read scope
+ req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/repos/user2/repo1/actions/runners/%d", 34348)).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusForbidden)
+ })
+
+ t.Run("GetOrganizationScopeForbidden", func(t *testing.T) {
+ userUsername := "user2"
+ token := getUserToken(t, userUsername, auth_model.AccessTokenScopeReadOrganization)
+ // Verify get the runner by id with read scope
+ req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/user2/repo1/actions/runners/%d", 34348)).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusForbidden)
+ })
+
+ t.Run("GetAdminRunnerNotFound", func(t *testing.T) {
+ userUsername := "user2"
+ token := getUserToken(t, userUsername, auth_model.AccessTokenScopeReadRepository)
+ // Verify get a runner by id of different entity is not found
+ // runner.EditableInContext(ownerID, repoID) false
+ req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/user2/repo1/actions/runners/%d", 34349)).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNotFound)
+ })
+
+ t.Run("DeleteAdminRunnerNotFound", func(t *testing.T) {
+ userUsername := "user2"
+ token := getUserToken(t, userUsername, auth_model.AccessTokenScopeWriteRepository)
+ // Verify delete a runner by id of different entity is not found
+ // runner.EditableInContext(ownerID, repoID) false
+ req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/repos/user2/repo1/actions/runners/%d", 34349)).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNotFound)
+ })
+
+ t.Run("DeleteAdminRunnerNotFoundUnknownID", func(t *testing.T) {
+ userUsername := "user2"
+ token := getUserToken(t, userUsername, auth_model.AccessTokenScopeWriteRepository)
+ // Verify delete a runner by unknown id is not found
+ req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/repos/user2/repo1/actions/runners/%d", 4384797347934)).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNotFound)
+ })
+}
diff --git a/tests/integration/api_activitypub_person_test.go b/tests/integration/api_activitypub_person_test.go
index 42a2a09072..9bb1f2736e 100644
--- a/tests/integration/api_activitypub_person_test.go
+++ b/tests/integration/api_activitypub_person_test.go
@@ -4,32 +4,31 @@
package integration
import (
- "context"
"fmt"
"net/http"
"net/http/httptest"
- "net/url"
"testing"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/activitypub"
"code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/routers"
+ "code.gitea.io/gitea/tests"
ap "github.com/go-ap/activitypub"
"github.com/stretchr/testify/assert"
)
func TestActivityPubPerson(t *testing.T) {
- setting.Federation.Enabled = true
- testWebRoutes = routers.NormalRoutes()
- defer func() {
- setting.Federation.Enabled = false
- testWebRoutes = routers.NormalRoutes()
- }()
+ defer tests.PrepareTestEnv(t)()
+ defer test.MockVariableValue(&setting.Federation.Enabled, true)()
+ defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
+
+ t.Run("ExistingPerson", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
- onGiteaRun(t, func(*testing.T, *url.URL) {
userID := 2
username := "user2"
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/activitypub/user-id/%v", userID))
@@ -57,49 +56,26 @@ func TestActivityPubPerson(t *testing.T) {
assert.NotNil(t, pubKeyPem)
assert.Regexp(t, "^-----BEGIN PUBLIC KEY-----", pubKeyPem)
})
-}
-
-func TestActivityPubMissingPerson(t *testing.T) {
- setting.Federation.Enabled = true
- testWebRoutes = routers.NormalRoutes()
- defer func() {
- setting.Federation.Enabled = false
- testWebRoutes = routers.NormalRoutes()
- }()
-
- onGiteaRun(t, func(*testing.T, *url.URL) {
+ t.Run("MissingPerson", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
req := NewRequest(t, "GET", "/api/v1/activitypub/user-id/999999999")
resp := MakeRequest(t, req, http.StatusNotFound)
assert.Contains(t, resp.Body.String(), "user does not exist")
})
-}
-
-func TestActivityPubPersonInbox(t *testing.T) {
- setting.Federation.Enabled = true
- testWebRoutes = routers.NormalRoutes()
- defer func() {
- setting.Federation.Enabled = false
- testWebRoutes = routers.NormalRoutes()
- }()
-
- srv := httptest.NewServer(testWebRoutes)
- defer srv.Close()
+ t.Run("MissingPersonInbox", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+ srv := httptest.NewServer(testWebRoutes)
+ defer srv.Close()
+ defer test.MockVariableValue(&setting.AppURL, srv.URL+"/")()
- onGiteaRun(t, func(*testing.T, *url.URL) {
- appURL := setting.AppURL
- setting.AppURL = srv.URL + "/"
- defer func() {
- setting.Database.LogSQL = false
- setting.AppURL = appURL
- }()
username1 := "user1"
- ctx := context.Background()
+ ctx := t.Context()
user1, err := user_model.GetUserByName(ctx, username1)
assert.NoError(t, err)
- user1url := fmt.Sprintf("%s/api/v1/activitypub/user-id/1#main-key", srv.URL)
+ user1url := srv.URL + "/api/v1/activitypub/user-id/1#main-key"
c, err := activitypub.NewClient(db.DefaultContext, user1, user1url)
assert.NoError(t, err)
- user2inboxurl := fmt.Sprintf("%s/api/v1/activitypub/user-id/2/inbox", srv.URL)
+ user2inboxurl := srv.URL + "/api/v1/activitypub/user-id/2/inbox"
// Signed request succeeds
resp, err := c.Post([]byte{}, user2inboxurl)
diff --git a/tests/integration/api_admin_org_test.go b/tests/integration/api_admin_org_test.go
index a29d0ba1d7..b2d77456c4 100644
--- a/tests/integration/api_admin_org_test.go
+++ b/tests/integration/api_admin_org_test.go
@@ -5,7 +5,6 @@ package integration
import (
"net/http"
- "net/url"
"strings"
"testing"
@@ -19,10 +18,12 @@ import (
)
func TestAPIAdminOrgCreate(t *testing.T) {
- onGiteaRun(t, func(*testing.T, *url.URL) {
- session := loginUser(t, "user1")
- token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin)
+ defer tests.PrepareTestEnv(t)()
+ session := loginUser(t, "user1")
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin)
+ t.Run("CreateOrg", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
org := api.CreateOrgOption{
UserName: "user2_org",
FullName: "User2's organization",
@@ -51,13 +52,8 @@ func TestAPIAdminOrgCreate(t *testing.T) {
FullName: org.FullName,
})
})
-}
-
-func TestAPIAdminOrgCreateBadVisibility(t *testing.T) {
- onGiteaRun(t, func(*testing.T, *url.URL) {
- session := loginUser(t, "user1")
- token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteAdmin)
-
+ t.Run("CreateBadVisibility", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
org := api.CreateOrgOption{
UserName: "user2_org",
FullName: "User2's organization",
@@ -70,22 +66,21 @@ func TestAPIAdminOrgCreateBadVisibility(t *testing.T) {
AddTokenAuth(token)
MakeRequest(t, req, http.StatusUnprocessableEntity)
})
-}
-
-func TestAPIAdminOrgCreateNotAdmin(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
- nonAdminUsername := "user2"
- session := loginUser(t, nonAdminUsername)
- token := getTokenForLoggedInUser(t, session)
- org := api.CreateOrgOption{
- UserName: "user2_org",
- FullName: "User2's organization",
- Description: "This organization created by admin for user2",
- Website: "https://try.gitea.io",
- Location: "Shanghai",
- Visibility: "public",
- }
- req := NewRequestWithJSON(t, "POST", "/api/v1/admin/users/user2/orgs", &org).
- AddTokenAuth(token)
- MakeRequest(t, req, http.StatusForbidden)
+ t.Run("CreateNotAdmin", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+ nonAdminUsername := "user2"
+ session := loginUser(t, nonAdminUsername)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll)
+ org := api.CreateOrgOption{
+ UserName: "user2_org",
+ FullName: "User2's organization",
+ Description: "This organization created by admin for user2",
+ Website: "https://try.gitea.io",
+ Location: "Shanghai",
+ Visibility: "public",
+ }
+ req := NewRequestWithJSON(t, "POST", "/api/v1/admin/users/user2/orgs", &org).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusForbidden)
+ })
}
diff --git a/tests/integration/api_admin_test.go b/tests/integration/api_admin_test.go
index 66209ee4e0..d28a103e59 100644
--- a/tests/integration/api_admin_test.go
+++ b/tests/integration/api_admin_test.go
@@ -76,7 +76,7 @@ func TestAPIAdminDeleteUnauthorizedKey(t *testing.T) {
var newPublicKey api.PublicKey
DecodeJSON(t, resp, &newPublicKey)
- token = getUserToken(t, normalUsername)
+ token = getUserToken(t, normalUsername, auth_model.AccessTokenScopeAll)
req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d", adminUsername, newPublicKey.ID).
AddTokenAuth(token)
MakeRequest(t, req, http.StatusForbidden)
@@ -88,7 +88,7 @@ func TestAPISudoUser(t *testing.T) {
normalUsername := "user2"
token := getUserToken(t, adminUsername, auth_model.AccessTokenScopeReadUser)
- req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/user?sudo=%s", normalUsername)).
+ req := NewRequest(t, "GET", "/api/v1/user?sudo="+normalUsername).
AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
var user api.User
@@ -103,7 +103,7 @@ func TestAPISudoUserForbidden(t *testing.T) {
normalUsername := "user2"
token := getUserToken(t, normalUsername, auth_model.AccessTokenScopeReadAdmin)
- req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/user?sudo=%s", adminUsername)).
+ req := NewRequest(t, "GET", "/api/v1/user?sudo="+adminUsername).
AddTokenAuth(token)
MakeRequest(t, req, http.StatusForbidden)
}
@@ -139,7 +139,7 @@ func TestAPIListUsersNotLoggedIn(t *testing.T) {
func TestAPIListUsersNonAdmin(t *testing.T) {
defer tests.PrepareTestEnv(t)()
nonAdminUsername := "user2"
- token := getUserToken(t, nonAdminUsername)
+ token := getUserToken(t, nonAdminUsername, auth_model.AccessTokenScopeAll)
req := NewRequest(t, "GET", "/api/v1/admin/users").
AddTokenAuth(token)
MakeRequest(t, req, http.StatusForbidden)
@@ -193,7 +193,7 @@ func TestAPIEditUser(t *testing.T) {
defer tests.PrepareTestEnv(t)()
adminUsername := "user1"
token := getUserToken(t, adminUsername, auth_model.AccessTokenScopeWriteAdmin)
- urlStr := fmt.Sprintf("/api/v1/admin/users/%s", "user2")
+ urlStr := "/api/v1/admin/users/" + "user2"
fullNameToChange := "Full Name User 2"
req := NewRequestWithValues(t, "PATCH", urlStr, map[string]string{
@@ -217,7 +217,7 @@ func TestAPIEditUser(t *testing.T) {
errMap := make(map[string]any)
json.Unmarshal(resp.Body.Bytes(), &errMap)
- assert.EqualValues(t, "e-mail invalid [email: ]", errMap["message"].(string))
+ assert.Equal(t, "e-mail invalid [email: ]", errMap["message"].(string))
user2 = unittest.AssertExistsAndLoadBean(t, &user_model.User{LoginName: "user2"})
assert.False(t, user2.IsRestricted)
@@ -374,7 +374,7 @@ func TestAPIEditUser_NotAllowedEmailDomain(t *testing.T) {
adminUsername := "user1"
token := getUserToken(t, adminUsername, auth_model.AccessTokenScopeWriteAdmin)
- urlStr := fmt.Sprintf("/api/v1/admin/users/%s", "user2")
+ urlStr := "/api/v1/admin/users/" + "user2"
newEmail := "user2@example1.com"
req := NewRequestWithJSON(t, "PATCH", urlStr, api.EditUserOption{
diff --git a/tests/integration/api_branch_test.go b/tests/integration/api_branch_test.go
index 8a0bd2e4ff..16e1f2812e 100644
--- a/tests/integration/api_branch_test.go
+++ b/tests/integration/api_branch_test.go
@@ -24,13 +24,13 @@ func testAPIGetBranch(t *testing.T, branchName string, exists bool) {
AddTokenAuth(token)
resp := MakeRequest(t, req, NoExpectedStatus)
if !exists {
- assert.EqualValues(t, http.StatusNotFound, resp.Code)
+ assert.Equal(t, http.StatusNotFound, resp.Code)
return
}
- assert.EqualValues(t, http.StatusOK, resp.Code)
+ assert.Equal(t, http.StatusOK, resp.Code)
var branch api.Branch
DecodeJSON(t, resp, &branch)
- assert.EqualValues(t, branchName, branch.Name)
+ assert.Equal(t, branchName, branch.Name)
assert.True(t, branch.UserCanPush)
assert.True(t, branch.UserCanMerge)
}
@@ -44,7 +44,7 @@ func testAPIGetBranchProtection(t *testing.T, branchName string, expectedHTTPSta
if resp.Code == http.StatusOK {
var branchProtection api.BranchProtection
DecodeJSON(t, resp, &branchProtection)
- assert.EqualValues(t, branchName, branchProtection.RuleName)
+ assert.Equal(t, branchName, branchProtection.RuleName)
return &branchProtection
}
return nil
@@ -60,7 +60,7 @@ func testAPICreateBranchProtection(t *testing.T, branchName string, expectedPrio
if resp.Code == http.StatusCreated {
var branchProtection api.BranchProtection
DecodeJSON(t, resp, &branchProtection)
- assert.EqualValues(t, branchName, branchProtection.RuleName)
+ assert.Equal(t, branchName, branchProtection.RuleName)
assert.EqualValues(t, expectedPriority, branchProtection.Priority)
}
}
@@ -74,7 +74,7 @@ func testAPIEditBranchProtection(t *testing.T, branchName string, body *api.Bran
if resp.Code == http.StatusOK {
var branchProtection api.BranchProtection
DecodeJSON(t, resp, &branchProtection)
- assert.EqualValues(t, branchName, branchProtection.RuleName)
+ assert.Equal(t, branchName, branchProtection.RuleName)
}
}
@@ -181,7 +181,7 @@ func testAPICreateBranch(t testing.TB, session *TestSession, user, repo, oldBran
DecodeJSON(t, resp, &branch)
if resp.Result().StatusCode == http.StatusCreated {
- assert.EqualValues(t, newBranch, branch.Name)
+ assert.Equal(t, newBranch, branch.Name)
}
return resp.Result().StatusCode == status
@@ -190,28 +190,61 @@ func testAPICreateBranch(t testing.TB, session *TestSession, user, repo, oldBran
func TestAPIUpdateBranch(t *testing.T) {
onGiteaRun(t, func(t *testing.T, _ *url.URL) {
t.Run("UpdateBranchWithEmptyRepo", func(t *testing.T) {
- testAPIUpdateBranch(t, "user10", "repo6", "master", "test", http.StatusNotFound)
+ testAPIUpdateBranch(t, "user10", "user10", "repo6", "master", "test", http.StatusNotFound)
})
t.Run("UpdateBranchWithSameBranchNames", func(t *testing.T) {
- resp := testAPIUpdateBranch(t, "user2", "repo1", "master", "master", http.StatusUnprocessableEntity)
+ resp := testAPIUpdateBranch(t, "user2", "user2", "repo1", "master", "master", http.StatusUnprocessableEntity)
assert.Contains(t, resp.Body.String(), "Cannot rename a branch using the same name or rename to a branch that already exists.")
})
t.Run("UpdateBranchThatAlreadyExists", func(t *testing.T) {
- resp := testAPIUpdateBranch(t, "user2", "repo1", "master", "branch2", http.StatusUnprocessableEntity)
+ resp := testAPIUpdateBranch(t, "user2", "user2", "repo1", "master", "branch2", http.StatusUnprocessableEntity)
assert.Contains(t, resp.Body.String(), "Cannot rename a branch using the same name or rename to a branch that already exists.")
})
t.Run("UpdateBranchWithNonExistentBranch", func(t *testing.T) {
- resp := testAPIUpdateBranch(t, "user2", "repo1", "i-dont-exist", "new-branch-name", http.StatusNotFound)
+ resp := testAPIUpdateBranch(t, "user2", "user2", "repo1", "i-dont-exist", "new-branch-name", http.StatusNotFound)
assert.Contains(t, resp.Body.String(), "Branch doesn't exist.")
})
- t.Run("RenameBranchNormalScenario", func(t *testing.T) {
- testAPIUpdateBranch(t, "user2", "repo1", "branch2", "new-branch-name", http.StatusNoContent)
+ t.Run("UpdateBranchWithNonAdminDoer", func(t *testing.T) {
+ // don't allow default branch renaming
+ resp := testAPIUpdateBranch(t, "user40", "user2", "repo1", "master", "new-branch-name", http.StatusForbidden)
+ assert.Contains(t, resp.Body.String(), "User must be a repo or site admin to rename default or protected branches.")
+
+ // don't allow protected branch renaming
+ token := getUserToken(t, "user2", auth_model.AccessTokenScopeWriteRepository)
+ req := NewRequestWithJSON(t, "POST", "/api/v1/repos/user2/repo1/branches", &api.CreateBranchRepoOption{
+ BranchName: "protected-branch",
+ }).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusCreated)
+ testAPICreateBranchProtection(t, "protected-branch", 1, http.StatusCreated)
+ resp = testAPIUpdateBranch(t, "user40", "user2", "repo1", "protected-branch", "new-branch-name", http.StatusForbidden)
+ assert.Contains(t, resp.Body.String(), "User must be a repo or site admin to rename default or protected branches.")
+ })
+ t.Run("UpdateBranchWithGlobedBasedProtectionRulesAndAdminAccess", func(t *testing.T) {
+ // don't allow branch that falls under glob-based protection rules to be renamed
+ token := getUserToken(t, "user2", auth_model.AccessTokenScopeWriteRepository)
+ req := NewRequestWithJSON(t, "POST", "/api/v1/repos/user2/repo1/branch_protections", &api.BranchProtection{
+ RuleName: "protected/**",
+ EnablePush: true,
+ }).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusCreated)
+
+ from := "protected/1"
+ req = NewRequestWithJSON(t, "POST", "/api/v1/repos/user2/repo1/branches", &api.CreateBranchRepoOption{
+ BranchName: from,
+ }).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusCreated)
+
+ resp := testAPIUpdateBranch(t, "user2", "user2", "repo1", from, "new-branch-name", http.StatusForbidden)
+ assert.Contains(t, resp.Body.String(), "Branch is protected by glob-based protection rules.")
+ })
+ t.Run("UpdateBranchNormalScenario", func(t *testing.T) {
+ testAPIUpdateBranch(t, "user2", "user2", "repo1", "branch2", "new-branch-name", http.StatusNoContent)
})
})
}
-func testAPIUpdateBranch(t *testing.T, ownerName, repoName, from, to string, expectedHTTPStatus int) *httptest.ResponseRecorder {
- token := getUserToken(t, ownerName, auth_model.AccessTokenScopeWriteRepository)
+func testAPIUpdateBranch(t *testing.T, doerName, ownerName, repoName, from, to string, expectedHTTPStatus int) *httptest.ResponseRecorder {
+ token := getUserToken(t, doerName, auth_model.AccessTokenScopeWriteRepository)
req := NewRequestWithJSON(t, "PATCH", "api/v1/repos/"+ownerName+"/"+repoName+"/branches/"+from, &api.UpdateBranchRepoOption{
Name: to,
}).AddTokenAuth(token)
@@ -270,7 +303,7 @@ func TestAPICreateBranchWithSyncBranches(t *testing.T) {
RepoID: 1,
})
assert.NoError(t, err)
- assert.Len(t, branches, 4)
+ assert.Len(t, branches, 6)
// make a broke repository with no branch on database
_, err = db.DeleteByBean(db.DefaultContext, git_model.Branch{RepoID: 1})
@@ -287,7 +320,7 @@ func TestAPICreateBranchWithSyncBranches(t *testing.T) {
RepoID: 1,
})
assert.NoError(t, err)
- assert.Len(t, branches, 5)
+ assert.Len(t, branches, 7)
branches, err = db.Find[git_model.Branch](db.DefaultContext, git_model.FindBranchOptions{
RepoID: 1,
diff --git a/tests/integration/api_comment_test.go b/tests/integration/api_comment_test.go
index 255b8332b2..9842c358f6 100644
--- a/tests/integration/api_comment_test.go
+++ b/tests/integration/api_comment_test.go
@@ -106,7 +106,7 @@ func TestAPICreateComment(t *testing.T) {
var updatedComment api.Comment
DecodeJSON(t, resp, &updatedComment)
- assert.EqualValues(t, commentBody, updatedComment.Body)
+ assert.Equal(t, commentBody, updatedComment.Body)
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: updatedComment.ID, IssueID: issue.ID, Content: commentBody})
t.Run("BlockedByRepoOwner", func(t *testing.T) {
@@ -174,7 +174,7 @@ func TestAPIGetSystemUserComment(t *testing.T) {
user_model.NewGhostUser(),
user_model.NewActionsUser(),
} {
- body := fmt.Sprintf("Hello %s", systemUser.Name)
+ body := "Hello " + systemUser.Name
comment, err := issues_model.CreateComment(db.DefaultContext, &issues_model.CreateCommentOptions{
Type: issues_model.CommentTypeComment,
Doer: systemUser,
@@ -233,8 +233,8 @@ func TestAPIEditComment(t *testing.T) {
var updatedComment api.Comment
DecodeJSON(t, resp, &updatedComment)
- assert.EqualValues(t, comment.ID, updatedComment.ID)
- assert.EqualValues(t, newCommentBody, updatedComment.Body)
+ assert.Equal(t, comment.ID, updatedComment.ID)
+ assert.Equal(t, newCommentBody, updatedComment.Body)
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: comment.ID, IssueID: issue.ID, Content: newCommentBody})
}
diff --git a/tests/integration/api_fork_test.go b/tests/integration/api_fork_test.go
index 580bb459e7..2837c3b93e 100644
--- a/tests/integration/api_fork_test.go
+++ b/tests/integration/api_fork_test.go
@@ -10,6 +10,7 @@ import (
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
org_model "code.gitea.io/gitea/models/organization"
+ repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
api "code.gitea.io/gitea/modules/structs"
@@ -33,7 +34,7 @@ func TestAPIForkListLimitedAndPrivateRepos(t *testing.T) {
// fork into a limited org
limitedOrg := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 22})
- assert.EqualValues(t, api.VisibleTypeLimited, limitedOrg.Visibility)
+ assert.Equal(t, api.VisibleTypeLimited, limitedOrg.Visibility)
ownerTeam1, err := org_model.OrgFromUser(limitedOrg).GetOwnerTeam(db.DefaultContext)
assert.NoError(t, err)
@@ -48,7 +49,7 @@ func TestAPIForkListLimitedAndPrivateRepos(t *testing.T) {
user4Sess := loginUser(t, "user4")
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user4"})
privateOrg := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 23})
- assert.EqualValues(t, api.VisibleTypePrivate, privateOrg.Visibility)
+ assert.Equal(t, api.VisibleTypePrivate, privateOrg.Visibility)
ownerTeam2, err := org_model.OrgFromUser(privateOrg).GetOwnerTeam(db.DefaultContext)
assert.NoError(t, err)
@@ -69,7 +70,7 @@ func TestAPIForkListLimitedAndPrivateRepos(t *testing.T) {
DecodeJSON(t, resp, &forks)
assert.Empty(t, forks)
- assert.EqualValues(t, "0", resp.Header().Get("X-Total-Count"))
+ assert.Equal(t, "0", resp.Header().Get("X-Total-Count"))
})
t.Run("Logged in", func(t *testing.T) {
@@ -81,8 +82,8 @@ func TestAPIForkListLimitedAndPrivateRepos(t *testing.T) {
var forks []*api.Repository
DecodeJSON(t, resp, &forks)
- assert.Len(t, forks, 1)
- assert.EqualValues(t, "1", resp.Header().Get("X-Total-Count"))
+ assert.Len(t, forks, 2)
+ assert.Equal(t, "2", resp.Header().Get("X-Total-Count"))
assert.NoError(t, org_service.AddTeamMember(db.DefaultContext, ownerTeam2, user1))
@@ -93,6 +94,34 @@ func TestAPIForkListLimitedAndPrivateRepos(t *testing.T) {
DecodeJSON(t, resp, &forks)
assert.Len(t, forks, 2)
- assert.EqualValues(t, "2", resp.Header().Get("X-Total-Count"))
+ assert.Equal(t, "2", resp.Header().Get("X-Total-Count"))
})
}
+
+func TestGetPrivateReposForks(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+
+ user1Sess := loginUser(t, "user1")
+ repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) // private repository
+ privateOrg := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 23})
+ user1Token := getTokenForLoggedInUser(t, user1Sess, auth_model.AccessTokenScopeWriteRepository)
+
+ forkedRepoName := "forked-repo"
+ // create fork from a private repository
+ req := NewRequestWithJSON(t, "POST", "/api/v1/repos/"+repo2.FullName()+"/forks", &api.CreateForkOption{
+ Organization: &privateOrg.Name,
+ Name: &forkedRepoName,
+ }).AddTokenAuth(user1Token)
+ MakeRequest(t, req, http.StatusAccepted)
+
+ // test get a private fork without clear permissions
+ req = NewRequest(t, "GET", "/api/v1/repos/"+repo2.FullName()+"/forks").AddTokenAuth(user1Token)
+ resp := MakeRequest(t, req, http.StatusOK)
+
+ forks := []*api.Repository{}
+ DecodeJSON(t, resp, &forks)
+ assert.Len(t, forks, 1)
+ assert.Equal(t, "1", resp.Header().Get("X-Total-Count"))
+ assert.Equal(t, "forked-repo", forks[0].Name)
+ assert.Equal(t, privateOrg.Name, forks[0].Owner.UserName)
+}
diff --git a/tests/integration/api_gitignore_templates_test.go b/tests/integration/api_gitignore_templates_test.go
index c58f5eebfe..1c56d51344 100644
--- a/tests/integration/api_gitignore_templates_test.go
+++ b/tests/integration/api_gitignore_templates_test.go
@@ -4,7 +4,6 @@
package integration
import (
- "fmt"
"net/http"
"testing"
@@ -38,7 +37,7 @@ func TestAPIGetGitignoreTemplateInfo(t *testing.T) {
// Use the first template for the test
templateName := repo_module.Gitignores[0]
- urlStr := fmt.Sprintf("/api/v1/gitignore/templates/%s", templateName)
+ urlStr := "/api/v1/gitignore/templates/" + templateName
req := NewRequest(t, "GET", urlStr)
resp := MakeRequest(t, req, http.StatusOK)
diff --git a/tests/integration/api_gpg_keys_test.go b/tests/integration/api_gpg_keys_test.go
index ec0dafc2d6..edfb9e6eca 100644
--- a/tests/integration/api_gpg_keys_test.go
+++ b/tests/integration/api_gpg_keys_test.go
@@ -86,13 +86,13 @@ func TestGPGKeys(t *testing.T) {
assert.Len(t, keys, 1)
primaryKey1 := keys[0] // Primary key 1
- assert.EqualValues(t, "38EA3BCED732982C", primaryKey1.KeyID)
+ assert.Equal(t, "38EA3BCED732982C", primaryKey1.KeyID)
assert.Len(t, primaryKey1.Emails, 1)
- assert.EqualValues(t, "user2@example.com", primaryKey1.Emails[0].Email)
+ assert.Equal(t, "user2@example.com", primaryKey1.Emails[0].Email)
assert.True(t, primaryKey1.Emails[0].Verified)
subKey := primaryKey1.SubsKey[0] // Subkey of 38EA3BCED732982C
- assert.EqualValues(t, "70D7C694D17D03AD", subKey.KeyID)
+ assert.Equal(t, "70D7C694D17D03AD", subKey.KeyID)
assert.Empty(t, subKey.Emails)
var key api.GPGKey
@@ -100,16 +100,16 @@ func TestGPGKeys(t *testing.T) {
AddTokenAuth(tokenWithGPGKeyScope)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &key)
- assert.EqualValues(t, "38EA3BCED732982C", key.KeyID)
+ assert.Equal(t, "38EA3BCED732982C", key.KeyID)
assert.Len(t, key.Emails, 1)
- assert.EqualValues(t, "user2@example.com", key.Emails[0].Email)
+ assert.Equal(t, "user2@example.com", key.Emails[0].Email)
assert.True(t, key.Emails[0].Verified)
req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(subKey.ID, 10)). // Subkey of 38EA3BCED732982C
AddTokenAuth(tokenWithGPGKeyScope)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &key)
- assert.EqualValues(t, "70D7C694D17D03AD", key.KeyID)
+ assert.Equal(t, "70D7C694D17D03AD", key.KeyID)
assert.Empty(t, key.Emails)
})
diff --git a/tests/integration/api_helper_for_declarative_test.go b/tests/integration/api_helper_for_declarative_test.go
index 7755b9861a..b30cdfd0fc 100644
--- a/tests/integration/api_helper_for_declarative_test.go
+++ b/tests/integration/api_helper_for_declarative_test.go
@@ -4,7 +4,6 @@
package integration
import (
- "context"
"fmt"
"net/http"
"net/http/httptest"
@@ -34,6 +33,10 @@ type APITestContext struct {
func NewAPITestContext(t *testing.T, username, reponame string, scope ...auth.AccessTokenScope) APITestContext {
session := loginUser(t, username)
+ if len(scope) == 0 {
+ // FIXME: legacy logic: no scope means all
+ scope = []auth.AccessTokenScope{auth.AccessTokenScopeAll}
+ }
token := getTokenForLoggedInUser(t, session, scope...)
return APITestContext{
Session: session,
@@ -260,7 +263,7 @@ func doAPIMergePullRequest(ctx APITestContext, owner, repo string, index int64)
var req *RequestWrapper
var resp *httptest.ResponseRecorder
- for i := 0; i < 6; i++ {
+ for range 6 {
req = NewRequestWithJSON(t, http.MethodPost, urlStr, &forms.MergePullRequestForm{
MergeMessageField: "doAPIMergePullRequest Merge",
Do: string(repo_model.MergeStyleMerge),
@@ -273,8 +276,8 @@ func doAPIMergePullRequest(ctx APITestContext, owner, repo string, index int64)
}
err := api.APIError{}
DecodeJSON(t, resp, &err)
- assert.EqualValues(t, "Please try again later", err.Message)
- queue.GetManager().FlushAll(context.Background(), 5*time.Second)
+ assert.Equal(t, "Please try again later", err.Message)
+ queue.GetManager().FlushAll(t.Context(), 5*time.Second)
<-time.After(1 * time.Second)
}
@@ -283,7 +286,7 @@ func doAPIMergePullRequest(ctx APITestContext, owner, repo string, index int64)
expected = http.StatusOK
}
- if !assert.EqualValues(t, expected, resp.Code,
+ if !assert.Equal(t, expected, resp.Code,
"Request: %s %s", req.Method, req.URL.String()) {
logUnexpectedResponse(t, resp)
}
diff --git a/tests/integration/api_issue_label_test.go b/tests/integration/api_issue_label_test.go
index 0e4cd8243b..4324fd37d9 100644
--- a/tests/integration/api_issue_label_test.go
+++ b/tests/integration/api_issue_label_test.go
@@ -38,8 +38,8 @@ func TestAPIModifyLabels(t *testing.T) {
apiLabel := new(api.Label)
DecodeJSON(t, resp, &apiLabel)
dbLabel := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: apiLabel.ID, RepoID: repo.ID})
- assert.EqualValues(t, dbLabel.Name, apiLabel.Name)
- assert.EqualValues(t, strings.TrimLeft(dbLabel.Color, "#"), apiLabel.Color)
+ assert.Equal(t, dbLabel.Name, apiLabel.Name)
+ assert.Equal(t, strings.TrimLeft(dbLabel.Color, "#"), apiLabel.Color)
req = NewRequestWithJSON(t, "POST", urlStr, &api.CreateLabelOption{
Name: "TestL 2",
@@ -67,7 +67,7 @@ func TestAPIModifyLabels(t *testing.T) {
AddTokenAuth(token)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiLabel)
- assert.EqualValues(t, strings.TrimLeft(dbLabel.Color, "#"), apiLabel.Color)
+ assert.Equal(t, strings.TrimLeft(dbLabel.Color, "#"), apiLabel.Color)
// EditLabel
newName := "LabelNewName"
@@ -79,7 +79,7 @@ func TestAPIModifyLabels(t *testing.T) {
}).AddTokenAuth(token)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiLabel)
- assert.EqualValues(t, newColor, apiLabel.Color)
+ assert.Equal(t, newColor, apiLabel.Color)
req = NewRequestWithJSON(t, "PATCH", singleURLStr, &api.EditLabelOption{
Color: &newColorWrong,
}).AddTokenAuth(token)
@@ -117,27 +117,33 @@ func TestAPIAddIssueLabels(t *testing.T) {
func TestAPIAddIssueLabelsWithLabelNames(t *testing.T) {
assert.NoError(t, unittest.LoadFixtures())
- repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
- issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repo.ID})
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
+ issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 6, RepoID: repo.ID})
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+ repoLabel := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 10, RepoID: repo.ID})
+ orgLabel := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 4, OrgID: owner.ID})
- session := loginUser(t, owner.Name)
- token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue)
- urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels",
- repo.OwnerName, repo.Name, issue.Index)
+ user1Session := loginUser(t, "user1")
+ token := getTokenForLoggedInUser(t, user1Session, auth_model.AccessTokenScopeWriteIssue)
+
+ // add the org label and the repo label to the issue
+ urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels", owner.Name, repo.Name, issue.Index)
req := NewRequestWithJSON(t, "POST", urlStr, &api.IssueLabelsOption{
- Labels: []any{"label1", "label2"},
+ Labels: []any{repoLabel.Name, orgLabel.Name},
}).AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
var apiLabels []*api.Label
DecodeJSON(t, resp, &apiLabels)
assert.Len(t, apiLabels, unittest.GetCount(t, &issues_model.IssueLabel{IssueID: issue.ID}))
-
var apiLabelNames []string
for _, label := range apiLabels {
apiLabelNames = append(apiLabelNames, label.Name)
}
- assert.ElementsMatch(t, apiLabelNames, []string{"label1", "label2"})
+ assert.ElementsMatch(t, apiLabelNames, []string{repoLabel.Name, orgLabel.Name})
+
+ // delete labels
+ req = NewRequest(t, "DELETE", urlStr).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNoContent)
}
func TestAPIReplaceIssueLabels(t *testing.T) {
@@ -159,7 +165,7 @@ func TestAPIReplaceIssueLabels(t *testing.T) {
var apiLabels []*api.Label
DecodeJSON(t, resp, &apiLabels)
if assert.Len(t, apiLabels, 1) {
- assert.EqualValues(t, label.ID, apiLabels[0].ID)
+ assert.Equal(t, label.ID, apiLabels[0].ID)
}
unittest.AssertCount(t, &issues_model.IssueLabel{IssueID: issue.ID}, 1)
@@ -185,7 +191,7 @@ func TestAPIReplaceIssueLabelsWithLabelNames(t *testing.T) {
var apiLabels []*api.Label
DecodeJSON(t, resp, &apiLabels)
if assert.Len(t, apiLabels, 1) {
- assert.EqualValues(t, label.Name, apiLabels[0].Name)
+ assert.Equal(t, label.Name, apiLabels[0].Name)
}
}
@@ -209,8 +215,8 @@ func TestAPIModifyOrgLabels(t *testing.T) {
apiLabel := new(api.Label)
DecodeJSON(t, resp, &apiLabel)
dbLabel := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: apiLabel.ID, OrgID: owner.ID})
- assert.EqualValues(t, dbLabel.Name, apiLabel.Name)
- assert.EqualValues(t, strings.TrimLeft(dbLabel.Color, "#"), apiLabel.Color)
+ assert.Equal(t, dbLabel.Name, apiLabel.Name)
+ assert.Equal(t, strings.TrimLeft(dbLabel.Color, "#"), apiLabel.Color)
req = NewRequestWithJSON(t, "POST", urlStr, &api.CreateLabelOption{
Name: "TestL 2",
@@ -238,7 +244,7 @@ func TestAPIModifyOrgLabels(t *testing.T) {
AddTokenAuth(token)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiLabel)
- assert.EqualValues(t, strings.TrimLeft(dbLabel.Color, "#"), apiLabel.Color)
+ assert.Equal(t, strings.TrimLeft(dbLabel.Color, "#"), apiLabel.Color)
// EditLabel
newName := "LabelNewName"
@@ -250,7 +256,7 @@ func TestAPIModifyOrgLabels(t *testing.T) {
}).AddTokenAuth(token)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiLabel)
- assert.EqualValues(t, newColor, apiLabel.Color)
+ assert.Equal(t, newColor, apiLabel.Color)
req = NewRequestWithJSON(t, "PATCH", singleURLStr, &api.EditLabelOption{
Color: &newColorWrong,
}).AddTokenAuth(token)
diff --git a/tests/integration/api_issue_lock_test.go b/tests/integration/api_issue_lock_test.go
new file mode 100644
index 0000000000..47b1f2cf0d
--- /dev/null
+++ b/tests/integration/api_issue_lock_test.go
@@ -0,0 +1,74 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package integration
+
+import (
+ "fmt"
+ "net/http"
+ "testing"
+
+ auth_model "code.gitea.io/gitea/models/auth"
+ issues_model "code.gitea.io/gitea/models/issues"
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
+ api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/tests"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestAPILockIssue(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+
+ t.Run("Lock", func(t *testing.T) {
+ issueBefore := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
+ assert.False(t, issueBefore.IsLocked)
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID})
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+ urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/lock", owner.Name, repo.Name, issueBefore.Index)
+
+ session := loginUser(t, owner.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue)
+
+ // check lock issue
+ req := NewRequestWithJSON(t, "PUT", urlStr, api.LockIssueOption{Reason: "Spam"}).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNoContent)
+ issueAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
+ assert.True(t, issueAfter.IsLocked)
+
+ // check with other user
+ user34 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 34})
+ session34 := loginUser(t, user34.Name)
+ token34 := getTokenForLoggedInUser(t, session34, auth_model.AccessTokenScopeAll)
+ req = NewRequestWithJSON(t, "PUT", urlStr, api.LockIssueOption{Reason: "Spam"}).AddTokenAuth(token34)
+ MakeRequest(t, req, http.StatusForbidden)
+ })
+
+ t.Run("Unlock", func(t *testing.T) {
+ issueBefore := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID})
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+ urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/lock", owner.Name, repo.Name, issueBefore.Index)
+
+ session := loginUser(t, owner.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue)
+
+ lockReq := NewRequestWithJSON(t, "PUT", urlStr, api.LockIssueOption{Reason: "Spam"}).AddTokenAuth(token)
+ MakeRequest(t, lockReq, http.StatusNoContent)
+
+ // check unlock issue
+ req := NewRequest(t, "DELETE", urlStr).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNoContent)
+ issueAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
+ assert.False(t, issueAfter.IsLocked)
+
+ // check with other user
+ user34 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 34})
+ session34 := loginUser(t, user34.Name)
+ token34 := getTokenForLoggedInUser(t, session34, auth_model.AccessTokenScopeAll)
+ req = NewRequest(t, "DELETE", urlStr).AddTokenAuth(token34)
+ MakeRequest(t, req, http.StatusForbidden)
+ })
+}
diff --git a/tests/integration/api_issue_milestone_test.go b/tests/integration/api_issue_milestone_test.go
index 2d00752302..1196c8d358 100644
--- a/tests/integration/api_issue_milestone_test.go
+++ b/tests/integration/api_issue_milestone_test.go
@@ -73,7 +73,7 @@ func TestAPIIssuesMilestone(t *testing.T) {
AddTokenAuth(token)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiMilestone)
- assert.EqualValues(t, apiMilestones[2], apiMilestone)
+ assert.Equal(t, apiMilestones[2], apiMilestone)
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/milestones?state=%s&name=%s", owner.Name, repo.Name, "all", "milestone2")).
AddTokenAuth(token)
diff --git a/tests/integration/api_issue_stopwatch_test.go b/tests/integration/api_issue_stopwatch_test.go
index 4765787e6f..3606d9a228 100644
--- a/tests/integration/api_issue_stopwatch_test.go
+++ b/tests/integration/api_issue_stopwatch_test.go
@@ -35,11 +35,11 @@ func TestAPIListStopWatches(t *testing.T) {
stopwatch := unittest.AssertExistsAndLoadBean(t, &issues_model.Stopwatch{UserID: owner.ID})
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: stopwatch.IssueID})
if assert.Len(t, apiWatches, 1) {
- assert.EqualValues(t, stopwatch.CreatedUnix.AsTime().Unix(), apiWatches[0].Created.Unix())
- assert.EqualValues(t, issue.Index, apiWatches[0].IssueIndex)
- assert.EqualValues(t, issue.Title, apiWatches[0].IssueTitle)
- assert.EqualValues(t, repo.Name, apiWatches[0].RepoName)
- assert.EqualValues(t, repo.OwnerName, apiWatches[0].RepoOwnerName)
+ assert.Equal(t, stopwatch.CreatedUnix.AsTime().Unix(), apiWatches[0].Created.Unix())
+ assert.Equal(t, issue.Index, apiWatches[0].IssueIndex)
+ assert.Equal(t, issue.Title, apiWatches[0].IssueTitle)
+ assert.Equal(t, repo.Name, apiWatches[0].RepoName)
+ assert.Equal(t, repo.OwnerName, apiWatches[0].RepoOwnerName)
assert.Positive(t, apiWatches[0].Seconds)
}
}
diff --git a/tests/integration/api_issue_subscription_test.go b/tests/integration/api_issue_subscription_test.go
index 7a716301c4..74ba171c01 100644
--- a/tests/integration/api_issue_subscription_test.go
+++ b/tests/integration/api_issue_subscription_test.go
@@ -43,11 +43,11 @@ func TestAPIIssueSubscriptions(t *testing.T) {
wi := new(api.WatchInfo)
DecodeJSON(t, resp, wi)
- assert.EqualValues(t, isWatching, wi.Subscribed)
- assert.EqualValues(t, !isWatching, wi.Ignored)
- assert.EqualValues(t, issue.APIURL(db.DefaultContext)+"/subscriptions", wi.URL)
+ assert.Equal(t, isWatching, wi.Subscribed)
+ assert.Equal(t, !isWatching, wi.Ignored)
+ assert.Equal(t, issue.APIURL(db.DefaultContext)+"/subscriptions", wi.URL)
assert.EqualValues(t, issue.CreatedUnix, wi.CreatedAt.Unix())
- assert.EqualValues(t, issueRepo.APIURL(), wi.RepositoryURL)
+ assert.Equal(t, issueRepo.APIURL(), wi.RepositoryURL)
}
testSubscription(issue1, true)
diff --git a/tests/integration/api_issue_test.go b/tests/integration/api_issue_test.go
index d8394a33d9..370c90a100 100644
--- a/tests/integration/api_issue_test.go
+++ b/tests/integration/api_issue_test.go
@@ -166,7 +166,7 @@ func TestAPICreateIssueParallel(t *testing.T) {
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues", owner.Name, repoBefore.Name)
var wg sync.WaitGroup
- for i := 0; i < 10; i++ {
+ for i := range 10 {
wg.Add(1)
go func(parentT *testing.T, i int) {
parentT.Run(fmt.Sprintf("ParallelCreateIssue_%d", i), func(t *testing.T) {
@@ -267,10 +267,7 @@ func TestAPISearchIssues(t *testing.T) {
defer tests.PrepareTestEnv(t)()
// as this API was used in the frontend, it uses UI page size
- expectedIssueCount := 20 // from the fixtures
- if expectedIssueCount > setting.UI.IssuePagingNum {
- expectedIssueCount = setting.UI.IssuePagingNum
- }
+ expectedIssueCount := min(20, setting.UI.IssuePagingNum) // 20 is from the fixtures
link, _ := url.Parse("/api/v1/repos/issues/search")
token := getUserToken(t, "user1", auth_model.AccessTokenScopeReadIssue)
@@ -313,7 +310,7 @@ func TestAPISearchIssues(t *testing.T) {
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
- assert.EqualValues(t, "22", resp.Header().Get("X-Total-Count"))
+ assert.Equal(t, "22", resp.Header().Get("X-Total-Count"))
assert.Len(t, apiIssues, 20)
query.Add("limit", "10")
@@ -321,7 +318,7 @@ func TestAPISearchIssues(t *testing.T) {
req = NewRequest(t, "GET", link.String()).AddTokenAuth(token)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
- assert.EqualValues(t, "22", resp.Header().Get("X-Total-Count"))
+ assert.Equal(t, "22", resp.Header().Get("X-Total-Count"))
assert.Len(t, apiIssues, 10)
query = url.Values{"assigned": {"true"}, "state": {"all"}}
@@ -371,10 +368,7 @@ func TestAPISearchIssuesWithLabels(t *testing.T) {
defer tests.PrepareTestEnv(t)()
// as this API was used in the frontend, it uses UI page size
- expectedIssueCount := 20 // from the fixtures
- if expectedIssueCount > setting.UI.IssuePagingNum {
- expectedIssueCount = setting.UI.IssuePagingNum
- }
+ expectedIssueCount := min(20, setting.UI.IssuePagingNum) // 20 is from the fixtures
link, _ := url.Parse("/api/v1/repos/issues/search")
token := getUserToken(t, "user1", auth_model.AccessTokenScopeReadIssue)
diff --git a/tests/integration/api_issue_tracked_time_test.go b/tests/integration/api_issue_tracked_time_test.go
index fd2c452b20..bd562b602e 100644
--- a/tests/integration/api_issue_tracked_time_test.go
+++ b/tests/integration/api_issue_tracked_time_test.go
@@ -41,8 +41,8 @@ func TestAPIGetTrackedTimes(t *testing.T) {
for i, time := range expect {
assert.Equal(t, time.ID, apiTimes[i].ID)
- assert.EqualValues(t, issue2.Title, apiTimes[i].Issue.Title)
- assert.EqualValues(t, issue2.ID, apiTimes[i].IssueID)
+ assert.Equal(t, issue2.Title, apiTimes[i].Issue.Title)
+ assert.Equal(t, issue2.ID, apiTimes[i].IssueID)
assert.Equal(t, time.Created.Unix(), apiTimes[i].Created.Unix())
assert.Equal(t, time.Time, apiTimes[i].Time)
user, err := user_model.GetUserByID(db.DefaultContext, time.UserID)
@@ -125,6 +125,6 @@ func TestAPIAddTrackedTimes(t *testing.T) {
DecodeJSON(t, resp, &apiNewTime)
assert.EqualValues(t, 33, apiNewTime.Time)
- assert.EqualValues(t, user2.ID, apiNewTime.UserID)
+ assert.Equal(t, user2.ID, apiNewTime.UserID)
assert.EqualValues(t, 947688818, apiNewTime.Created.Unix())
}
diff --git a/tests/integration/api_keys_test.go b/tests/integration/api_keys_test.go
index 2276b955cf..3162051acc 100644
--- a/tests/integration/api_keys_test.go
+++ b/tests/integration/api_keys_test.go
@@ -143,7 +143,7 @@ func TestCreateUserKey(t *testing.T) {
})
// Search by fingerprint
- req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/user/keys?fingerprint=%s", newPublicKey.Fingerprint)).
+ req = NewRequest(t, "GET", "/api/v1/user/keys?fingerprint="+newPublicKey.Fingerprint).
AddTokenAuth(token)
resp = MakeRequest(t, req, http.StatusOK)
@@ -183,7 +183,7 @@ func TestCreateUserKey(t *testing.T) {
token2 := getTokenForLoggedInUser(t, session2, auth_model.AccessTokenScopeWriteUser)
// Should find key even though not ours, but we shouldn't know whose it is
- req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/user/keys?fingerprint=%s", newPublicKey.Fingerprint)).
+ req = NewRequest(t, "GET", "/api/v1/user/keys?fingerprint="+newPublicKey.Fingerprint).
AddTokenAuth(token2)
resp = MakeRequest(t, req, http.StatusOK)
diff --git a/tests/integration/api_label_templates_test.go b/tests/integration/api_label_templates_test.go
index 007e979011..3e637daba6 100644
--- a/tests/integration/api_label_templates_test.go
+++ b/tests/integration/api_label_templates_test.go
@@ -4,7 +4,6 @@
package integration
import (
- "fmt"
"net/http"
"net/url"
"strings"
@@ -42,7 +41,7 @@ func TestAPIGetLabelTemplateInfo(t *testing.T) {
// Use the first template for the test
templateName := repo_module.LabelTemplateFiles[0].DisplayName
- urlStr := fmt.Sprintf("/api/v1/label/templates/%s", url.PathEscape(templateName))
+ urlStr := "/api/v1/label/templates/" + url.PathEscape(templateName)
req := NewRequest(t, "GET", urlStr)
resp := MakeRequest(t, req, http.StatusOK)
diff --git a/tests/integration/api_license_templates_test.go b/tests/integration/api_license_templates_test.go
index e12aab7c2c..52e240f9a7 100644
--- a/tests/integration/api_license_templates_test.go
+++ b/tests/integration/api_license_templates_test.go
@@ -4,7 +4,6 @@
package integration
import (
- "fmt"
"net/http"
"net/url"
"testing"
@@ -39,7 +38,7 @@ func TestAPIGetLicenseTemplateInfo(t *testing.T) {
// Use the first template for the test
licenseName := repo_module.Licenses[0]
- urlStr := fmt.Sprintf("/api/v1/licenses/%s", url.PathEscape(licenseName))
+ urlStr := "/api/v1/licenses/" + url.PathEscape(licenseName)
req := NewRequest(t, "GET", urlStr)
resp := MakeRequest(t, req, http.StatusOK)
diff --git a/tests/integration/api_nodeinfo_test.go b/tests/integration/api_nodeinfo_test.go
index 75f8dbb4ba..916c2f1723 100644
--- a/tests/integration/api_nodeinfo_test.go
+++ b/tests/integration/api_nodeinfo_test.go
@@ -5,35 +5,31 @@ package integration
import (
"net/http"
- "net/url"
"testing"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/routers"
+ "code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
)
func TestNodeinfo(t *testing.T) {
- setting.Federation.Enabled = true
- testWebRoutes = routers.NormalRoutes()
- defer func() {
- setting.Federation.Enabled = false
- testWebRoutes = routers.NormalRoutes()
- }()
+ defer tests.PrepareTestEnv(t)()
+ defer test.MockVariableValue(&setting.Federation.Enabled, true)()
+ defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
- onGiteaRun(t, func(*testing.T, *url.URL) {
- req := NewRequest(t, "GET", "/api/v1/nodeinfo")
- resp := MakeRequest(t, req, http.StatusOK)
- VerifyJSONSchema(t, resp, "nodeinfo_2.1.json")
+ req := NewRequest(t, "GET", "/api/v1/nodeinfo")
+ resp := MakeRequest(t, req, http.StatusOK)
+ VerifyJSONSchema(t, resp, "nodeinfo_2.1.json")
- var nodeinfo api.NodeInfo
- DecodeJSON(t, resp, &nodeinfo)
- assert.True(t, nodeinfo.OpenRegistrations)
- assert.Equal(t, "gitea", nodeinfo.Software.Name)
- assert.Equal(t, 29, nodeinfo.Usage.Users.Total)
- assert.Equal(t, 22, nodeinfo.Usage.LocalPosts)
- assert.Equal(t, 3, nodeinfo.Usage.LocalComments)
- })
+ var nodeinfo api.NodeInfo
+ DecodeJSON(t, resp, &nodeinfo)
+ assert.True(t, nodeinfo.OpenRegistrations)
+ assert.Equal(t, "gitea", nodeinfo.Software.Name)
+ assert.Equal(t, 29, nodeinfo.Usage.Users.Total)
+ assert.Equal(t, 22, nodeinfo.Usage.LocalPosts)
+ assert.Equal(t, 3, nodeinfo.Usage.LocalComments)
}
diff --git a/tests/integration/api_notification_test.go b/tests/integration/api_notification_test.go
index dc4ba83ecc..e6bc142476 100644
--- a/tests/integration/api_notification_test.go
+++ b/tests/integration/api_notification_test.go
@@ -35,7 +35,7 @@ func TestAPINotification(t *testing.T) {
// -- GET /notifications --
// test filter
since := "2000-01-01T00%3A50%3A01%2B00%3A00" // 946687801
- req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?since=%s", since)).
+ req := NewRequest(t, "GET", "/api/v1/notifications?since="+since).
AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
var apiNL []api.NotificationThread
@@ -104,10 +104,10 @@ func TestAPINotification(t *testing.T) {
assert.EqualValues(t, 5, apiN.ID)
assert.False(t, apiN.Pinned)
assert.True(t, apiN.Unread)
- assert.EqualValues(t, "issue4", apiN.Subject.Title)
+ assert.Equal(t, "issue4", apiN.Subject.Title)
assert.EqualValues(t, "Issue", apiN.Subject.Type)
- assert.EqualValues(t, thread5.Issue.APIURL(db.DefaultContext), apiN.Subject.URL)
- assert.EqualValues(t, thread5.Repository.HTMLURL(), apiN.Repository.HTMLURL)
+ assert.Equal(t, thread5.Issue.APIURL(db.DefaultContext), apiN.Subject.URL)
+ assert.Equal(t, thread5.Repository.HTMLURL(), apiN.Repository.HTMLURL)
MakeRequest(t, NewRequest(t, "GET", "/api/v1/notifications/new"), http.StatusUnauthorized)
diff --git a/tests/integration/api_oauth2_apps_test.go b/tests/integration/api_oauth2_apps_test.go
index 7a17b4ca88..13f64fd69e 100644
--- a/tests/integration/api_oauth2_apps_test.go
+++ b/tests/integration/api_oauth2_apps_test.go
@@ -43,12 +43,12 @@ func testAPICreateOAuth2Application(t *testing.T) {
var createdApp *api.OAuth2Application
DecodeJSON(t, resp, &createdApp)
- assert.EqualValues(t, appBody.Name, createdApp.Name)
+ assert.Equal(t, appBody.Name, createdApp.Name)
assert.Len(t, createdApp.ClientSecret, 56)
assert.Len(t, createdApp.ClientID, 36)
assert.True(t, createdApp.ConfidentialClient)
assert.NotEmpty(t, createdApp.Created)
- assert.EqualValues(t, appBody.RedirectURIs[0], createdApp.RedirectURIs[0])
+ assert.Equal(t, appBody.RedirectURIs[0], createdApp.RedirectURIs[0])
unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{UID: user.ID, Name: createdApp.Name})
}
@@ -74,12 +74,12 @@ func testAPIListOAuth2Applications(t *testing.T) {
DecodeJSON(t, resp, &appList)
expectedApp := appList[0]
- assert.EqualValues(t, expectedApp.Name, existApp.Name)
- assert.EqualValues(t, expectedApp.ClientID, existApp.ClientID)
+ assert.Equal(t, expectedApp.Name, existApp.Name)
+ assert.Equal(t, expectedApp.ClientID, existApp.ClientID)
assert.Equal(t, expectedApp.ConfidentialClient, existApp.ConfidentialClient)
assert.Len(t, expectedApp.ClientID, 36)
assert.Empty(t, expectedApp.ClientSecret)
- assert.EqualValues(t, existApp.RedirectURIs[0], expectedApp.RedirectURIs[0])
+ assert.Equal(t, existApp.RedirectURIs[0], expectedApp.RedirectURIs[0])
unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: expectedApp.ID, Name: expectedApp.Name})
}
@@ -128,13 +128,13 @@ func testAPIGetOAuth2Application(t *testing.T) {
DecodeJSON(t, resp, &app)
expectedApp := app
- assert.EqualValues(t, expectedApp.Name, existApp.Name)
- assert.EqualValues(t, expectedApp.ClientID, existApp.ClientID)
+ assert.Equal(t, expectedApp.Name, existApp.Name)
+ assert.Equal(t, expectedApp.ClientID, existApp.ClientID)
assert.Equal(t, expectedApp.ConfidentialClient, existApp.ConfidentialClient)
assert.Len(t, expectedApp.ClientID, 36)
assert.Empty(t, expectedApp.ClientSecret)
assert.Len(t, expectedApp.RedirectURIs, 1)
- assert.EqualValues(t, expectedApp.RedirectURIs[0], existApp.RedirectURIs[0])
+ assert.Equal(t, expectedApp.RedirectURIs[0], existApp.RedirectURIs[0])
unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: expectedApp.ID, Name: expectedApp.Name})
}
@@ -168,8 +168,8 @@ func testAPIUpdateOAuth2Application(t *testing.T) {
expectedApp := app
assert.Len(t, expectedApp.RedirectURIs, 2)
- assert.EqualValues(t, expectedApp.RedirectURIs[0], appBody.RedirectURIs[0])
- assert.EqualValues(t, expectedApp.RedirectURIs[1], appBody.RedirectURIs[1])
+ assert.Equal(t, expectedApp.RedirectURIs[0], appBody.RedirectURIs[0])
+ assert.Equal(t, expectedApp.RedirectURIs[1], appBody.RedirectURIs[1])
assert.Equal(t, expectedApp.ConfidentialClient, appBody.ConfidentialClient)
unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: expectedApp.ID, Name: expectedApp.Name})
}
diff --git a/tests/integration/api_org_test.go b/tests/integration/api_org_test.go
index fff121490c..6577bd1684 100644
--- a/tests/integration/api_org_test.go
+++ b/tests/integration/api_org_test.go
@@ -6,7 +6,6 @@ package integration
import (
"fmt"
"net/http"
- "net/url"
"strings"
"testing"
@@ -19,46 +18,53 @@ import (
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
-func TestAPIOrgCreate(t *testing.T) {
- onGiteaRun(t, func(*testing.T, *url.URL) {
- token := getUserToken(t, "user1", auth_model.AccessTokenScopeWriteOrganization)
-
- org := api.CreateOrgOption{
- UserName: "user1_org",
- FullName: "User1's organization",
- Description: "This organization created by user1",
- Website: "https://try.gitea.io",
- Location: "Shanghai",
- Visibility: "limited",
- }
- req := NewRequestWithJSON(t, "POST", "/api/v1/orgs", &org).
- AddTokenAuth(token)
- resp := MakeRequest(t, req, http.StatusCreated)
-
- var apiOrg api.Organization
- DecodeJSON(t, resp, &apiOrg)
-
- assert.Equal(t, org.UserName, apiOrg.Name)
- assert.Equal(t, org.FullName, apiOrg.FullName)
- assert.Equal(t, org.Description, apiOrg.Description)
- assert.Equal(t, org.Website, apiOrg.Website)
- assert.Equal(t, org.Location, apiOrg.Location)
- assert.Equal(t, org.Visibility, apiOrg.Visibility)
+func TestAPIOrgCreateRename(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+ token := getUserToken(t, "user1", auth_model.AccessTokenScopeWriteOrganization)
+
+ org := api.CreateOrgOption{
+ UserName: "user1_org",
+ FullName: "User1's organization",
+ Description: "This organization created by user1",
+ Website: "https://try.gitea.io",
+ Location: "Shanghai",
+ Visibility: "limited",
+ }
+ req := NewRequestWithJSON(t, "POST", "/api/v1/orgs", &org).AddTokenAuth(token)
+ resp := MakeRequest(t, req, http.StatusCreated)
+
+ var apiOrg api.Organization
+ DecodeJSON(t, resp, &apiOrg)
+
+ assert.Equal(t, org.UserName, apiOrg.Name)
+ assert.Equal(t, org.FullName, apiOrg.FullName)
+ assert.Equal(t, org.Description, apiOrg.Description)
+ assert.Equal(t, org.Website, apiOrg.Website)
+ assert.Equal(t, org.Location, apiOrg.Location)
+ assert.Equal(t, org.Visibility, apiOrg.Visibility)
+
+ unittest.AssertExistsAndLoadBean(t, &user_model.User{
+ Name: org.UserName,
+ LowerName: strings.ToLower(org.UserName),
+ FullName: org.FullName,
+ })
- unittest.AssertExistsAndLoadBean(t, &user_model.User{
- Name: org.UserName,
- LowerName: strings.ToLower(org.UserName),
- FullName: org.FullName,
- })
+ // check org name
+ req = NewRequestf(t, "GET", "/api/v1/orgs/%s", org.UserName).AddTokenAuth(token)
+ resp = MakeRequest(t, req, http.StatusOK)
+ DecodeJSON(t, resp, &apiOrg)
+ assert.Equal(t, org.UserName, apiOrg.Name)
+ t.Run("CheckPermission", func(t *testing.T) {
// Check owner team permission
ownerTeam, _ := org_model.GetOwnerTeam(db.DefaultContext, apiOrg.ID)
-
for _, ut := range unit_model.AllRepoUnitTypes {
up := perm.AccessModeOwner
if ut == unit_model.TypeExternalTracker || ut == unit_model.TypeExternalWiki {
@@ -71,40 +77,67 @@ func TestAPIOrgCreate(t *testing.T) {
AccessMode: up,
})
}
+ })
- req = NewRequestf(t, "GET", "/api/v1/orgs/%s", org.UserName).
- AddTokenAuth(token)
+ t.Run("CheckMembers", func(t *testing.T) {
+ req = NewRequestf(t, "GET", "/api/v1/orgs/%s/members", org.UserName).AddTokenAuth(token)
resp = MakeRequest(t, req, http.StatusOK)
- DecodeJSON(t, resp, &apiOrg)
- assert.EqualValues(t, org.UserName, apiOrg.Name)
- req = NewRequestf(t, "GET", "/api/v1/orgs/%s/repos", org.UserName).
- AddTokenAuth(token)
- resp = MakeRequest(t, req, http.StatusOK)
+ // user1 on this org is public
+ var users []*api.User
+ DecodeJSON(t, resp, &users)
+ assert.Len(t, users, 1)
+ assert.Equal(t, "user1", users[0].UserName)
+ })
+ t.Run("RenameOrg", func(t *testing.T) {
+ req = NewRequestWithJSON(t, "POST", "/api/v1/orgs/user1_org/rename", &api.RenameOrgOption{
+ NewName: "renamed_org",
+ }).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNoContent)
+ unittest.AssertExistsAndLoadBean(t, &org_model.Organization{Name: "renamed_org"})
+ org.UserName = "renamed_org" // update the variable so the following tests could still use it
+ })
+
+ t.Run("ListRepos", func(t *testing.T) {
+ // FIXME: this test is wrong, there is no repository at all, so the for-loop is empty
+ req = NewRequestf(t, "GET", "/api/v1/orgs/%s/repos", org.UserName).AddTokenAuth(token)
+ resp = MakeRequest(t, req, http.StatusOK)
var repos []*api.Repository
DecodeJSON(t, resp, &repos)
for _, repo := range repos {
assert.False(t, repo.Private)
}
+ })
+}
+
+func TestAPIOrgGeneral(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+ user1Session := loginUser(t, "user1")
+ user1Token := getTokenForLoggedInUser(t, user1Session, auth_model.AccessTokenScopeWriteOrganization)
- req = NewRequestf(t, "GET", "/api/v1/orgs/%s/members", org.UserName).
- AddTokenAuth(token)
+ t.Run("OrgGetAll", func(t *testing.T) {
+ // accessing with a token will return all orgs
+ req := NewRequest(t, "GET", "/api/v1/orgs").AddTokenAuth(user1Token)
+ resp := MakeRequest(t, req, http.StatusOK)
+ var apiOrgList []*api.Organization
+
+ DecodeJSON(t, resp, &apiOrgList)
+ assert.Len(t, apiOrgList, 13)
+ assert.Equal(t, "Limited Org 36", apiOrgList[1].FullName)
+ assert.Equal(t, "limited", apiOrgList[1].Visibility)
+
+ // accessing without a token will return only public orgs
+ req = NewRequest(t, "GET", "/api/v1/orgs")
resp = MakeRequest(t, req, http.StatusOK)
- // user1 on this org is public
- var users []*api.User
- DecodeJSON(t, resp, &users)
- assert.Len(t, users, 1)
- assert.EqualValues(t, "user1", users[0].UserName)
+ DecodeJSON(t, resp, &apiOrgList)
+ assert.Len(t, apiOrgList, 9)
+ assert.Equal(t, "org 17", apiOrgList[0].FullName)
+ assert.Equal(t, "public", apiOrgList[0].Visibility)
})
-}
-func TestAPIOrgEdit(t *testing.T) {
- onGiteaRun(t, func(*testing.T, *url.URL) {
- session := loginUser(t, "user1")
-
- token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization)
+ t.Run("OrgEdit", func(t *testing.T) {
org := api.EditOrgOption{
FullName: "Org3 organization new full name",
Description: "A new description",
@@ -112,8 +145,7 @@ func TestAPIOrgEdit(t *testing.T) {
Location: "Beijing",
Visibility: "private",
}
- req := NewRequestWithJSON(t, "PATCH", "/api/v1/orgs/org3", &org).
- AddTokenAuth(token)
+ req := NewRequestWithJSON(t, "PATCH", "/api/v1/orgs/org3", &org).AddTokenAuth(user1Token)
resp := MakeRequest(t, req, http.StatusOK)
var apiOrg api.Organization
@@ -126,13 +158,8 @@ func TestAPIOrgEdit(t *testing.T) {
assert.Equal(t, org.Location, apiOrg.Location)
assert.Equal(t, org.Visibility, apiOrg.Visibility)
})
-}
-func TestAPIOrgEditBadVisibility(t *testing.T) {
- onGiteaRun(t, func(*testing.T, *url.URL) {
- session := loginUser(t, "user1")
-
- token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization)
+ t.Run("OrgEditBadVisibility", func(t *testing.T) {
org := api.EditOrgOption{
FullName: "Org3 organization new full name",
Description: "A new description",
@@ -140,18 +167,12 @@ func TestAPIOrgEditBadVisibility(t *testing.T) {
Location: "Beijing",
Visibility: "badvisibility",
}
- req := NewRequestWithJSON(t, "PATCH", "/api/v1/orgs/org3", &org).
- AddTokenAuth(token)
+ req := NewRequestWithJSON(t, "PATCH", "/api/v1/orgs/org3", &org).AddTokenAuth(user1Token)
MakeRequest(t, req, http.StatusUnprocessableEntity)
})
-}
-func TestAPIOrgDeny(t *testing.T) {
- onGiteaRun(t, func(*testing.T, *url.URL) {
- setting.Service.RequireSignInView = true
- defer func() {
- setting.Service.RequireSignInView = false
- }()
+ t.Run("OrgDeny", func(t *testing.T) {
+ defer test.MockVariableValue(&setting.Service.RequireSignInViewStrict, true)()
orgName := "user1_org"
req := NewRequestf(t, "GET", "/api/v1/orgs/%s", orgName)
@@ -163,43 +184,13 @@ func TestAPIOrgDeny(t *testing.T) {
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/members", orgName)
MakeRequest(t, req, http.StatusNotFound)
})
-}
-
-func TestAPIGetAll(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
- token := getUserToken(t, "user1", auth_model.AccessTokenScopeReadOrganization)
-
- // accessing with a token will return all orgs
- req := NewRequest(t, "GET", "/api/v1/orgs").
- AddTokenAuth(token)
- resp := MakeRequest(t, req, http.StatusOK)
- var apiOrgList []*api.Organization
-
- DecodeJSON(t, resp, &apiOrgList)
- assert.Len(t, apiOrgList, 13)
- assert.Equal(t, "Limited Org 36", apiOrgList[1].FullName)
- assert.Equal(t, "limited", apiOrgList[1].Visibility)
-
- // accessing without a token will return only public orgs
- req = NewRequest(t, "GET", "/api/v1/orgs")
- resp = MakeRequest(t, req, http.StatusOK)
-
- DecodeJSON(t, resp, &apiOrgList)
- assert.Len(t, apiOrgList, 9)
- assert.Equal(t, "org 17", apiOrgList[0].FullName)
- assert.Equal(t, "public", apiOrgList[0].Visibility)
-}
-
-func TestAPIOrgSearchEmptyTeam(t *testing.T) {
- onGiteaRun(t, func(*testing.T, *url.URL) {
- token := getUserToken(t, "user1", auth_model.AccessTokenScopeWriteOrganization)
+ t.Run("OrgSearchEmptyTeam", func(t *testing.T) {
orgName := "org_with_empty_team"
-
// create org
req := NewRequestWithJSON(t, "POST", "/api/v1/orgs", &api.CreateOrgOption{
UserName: orgName,
- }).AddTokenAuth(token)
+ }).AddTokenAuth(user1Token)
MakeRequest(t, req, http.StatusCreated)
// create team with no member
@@ -208,12 +199,12 @@ func TestAPIOrgSearchEmptyTeam(t *testing.T) {
IncludesAllRepositories: true,
Permission: "read",
Units: []string{"repo.code", "repo.issues", "repo.ext_issues", "repo.wiki", "repo.pulls"},
- }).AddTokenAuth(token)
+ }).AddTokenAuth(user1Token)
MakeRequest(t, req, http.StatusCreated)
// case-insensitive search for teams that have no members
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/orgs/%s/teams/search?q=%s", orgName, "empty")).
- AddTokenAuth(token)
+ AddTokenAuth(user1Token)
resp := MakeRequest(t, req, http.StatusOK)
data := struct {
Ok bool
@@ -222,7 +213,40 @@ func TestAPIOrgSearchEmptyTeam(t *testing.T) {
DecodeJSON(t, resp, &data)
assert.True(t, data.Ok)
if assert.Len(t, data.Data, 1) {
- assert.EqualValues(t, "Empty", data.Data[0].Name)
+ assert.Equal(t, "Empty", data.Data[0].Name)
}
})
+
+ t.Run("User2ChangeStatus", func(t *testing.T) {
+ user2Session := loginUser(t, "user2")
+ user2Token := getTokenForLoggedInUser(t, user2Session, auth_model.AccessTokenScopeWriteOrganization)
+
+ req := NewRequest(t, "PUT", "/api/v1/orgs/org3/public_members/user2").AddTokenAuth(user2Token)
+ MakeRequest(t, req, http.StatusNoContent)
+ req = NewRequest(t, "DELETE", "/api/v1/orgs/org3/public_members/user2").AddTokenAuth(user2Token)
+ MakeRequest(t, req, http.StatusNoContent)
+
+ // non admin but org owner could also change other member's status
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user2"})
+ require.False(t, user2.IsAdmin)
+ req = NewRequest(t, "PUT", "/api/v1/orgs/org3/public_members/user1").AddTokenAuth(user2Token)
+ MakeRequest(t, req, http.StatusNoContent)
+ req = NewRequest(t, "DELETE", "/api/v1/orgs/org3/public_members/user1").AddTokenAuth(user2Token)
+ MakeRequest(t, req, http.StatusNoContent)
+ })
+
+ t.Run("User4ChangeStatus", func(t *testing.T) {
+ user4Session := loginUser(t, "user4")
+ user4Token := getTokenForLoggedInUser(t, user4Session, auth_model.AccessTokenScopeWriteOrganization)
+
+ // user4 is a normal team member, they could change their own status
+ req := NewRequest(t, "PUT", "/api/v1/orgs/org3/public_members/user4").AddTokenAuth(user4Token)
+ MakeRequest(t, req, http.StatusNoContent)
+ req = NewRequest(t, "DELETE", "/api/v1/orgs/org3/public_members/user4").AddTokenAuth(user4Token)
+ MakeRequest(t, req, http.StatusNoContent)
+ req = NewRequest(t, "PUT", "/api/v1/orgs/org3/public_members/user1").AddTokenAuth(user4Token)
+ MakeRequest(t, req, http.StatusForbidden)
+ req = NewRequest(t, "DELETE", "/api/v1/orgs/org3/public_members/user1").AddTokenAuth(user4Token)
+ MakeRequest(t, req, http.StatusForbidden)
+ })
}
diff --git a/tests/integration/api_packages_arch_test.go b/tests/integration/api_packages_arch_test.go
index 9c7a9dd19d..e5778b4203 100644
--- a/tests/integration/api_packages_arch_test.go
+++ b/tests/integration/api_packages_arch_test.go
@@ -79,6 +79,34 @@ license = MIT`)
return buf.Bytes()
}
+ readIndexContent := func(r io.Reader) (map[string]string, error) {
+ gzr, err := gzip.NewReader(r)
+ if err != nil {
+ return nil, err
+ }
+
+ content := make(map[string]string)
+
+ tr := tar.NewReader(gzr)
+ for {
+ hd, err := tr.Next()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ buf, err := io.ReadAll(tr)
+ if err != nil {
+ return nil, err
+ }
+
+ content[hd.Name] = string(buf)
+ }
+
+ return content, nil
+ }
compressions := []string{"gz", "xz", "zst"}
repositories := []string{"main", "testing", "with/slash", ""}
@@ -135,7 +163,7 @@ license = MIT`)
assert.Condition(t, func() bool {
seen := false
expectedFilename := fmt.Sprintf("%s-%s-aarch64.pkg.tar.%s", packageName, packageVersion, compression)
- expectedCompositeKey := fmt.Sprintf("%s|aarch64", repository)
+ expectedCompositeKey := repository + "|aarch64"
for _, pf := range pfs {
if pf.Name == expectedFilename && pf.CompositeKey == expectedCompositeKey {
if seen {
@@ -171,35 +199,6 @@ license = MIT`)
MakeRequest(t, req, http.StatusConflict)
})
- readIndexContent := func(r io.Reader) (map[string]string, error) {
- gzr, err := gzip.NewReader(r)
- if err != nil {
- return nil, err
- }
-
- content := make(map[string]string)
-
- tr := tar.NewReader(gzr)
- for {
- hd, err := tr.Next()
- if err == io.EOF {
- break
- }
- if err != nil {
- return nil, err
- }
-
- buf, err := io.ReadAll(tr)
- if err != nil {
- return nil, err
- }
-
- content[hd.Name] = string(buf)
- }
-
- return content, nil
- }
-
t.Run("Index", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
@@ -299,4 +298,39 @@ license = MIT`)
})
}
}
+ t.Run("KeepLastVersion", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+ pkgVer1 := createPackage("gz", "gitea-test", "1.0.0", "aarch64")
+ pkgVer2 := createPackage("gz", "gitea-test", "1.0.1", "aarch64")
+ req := NewRequestWithBody(t, "PUT", rootURL, bytes.NewReader(pkgVer1)).
+ AddBasicAuth(user.Name)
+ MakeRequest(t, req, http.StatusCreated)
+ req = NewRequestWithBody(t, "PUT", rootURL, bytes.NewReader(pkgVer2)).
+ AddBasicAuth(user.Name)
+ MakeRequest(t, req, http.StatusCreated)
+
+ req = NewRequest(t, "GET", fmt.Sprintf("%s/aarch64/%s", rootURL, arch_service.IndexArchiveFilename))
+ resp := MakeRequest(t, req, http.StatusOK)
+
+ content, err := readIndexContent(resp.Body)
+ assert.NoError(t, err)
+ assert.Len(t, content, 2)
+
+ _, has := content["gitea-test-1.0.0/desc"]
+ assert.False(t, has)
+ _, has = content["gitea-test-1.0.1/desc"]
+ assert.True(t, has)
+
+ req = NewRequest(t, "DELETE", rootURL+"/gitea-test/1.0.1/aarch64").
+ AddBasicAuth(user.Name)
+ MakeRequest(t, req, http.StatusNoContent)
+
+ req = NewRequest(t, "GET", fmt.Sprintf("%s/aarch64/%s", rootURL, arch_service.IndexArchiveFilename))
+ resp = MakeRequest(t, req, http.StatusOK)
+ content, err = readIndexContent(resp.Body)
+ assert.NoError(t, err)
+ assert.Len(t, content, 2)
+ _, has = content["gitea-test-1.0.0/desc"]
+ assert.True(t, has)
+ })
}
diff --git a/tests/integration/api_packages_cargo_test.go b/tests/integration/api_packages_cargo_test.go
index 3fb9687653..8b5caa7ea7 100644
--- a/tests/integration/api_packages_cargo_test.go
+++ b/tests/integration/api_packages_cargo_test.go
@@ -94,7 +94,7 @@ func testPackageCargo(t *testing.T, _ *neturl.URL) {
}
root := fmt.Sprintf("%sapi/packages/%s/cargo", setting.AppURL, user.Name)
- url := fmt.Sprintf("%s/api/v1/crates", root)
+ url := root + "/api/v1/crates"
t.Run("Index", func(t *testing.T) {
t.Run("Git/Config", func(t *testing.T) {
diff --git a/tests/integration/api_packages_chef_test.go b/tests/integration/api_packages_chef_test.go
index 6efb2708af..8f2c2592e7 100644
--- a/tests/integration/api_packages_chef_test.go
+++ b/tests/integration/api_packages_chef_test.go
@@ -181,7 +181,7 @@ nwIDAQAB
var data []byte
if version == "1.3" {
- data = []byte(fmt.Sprintf(
+ data = fmt.Appendf(nil,
"Method:%s\nPath:%s\nX-Ops-Content-Hash:%s\nX-Ops-Sign:version=%s\nX-Ops-Timestamp:%s\nX-Ops-UserId:%s\nX-Ops-Server-API-Version:%s",
req.Method,
path.Clean(req.URL.Path),
@@ -190,17 +190,17 @@ nwIDAQAB
req.Header.Get("X-Ops-Timestamp"),
username,
req.Header.Get("X-Ops-Server-Api-Version"),
- ))
+ )
} else {
sum := sha1.Sum([]byte(path.Clean(req.URL.Path)))
- data = []byte(fmt.Sprintf(
+ data = fmt.Appendf(nil,
"Method:%s\nHashed Path:%s\nX-Ops-Content-Hash:%s\nX-Ops-Timestamp:%s\nX-Ops-UserId:%s",
req.Method,
base64.StdEncoding.EncodeToString(sum[:]),
req.Header.Get("X-Ops-Content-Hash"),
req.Header.Get("X-Ops-Timestamp"),
username,
- ))
+ )
}
for k := range req.Header {
@@ -274,7 +274,7 @@ nwIDAQAB
uploadPackage := func(t *testing.T, version string, expectedStatus int) {
var body bytes.Buffer
mpw := multipart.NewWriter(&body)
- part, _ := mpw.CreateFormFile("tarball", fmt.Sprintf("%s.tar.gz", version))
+ part, _ := mpw.CreateFormFile("tarball", version+".tar.gz")
zw := gzip.NewWriter(part)
tw := tar.NewWriter(zw)
@@ -320,7 +320,7 @@ nwIDAQAB
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
assert.NoError(t, err)
assert.Len(t, pfs, 1)
- assert.Equal(t, fmt.Sprintf("%s.tar.gz", packageVersion), pfs[0].Name)
+ assert.Equal(t, packageVersion+".tar.gz", pfs[0].Name)
assert.True(t, pfs[0].IsLead)
uploadPackage(t, packageVersion, http.StatusConflict)
diff --git a/tests/integration/api_packages_composer_test.go b/tests/integration/api_packages_composer_test.go
index 51b047ab41..54f61d91d9 100644
--- a/tests/integration/api_packages_composer_test.go
+++ b/tests/integration/api_packages_composer_test.go
@@ -13,6 +13,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/packages"
+ repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
composer_module "code.gitea.io/gitea/modules/packages/composer"
@@ -63,7 +64,7 @@ func TestPackageComposer(t *testing.T) {
t.Run("ServiceIndex", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("%s/packages.json", url)).
+ req := NewRequest(t, "GET", url+"/packages.json").
AddBasicAuth(user.Name)
resp := MakeRequest(t, req, http.StatusOK)
@@ -217,5 +218,39 @@ func TestPackageComposer(t *testing.T) {
assert.Equal(t, "4f5fa464c3cb808a1df191dbf6cb75363f8b7072", pkgs[0].Dist.Checksum)
assert.Len(t, pkgs[0].Bin, 1)
assert.Equal(t, packageBin, pkgs[0].Bin[0])
+
+ // Test package linked to repository
+ repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+ userPkgs, err := packages.GetPackagesByType(db.DefaultContext, user.ID, packages.TypeComposer)
+ assert.NoError(t, err)
+ assert.Len(t, userPkgs, 1)
+ assert.EqualValues(t, 0, userPkgs[0].RepoID)
+
+ err = packages.SetRepositoryLink(db.DefaultContext, userPkgs[0].ID, repo1.ID)
+ assert.NoError(t, err)
+
+ req = NewRequest(t, "GET", fmt.Sprintf("%s/p2/%s/%s.json", url, vendorName, projectName)).
+ AddBasicAuth(user.Name)
+ resp = MakeRequest(t, req, http.StatusOK)
+
+ result = composer.PackageMetadataResponse{}
+ DecodeJSON(t, resp, &result)
+
+ assert.Contains(t, result.Packages, packageName)
+ pkgs = result.Packages[packageName]
+ assert.Len(t, pkgs, 1)
+ assert.Equal(t, packageName, pkgs[0].Name)
+ assert.Equal(t, packageVersion, pkgs[0].Version)
+ assert.Equal(t, packageType, pkgs[0].Type)
+ assert.Equal(t, packageDescription, pkgs[0].Description)
+ assert.Len(t, pkgs[0].Authors, 1)
+ assert.Equal(t, packageAuthor, pkgs[0].Authors[0].Name)
+ assert.Equal(t, "zip", pkgs[0].Dist.Type)
+ assert.Equal(t, "4f5fa464c3cb808a1df191dbf6cb75363f8b7072", pkgs[0].Dist.Checksum)
+ assert.Len(t, pkgs[0].Bin, 1)
+ assert.Equal(t, packageBin, pkgs[0].Bin[0])
+ assert.Equal(t, repo1.HTMLURL(), pkgs[0].Source.URL)
+ assert.Equal(t, "git", pkgs[0].Source.Type)
+ assert.Equal(t, packageVersion, pkgs[0].Source.Reference)
})
}
diff --git a/tests/integration/api_packages_conan_test.go b/tests/integration/api_packages_conan_test.go
index 3055e57a2e..4e83c998b8 100644
--- a/tests/integration/api_packages_conan_test.go
+++ b/tests/integration/api_packages_conan_test.go
@@ -91,18 +91,18 @@ func uploadConanPackageV1(t *testing.T, baseURL, token, name, version, user, cha
AddTokenAuth(token)
MakeRequest(t, req, http.StatusNotFound)
- req = NewRequest(t, "GET", fmt.Sprintf("%s/digest", recipeURL)).
+ req = NewRequest(t, "GET", recipeURL+"/digest").
AddTokenAuth(token)
MakeRequest(t, req, http.StatusNotFound)
- req = NewRequest(t, "GET", fmt.Sprintf("%s/download_urls", recipeURL)).
+ req = NewRequest(t, "GET", recipeURL+"/download_urls").
AddTokenAuth(token)
MakeRequest(t, req, http.StatusNotFound)
- req = NewRequest(t, "POST", fmt.Sprintf("%s/upload_urls", recipeURL))
+ req = NewRequest(t, "POST", recipeURL+"/upload_urls")
MakeRequest(t, req, http.StatusUnauthorized)
- req = NewRequestWithJSON(t, "POST", fmt.Sprintf("%s/upload_urls", recipeURL), map[string]int64{
+ req = NewRequestWithJSON(t, "POST", recipeURL+"/upload_urls", map[string]int64{
conanfileName: int64(len(contentConanfile)),
"removed.txt": 0,
}).AddTokenAuth(token)
@@ -127,18 +127,18 @@ func uploadConanPackageV1(t *testing.T, baseURL, token, name, version, user, cha
AddTokenAuth(token)
MakeRequest(t, req, http.StatusNotFound)
- req = NewRequest(t, "GET", fmt.Sprintf("%s/digest", packageURL)).
+ req = NewRequest(t, "GET", packageURL+"/digest").
AddTokenAuth(token)
MakeRequest(t, req, http.StatusNotFound)
- req = NewRequest(t, "GET", fmt.Sprintf("%s/download_urls", packageURL)).
+ req = NewRequest(t, "GET", packageURL+"/download_urls").
AddTokenAuth(token)
MakeRequest(t, req, http.StatusNotFound)
- req = NewRequest(t, "POST", fmt.Sprintf("%s/upload_urls", packageURL))
+ req = NewRequest(t, "POST", packageURL+"/upload_urls")
MakeRequest(t, req, http.StatusUnauthorized)
- req = NewRequestWithJSON(t, "POST", fmt.Sprintf("%s/upload_urls", packageURL), map[string]int64{
+ req = NewRequestWithJSON(t, "POST", packageURL+"/upload_urls", map[string]int64{
conaninfoName: int64(len(contentConaninfo)),
"removed.txt": 0,
}).AddTokenAuth(token)
@@ -167,7 +167,7 @@ func uploadConanPackageV2(t *testing.T, baseURL, token, name, version, user, cha
AddTokenAuth(token)
MakeRequest(t, req, http.StatusCreated)
- req = NewRequest(t, "GET", fmt.Sprintf("%s/files", recipeURL)).
+ req = NewRequest(t, "GET", recipeURL+"/files").
AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
@@ -180,7 +180,7 @@ func uploadConanPackageV2(t *testing.T, baseURL, token, name, version, user, cha
packageURL := fmt.Sprintf("%s/packages/%s/revisions/%s", recipeURL, conanPackageReference, packageRevision)
- req = NewRequest(t, "GET", fmt.Sprintf("%s/files", packageURL)).
+ req = NewRequest(t, "GET", packageURL+"/files").
AddTokenAuth(token)
MakeRequest(t, req, http.StatusNotFound)
@@ -188,7 +188,7 @@ func uploadConanPackageV2(t *testing.T, baseURL, token, name, version, user, cha
AddTokenAuth(token)
MakeRequest(t, req, http.StatusCreated)
- req = NewRequest(t, "GET", fmt.Sprintf("%s/files", packageURL)).
+ req = NewRequest(t, "GET", packageURL+"/files").
AddTokenAuth(token)
resp = MakeRequest(t, req, http.StatusOK)
@@ -219,7 +219,7 @@ func TestPackageConan(t *testing.T) {
t.Run("Ping", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("%s/v1/ping", url))
+ req := NewRequest(t, "GET", url+"/v1/ping")
resp := MakeRequest(t, req, http.StatusOK)
assert.Equal(t, "revisions", resp.Header().Get("X-Conan-Server-Capabilities"))
@@ -230,7 +230,7 @@ func TestPackageConan(t *testing.T) {
t.Run("UserName/Password Authenticate", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("%s/v1/users/authenticate", url)).
+ req := NewRequest(t, "GET", url+"/v1/users/authenticate").
AddBasicAuth(user.Name)
resp := MakeRequest(t, req, http.StatusOK)
@@ -256,7 +256,7 @@ func TestPackageConan(t *testing.T) {
token := getTokenForLoggedInUser(t, session, scope)
- req := NewRequest(t, "GET", fmt.Sprintf("%s/v1/users/authenticate", url)).
+ req := NewRequest(t, "GET", url+"/v1/users/authenticate").
AddTokenAuth(token)
resp := MakeRequest(t, req, expectedAuthStatusCode)
if expectedAuthStatusCode != http.StatusOK {
@@ -273,7 +273,7 @@ func TestPackageConan(t *testing.T) {
recipeURL := fmt.Sprintf("%s/v1/conans/%s/%s/%s/%s", url, "TestScope", version1, "testing", channel1)
- req = NewRequestWithJSON(t, "POST", fmt.Sprintf("%s/upload_urls", recipeURL), map[string]int64{
+ req = NewRequestWithJSON(t, "POST", recipeURL+"/upload_urls", map[string]int64{
conanfileName: 64,
"removed.txt": 0,
}).AddTokenAuth(token)
@@ -308,7 +308,7 @@ func TestPackageConan(t *testing.T) {
t.Run("CheckCredentials", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("%s/v1/users/check_credentials", url)).
+ req := NewRequest(t, "GET", url+"/v1/users/check_credentials").
AddTokenAuth(token)
MakeRequest(t, req, http.StatusOK)
})
@@ -356,7 +356,7 @@ func TestPackageConan(t *testing.T) {
assert.Equal(t, int64(len(contentConaninfo)), pb.Size)
} else {
- assert.FailNow(t, "unknown file: %s", pf.Name)
+ assert.FailNow(t, "unknown file", "unknown file: %s", pf.Name)
}
}
})
@@ -376,14 +376,14 @@ func TestPackageConan(t *testing.T) {
assert.Contains(t, fileHashes, conanfileName)
assert.Equal(t, "7abc52241c22090782c54731371847a8", fileHashes[conanfileName])
- req = NewRequest(t, "GET", fmt.Sprintf("%s/digest", recipeURL))
+ req = NewRequest(t, "GET", recipeURL+"/digest")
resp = MakeRequest(t, req, http.StatusOK)
downloadURLs := make(map[string]string)
DecodeJSON(t, resp, &downloadURLs)
assert.Contains(t, downloadURLs, conanfileName)
- req = NewRequest(t, "GET", fmt.Sprintf("%s/download_urls", recipeURL))
+ req = NewRequest(t, "GET", recipeURL+"/download_urls")
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &downloadURLs)
@@ -404,14 +404,14 @@ func TestPackageConan(t *testing.T) {
assert.Contains(t, fileHashes, conaninfoName)
assert.Equal(t, "7628bfcc5b17f1470c468621a78df394", fileHashes[conaninfoName])
- req = NewRequest(t, "GET", fmt.Sprintf("%s/digest", packageURL))
+ req = NewRequest(t, "GET", packageURL+"/digest")
resp = MakeRequest(t, req, http.StatusOK)
downloadURLs = make(map[string]string)
DecodeJSON(t, resp, &downloadURLs)
assert.Contains(t, downloadURLs, conaninfoName)
- req = NewRequest(t, "GET", fmt.Sprintf("%s/download_urls", packageURL))
+ req = NewRequest(t, "GET", packageURL+"/download_urls")
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &downloadURLs)
@@ -550,7 +550,7 @@ func TestPackageConan(t *testing.T) {
t.Run("Ping", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("%s/v2/ping", url))
+ req := NewRequest(t, "GET", url+"/v2/ping")
resp := MakeRequest(t, req, http.StatusOK)
assert.Equal(t, "revisions", resp.Header().Get("X-Conan-Server-Capabilities"))
@@ -561,7 +561,7 @@ func TestPackageConan(t *testing.T) {
t.Run("UserName/Password Authenticate", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("%s/v2/users/authenticate", url)).
+ req := NewRequest(t, "GET", url+"/v2/users/authenticate").
AddBasicAuth(user.Name)
resp := MakeRequest(t, req, http.StatusOK)
@@ -573,7 +573,7 @@ func TestPackageConan(t *testing.T) {
assert.Equal(t, user.ID, pkgMeta.UserID)
assert.Equal(t, auth_model.AccessTokenScopeAll, pkgMeta.Scope)
- token = fmt.Sprintf("Bearer %s", body)
+ token = "Bearer " + body
})
badToken := ""
@@ -590,7 +590,7 @@ func TestPackageConan(t *testing.T) {
token := getTokenForLoggedInUser(t, session, scope)
- req := NewRequest(t, "GET", fmt.Sprintf("%s/v2/users/authenticate", url)).
+ req := NewRequest(t, "GET", url+"/v2/users/authenticate").
AddTokenAuth(token)
resp := MakeRequest(t, req, expectedAuthStatusCode)
if expectedAuthStatusCode != http.StatusOK {
@@ -640,7 +640,7 @@ func TestPackageConan(t *testing.T) {
t.Run("CheckCredentials", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("%s/v2/users/check_credentials", url)).
+ req := NewRequest(t, "GET", url+"/v2/users/check_credentials").
AddTokenAuth(token)
MakeRequest(t, req, http.StatusOK)
})
@@ -664,7 +664,7 @@ func TestPackageConan(t *testing.T) {
recipeURL := fmt.Sprintf("%s/v2/conans/%s/%s/%s/%s", url, name, version1, user1, channel1)
- req := NewRequest(t, "GET", fmt.Sprintf("%s/latest", recipeURL))
+ req := NewRequest(t, "GET", recipeURL+"/latest")
resp := MakeRequest(t, req, http.StatusOK)
obj := make(map[string]string)
diff --git a/tests/integration/api_packages_conda_test.go b/tests/integration/api_packages_conda_test.go
index 272a660d45..32f55e5435 100644
--- a/tests/integration/api_packages_conda_test.go
+++ b/tests/integration/api_packages_conda_test.go
@@ -193,19 +193,19 @@ func TestPackageConda(t *testing.T) {
Removed map[string]*PackageInfo `json:"removed"`
}
- req := NewRequest(t, "GET", fmt.Sprintf("%s/noarch/repodata.json", root))
+ req := NewRequest(t, "GET", root+"/noarch/repodata.json")
resp := MakeRequest(t, req, http.StatusOK)
assert.Equal(t, "application/json", resp.Header().Get("Content-Type"))
- req = NewRequest(t, "GET", fmt.Sprintf("%s/noarch/repodata.json.bz2", root))
+ req = NewRequest(t, "GET", root+"/noarch/repodata.json.bz2")
resp = MakeRequest(t, req, http.StatusOK)
assert.Equal(t, "application/x-bzip2", resp.Header().Get("Content-Type"))
- req = NewRequest(t, "GET", fmt.Sprintf("%s/noarch/current_repodata.json", root))
+ req = NewRequest(t, "GET", root+"/noarch/current_repodata.json")
resp = MakeRequest(t, req, http.StatusOK)
assert.Equal(t, "application/json", resp.Header().Get("Content-Type"))
- req = NewRequest(t, "GET", fmt.Sprintf("%s/noarch/current_repodata.json.bz2", root))
+ req = NewRequest(t, "GET", root+"/noarch/current_repodata.json.bz2")
resp = MakeRequest(t, req, http.StatusOK)
assert.Equal(t, "application/x-bzip2", resp.Header().Get("Content-Type"))
@@ -218,7 +218,7 @@ func TestPackageConda(t *testing.T) {
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pv)
assert.NoError(t, err)
- req := NewRequest(t, "GET", fmt.Sprintf("%s/noarch/repodata.json", root))
+ req := NewRequest(t, "GET", root+"/noarch/repodata.json")
resp := MakeRequest(t, req, http.StatusOK)
var result RepoData
diff --git a/tests/integration/api_packages_container_test.go b/tests/integration/api_packages_container_test.go
index 3905ad1b70..204f099bbe 100644
--- a/tests/integration/api_packages_container_test.go
+++ b/tests/integration/api_packages_container_test.go
@@ -7,8 +7,10 @@ import (
"bytes"
"crypto/sha256"
"encoding/base64"
+ "encoding/hex"
"fmt"
"net/http"
+ "strconv"
"strings"
"sync"
"testing"
@@ -16,7 +18,6 @@ import (
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
packages_model "code.gitea.io/gitea/models/packages"
- container_model "code.gitea.io/gitea/models/packages/container"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
container_module "code.gitea.io/gitea/modules/packages/container"
@@ -56,7 +57,7 @@ func TestPackageContainer(t *testing.T) {
return values
}
- images := []string{"test", "te/st"}
+ images := []string{"test", "sub/name"}
tags := []string{"latest", "main"}
multiTag := "multi"
@@ -69,7 +70,8 @@ func TestPackageContainer(t *testing.T) {
configContent := `{"architecture":"amd64","config":{"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/true"],"ArgsEscaped":true,"Image":"sha256:9bd8b88dc68b80cffe126cc820e4b52c6e558eb3b37680bfee8e5f3ed7b8c257"},"container":"b89fe92a887d55c0961f02bdfbfd8ac3ddf66167db374770d2d9e9fab3311510","container_config":{"Hostname":"b89fe92a887d","Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/true\"]"],"ArgsEscaped":true,"Image":"sha256:9bd8b88dc68b80cffe126cc820e4b52c6e558eb3b37680bfee8e5f3ed7b8c257"},"created":"2022-01-01T00:00:00.000000000Z","docker_version":"20.10.12","history":[{"created":"2022-01-01T00:00:00.000000000Z","created_by":"/bin/sh -c #(nop) COPY file:0e7589b0c800daaf6fa460d2677101e4676dd9491980210cb345480e513f3602 in /true "},{"created":"2022-01-01T00:00:00.000000001Z","created_by":"/bin/sh -c #(nop) CMD [\"/true\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:0ff3b91bdf21ecdf2f2f3d4372c2098a14dbe06cd678e8f0a85fd4902d00e2e2"]}}`
manifestDigest := "sha256:4f10484d1c1bb13e3956b4de1cd42db8e0f14a75be1617b60f2de3cd59c803c6"
- manifestContent := `{"schemaVersion":2,"mediaType":"application/vnd.docker.distribution.manifest.v2+json","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d","size":1069},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4","size":32}]}`
+ manifestContent := `{"schemaVersion":2,"mediaType":"` + container_module.ContentTypeDockerDistributionManifestV2 + `","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d","size":1069},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4","size":32}]}`
+ manifestContentType := container_module.ContentTypeDockerDistributionManifestV2
untaggedManifestDigest := "sha256:4305f5f5572b9a426b88909b036e52ee3cf3d7b9c1b01fac840e90747f56623d"
untaggedManifestContent := `{"schemaVersion":2,"mediaType":"` + oci.MediaTypeImageManifest + `","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d","size":1069},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4","size":32}]}`
@@ -92,12 +94,12 @@ func TestPackageContainer(t *testing.T) {
t.Run("Anonymous", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL))
+ req := NewRequest(t, "GET", setting.AppURL+"v2")
resp := MakeRequest(t, req, http.StatusUnauthorized)
assert.ElementsMatch(t, defaultAuthenticateValues, resp.Header().Values("WWW-Authenticate"))
- req = NewRequest(t, "GET", fmt.Sprintf("%sv2/token", setting.AppURL))
+ req = NewRequest(t, "GET", setting.AppURL+"v2/token")
resp = MakeRequest(t, req, http.StatusOK)
tokenResponse := &TokenResponse{}
@@ -105,18 +107,18 @@ func TestPackageContainer(t *testing.T) {
assert.NotEmpty(t, tokenResponse.Token)
- anonymousToken = fmt.Sprintf("Bearer %s", tokenResponse.Token)
+ anonymousToken = "Bearer " + tokenResponse.Token
- req = NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL)).
+ req = NewRequest(t, "GET", setting.AppURL+"v2").
AddTokenAuth(anonymousToken)
MakeRequest(t, req, http.StatusOK)
- defer test.MockVariableValue(&setting.Service.RequireSignInView, true)()
+ defer test.MockVariableValue(&setting.Service.RequireSignInViewStrict, true)()
- req = NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL))
+ req = NewRequest(t, "GET", setting.AppURL+"v2")
MakeRequest(t, req, http.StatusUnauthorized)
- req = NewRequest(t, "GET", fmt.Sprintf("%sv2/token", setting.AppURL))
+ req = NewRequest(t, "GET", setting.AppURL+"v2/token")
MakeRequest(t, req, http.StatusUnauthorized)
defer test.MockVariableValue(&setting.AppURL, "https://domain:8443/sub-path/")()
@@ -129,12 +131,12 @@ func TestPackageContainer(t *testing.T) {
t.Run("UserName/Password", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL))
+ req := NewRequest(t, "GET", setting.AppURL+"v2")
resp := MakeRequest(t, req, http.StatusUnauthorized)
assert.ElementsMatch(t, defaultAuthenticateValues, resp.Header().Values("WWW-Authenticate"))
- req = NewRequest(t, "GET", fmt.Sprintf("%sv2/token", setting.AppURL)).
+ req = NewRequest(t, "GET", setting.AppURL+"v2/token").
AddBasicAuth(user.Name)
resp = MakeRequest(t, req, http.StatusOK)
@@ -147,9 +149,9 @@ func TestPackageContainer(t *testing.T) {
assert.Equal(t, user.ID, pkgMeta.UserID)
assert.Equal(t, auth_model.AccessTokenScopeAll, pkgMeta.Scope)
- userToken = fmt.Sprintf("Bearer %s", tokenResponse.Token)
+ userToken = "Bearer " + tokenResponse.Token
- req = NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL)).
+ req = NewRequest(t, "GET", setting.AppURL+"v2").
AddTokenAuth(userToken)
MakeRequest(t, req, http.StatusOK)
})
@@ -161,23 +163,23 @@ func TestPackageContainer(t *testing.T) {
session := loginUser(t, user.Name)
readToken = getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadPackage)
- req := NewRequest(t, "GET", fmt.Sprintf("%sv2/token", setting.AppURL))
+ req := NewRequest(t, "GET", setting.AppURL+"v2/token")
req.Request.SetBasicAuth(user.Name, readToken)
resp := MakeRequest(t, req, http.StatusOK)
tokenResponse := &TokenResponse{}
DecodeJSON(t, resp, &tokenResponse)
- readToken = fmt.Sprintf("Bearer %s", tokenResponse.Token)
+ readToken = "Bearer " + tokenResponse.Token
badToken = getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadNotification)
- req = NewRequest(t, "GET", fmt.Sprintf("%sv2/token", setting.AppURL))
+ req = NewRequest(t, "GET", setting.AppURL+"v2/token")
req.Request.SetBasicAuth(user.Name, badToken)
MakeRequest(t, req, http.StatusUnauthorized)
testCase := func(scope auth_model.AccessTokenScope, expectedAuthStatus, expectedStatus int) {
token := getTokenForLoggedInUser(t, session, scope)
- req := NewRequest(t, "GET", fmt.Sprintf("%sv2/token", setting.AppURL))
+ req := NewRequest(t, "GET", setting.AppURL+"v2/token")
req.SetBasicAuth(user.Name, token)
resp := MakeRequest(t, req, expectedAuthStatus)
@@ -190,8 +192,8 @@ func TestPackageContainer(t *testing.T) {
assert.NotEmpty(t, tokenResponse.Token)
- req = NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL)).
- AddTokenAuth(fmt.Sprintf("Bearer %s", tokenResponse.Token))
+ req = NewRequest(t, "GET", setting.AppURL+"v2").
+ AddTokenAuth("Bearer " + tokenResponse.Token)
MakeRequest(t, req, expectedStatus)
}
testCase(auth_model.AccessTokenScopeReadPackage, http.StatusOK, http.StatusOK)
@@ -204,17 +206,17 @@ func TestPackageContainer(t *testing.T) {
t.Run("DetermineSupport", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL)).
+ req := NewRequest(t, "GET", setting.AppURL+"v2").
AddTokenAuth(userToken)
resp := MakeRequest(t, req, http.StatusOK)
assert.Equal(t, "registry/2.0", resp.Header().Get("Docker-Distribution-Api-Version"))
- req = NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL)).
+ req = NewRequest(t, "GET", setting.AppURL+"v2").
AddTokenAuth(readToken)
resp = MakeRequest(t, req, http.StatusOK)
assert.Equal(t, "registry/2.0", resp.Header().Get("Docker-Distribution-Api-Version"))
- req = NewRequest(t, "GET", fmt.Sprintf("%sv2", setting.AppURL)).
+ req = NewRequest(t, "GET", setting.AppURL+"v2").
AddTokenAuth(badToken)
MakeRequest(t, req, http.StatusUnauthorized)
})
@@ -226,15 +228,15 @@ func TestPackageContainer(t *testing.T) {
t.Run("UploadBlob/Monolithic", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "POST", fmt.Sprintf("%s/blobs/uploads", url)).
+ req := NewRequest(t, "POST", url+"/blobs/uploads").
AddTokenAuth(anonymousToken)
MakeRequest(t, req, http.StatusUnauthorized)
- req = NewRequest(t, "POST", fmt.Sprintf("%s/blobs/uploads", url)).
+ req = NewRequest(t, "POST", url+"/blobs/uploads").
AddTokenAuth(readToken)
MakeRequest(t, req, http.StatusUnauthorized)
- req = NewRequest(t, "POST", fmt.Sprintf("%s/blobs/uploads", url)).
+ req = NewRequest(t, "POST", url+"/blobs/uploads").
AddTokenAuth(badToken)
MakeRequest(t, req, http.StatusUnauthorized)
@@ -249,7 +251,7 @@ func TestPackageContainer(t *testing.T) {
assert.Equal(t, fmt.Sprintf("/v2/%s/%s/blobs/%s", user.Name, image, blobDigest), resp.Header().Get("Location"))
assert.Equal(t, blobDigest, resp.Header().Get("Docker-Content-Digest"))
- pv, err := packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, container_model.UploadVersion)
+ pv, err := packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, container_module.UploadVersion)
assert.NoError(t, err)
pfs, err := packages_model.GetFilesByVersionID(db.DefaultContext, pv.ID)
@@ -264,15 +266,15 @@ func TestPackageContainer(t *testing.T) {
t.Run("UploadBlob/Chunked", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "POST", fmt.Sprintf("%s/blobs/uploads", url)).
+ req := NewRequest(t, "POST", url+"/blobs/uploads").
AddTokenAuth(readToken)
MakeRequest(t, req, http.StatusUnauthorized)
- req = NewRequest(t, "POST", fmt.Sprintf("%s/blobs/uploads", url)).
+ req = NewRequest(t, "POST", url+"/blobs/uploads").
AddTokenAuth(badToken)
MakeRequest(t, req, http.StatusUnauthorized)
- req = NewRequest(t, "POST", fmt.Sprintf("%s/blobs/uploads", url)).
+ req = NewRequest(t, "POST", url+"/blobs/uploads").
AddTokenAuth(userToken)
resp := MakeRequest(t, req, http.StatusAccepted)
@@ -295,11 +297,22 @@ func TestPackageContainer(t *testing.T) {
SetHeader("Content-Range", "1-10")
MakeRequest(t, req, http.StatusRequestedRangeNotSatisfiable)
- contentRange := fmt.Sprintf("0-%d", len(blobContent)-1)
- req.SetHeader("Content-Range", contentRange)
+ // first patch without Content-Range
+ req = NewRequestWithBody(t, "PATCH", setting.AppURL+uploadURL[1:], bytes.NewReader(blobContent[:1])).
+ AddTokenAuth(userToken)
+ resp = MakeRequest(t, req, http.StatusAccepted)
+ assert.NotEmpty(t, resp.Header().Get("Location"))
+ assert.Equal(t, "0-0", resp.Header().Get("Range"))
+
+ // then send remaining content with Content-Range
+ req = NewRequestWithBody(t, "PATCH", setting.AppURL+uploadURL[1:], bytes.NewReader(blobContent[1:])).
+ SetHeader("Content-Range", fmt.Sprintf("1-%d", len(blobContent)-1)).
+ AddTokenAuth(userToken)
resp = MakeRequest(t, req, http.StatusAccepted)
+ contentRange := fmt.Sprintf("0-%d", len(blobContent)-1)
assert.Equal(t, uuid, resp.Header().Get("Docker-Upload-Uuid"))
+ assert.NotEmpty(t, resp.Header().Get("Location"))
assert.Equal(t, contentRange, resp.Header().Get("Range"))
uploadURL = resp.Header().Get("Location")
@@ -309,7 +322,8 @@ func TestPackageContainer(t *testing.T) {
resp = MakeRequest(t, req, http.StatusNoContent)
assert.Equal(t, uuid, resp.Header().Get("Docker-Upload-Uuid"))
- assert.Equal(t, fmt.Sprintf("0-%d", len(blobContent)), resp.Header().Get("Range"))
+ assert.Equal(t, uploadURL, resp.Header().Get("Location"))
+ assert.Equal(t, contentRange, resp.Header().Get("Range"))
pbu, err = packages_model.GetBlobUploadByID(db.DefaultContext, uuid)
assert.NoError(t, err)
@@ -325,7 +339,7 @@ func TestPackageContainer(t *testing.T) {
t.Run("Cancel", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "POST", fmt.Sprintf("%s/blobs/uploads", url)).
+ req := NewRequest(t, "POST", url+"/blobs/uploads").
AddTokenAuth(userToken)
resp := MakeRequest(t, req, http.StatusAccepted)
@@ -340,7 +354,8 @@ func TestPackageContainer(t *testing.T) {
resp = MakeRequest(t, req, http.StatusNoContent)
assert.Equal(t, uuid, resp.Header().Get("Docker-Upload-Uuid"))
- assert.Equal(t, "0-0", resp.Header().Get("Range"))
+ // FIXME: undefined behavior when the uploaded content is empty: https://github.com/opencontainers/distribution-spec/issues/578
+ assert.Nil(t, resp.Header().Values("Range"))
req = NewRequest(t, "DELETE", setting.AppURL+uploadURL[1:]).
AddTokenAuth(userToken)
@@ -428,7 +443,7 @@ func TestPackageContainer(t *testing.T) {
assert.Len(t, pd.Files, 3)
for _, pfd := range pd.Files {
switch pfd.File.Name {
- case container_model.ManifestFilename:
+ case container_module.ManifestFilename:
assert.True(t, pfd.File.IsLead)
assert.Equal(t, "application/vnd.docker.distribution.manifest.v2+json", pfd.Properties.GetByName(container_module.PropertyMediaType))
assert.Equal(t, manifestDigest, pfd.Properties.GetByName(container_module.PropertyDigest))
@@ -441,7 +456,7 @@ func TestPackageContainer(t *testing.T) {
assert.Equal(t, "application/vnd.docker.image.rootfs.diff.tar.gzip", pfd.Properties.GetByName(container_module.PropertyMediaType))
assert.Equal(t, blobDigest, pfd.Properties.GetByName(container_module.PropertyDigest))
default:
- assert.FailNow(t, "unknown file: %s", pfd.File.Name)
+ assert.FailNow(t, "unknown file", "unknown file: %s", pfd.File.Name)
}
}
@@ -467,7 +482,7 @@ func TestPackageContainer(t *testing.T) {
t.Run("HeadManifest", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "HEAD", fmt.Sprintf("%s/manifests/unknown-tag", url)).
+ req := NewRequest(t, "HEAD", url+"/manifests/unknown-tag").
AddTokenAuth(userToken)
MakeRequest(t, req, http.StatusNotFound)
@@ -475,14 +490,14 @@ func TestPackageContainer(t *testing.T) {
AddTokenAuth(userToken)
resp := MakeRequest(t, req, http.StatusOK)
- assert.Equal(t, fmt.Sprintf("%d", len(manifestContent)), resp.Header().Get("Content-Length"))
+ assert.Equal(t, strconv.Itoa(len(manifestContent)), resp.Header().Get("Content-Length"))
assert.Equal(t, manifestDigest, resp.Header().Get("Docker-Content-Digest"))
})
t.Run("GetManifest", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("%s/manifests/unknown-tag", url)).
+ req := NewRequest(t, "GET", url+"/manifests/unknown-tag").
AddTokenAuth(userToken)
MakeRequest(t, req, http.StatusNotFound)
@@ -490,8 +505,8 @@ func TestPackageContainer(t *testing.T) {
AddTokenAuth(userToken)
resp := MakeRequest(t, req, http.StatusOK)
- assert.Equal(t, fmt.Sprintf("%d", len(manifestContent)), resp.Header().Get("Content-Length"))
- assert.Equal(t, oci.MediaTypeImageManifest, resp.Header().Get("Content-Type"))
+ assert.Equal(t, strconv.Itoa(len(manifestContent)), resp.Header().Get("Content-Length"))
+ assert.Equal(t, manifestContentType, resp.Header().Get("Content-Type"))
assert.Equal(t, manifestDigest, resp.Header().Get("Docker-Content-Digest"))
assert.Equal(t, manifestContent, resp.Body.String())
})
@@ -512,7 +527,7 @@ func TestPackageContainer(t *testing.T) {
AddTokenAuth(userToken)
resp = MakeRequest(t, req, http.StatusOK)
- assert.Equal(t, fmt.Sprintf("%d", len(untaggedManifestContent)), resp.Header().Get("Content-Length"))
+ assert.Equal(t, strconv.Itoa(len(untaggedManifestContent)), resp.Header().Get("Content-Length"))
assert.Equal(t, untaggedManifestDigest, resp.Header().Get("Docker-Content-Digest"))
pv, err := packages_model.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, untaggedManifestDigest)
@@ -530,7 +545,7 @@ func TestPackageContainer(t *testing.T) {
assert.Len(t, pd.Files, 3)
for _, pfd := range pd.Files {
- if pfd.File.Name == container_model.ManifestFilename {
+ if pfd.File.Name == container_module.ManifestFilename {
assert.True(t, pfd.File.IsLead)
assert.Equal(t, oci.MediaTypeImageManifest, pfd.Properties.GetByName(container_module.PropertyMediaType))
assert.Equal(t, untaggedManifestDigest, pfd.Properties.GetByName(container_module.PropertyDigest))
@@ -598,7 +613,7 @@ func TestPackageContainer(t *testing.T) {
AddTokenAuth(userToken)
resp := MakeRequest(t, req, http.StatusOK)
- assert.Equal(t, fmt.Sprintf("%d", len(blobContent)), resp.Header().Get("Content-Length"))
+ assert.Equal(t, strconv.Itoa(len(blobContent)), resp.Header().Get("Content-Length"))
assert.Equal(t, blobDigest, resp.Header().Get("Docker-Content-Digest"))
req = NewRequest(t, "HEAD", fmt.Sprintf("%s/blobs/%s", url, blobDigest)).
@@ -617,11 +632,27 @@ func TestPackageContainer(t *testing.T) {
AddTokenAuth(userToken)
resp := MakeRequest(t, req, http.StatusOK)
- assert.Equal(t, fmt.Sprintf("%d", len(blobContent)), resp.Header().Get("Content-Length"))
+ assert.Equal(t, strconv.Itoa(len(blobContent)), resp.Header().Get("Content-Length"))
assert.Equal(t, blobDigest, resp.Header().Get("Docker-Content-Digest"))
assert.Equal(t, blobContent, resp.Body.Bytes())
})
+ t.Run("GetBlob/Empty", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+ emptyDigestBuf := sha256.Sum256(nil)
+ emptyDigest := "sha256:" + hex.EncodeToString(emptyDigestBuf[:])
+ req := NewRequestWithBody(t, "POST", fmt.Sprintf("%s/blobs/uploads?digest=%s", url, emptyDigest), strings.NewReader("")).AddTokenAuth(userToken)
+ MakeRequest(t, req, http.StatusCreated)
+
+ req = NewRequest(t, "HEAD", fmt.Sprintf("%s/blobs/%s", url, emptyDigest)).AddTokenAuth(userToken)
+ resp := MakeRequest(t, req, http.StatusOK)
+ assert.Equal(t, "0", resp.Header().Get("Content-Length"))
+
+ req = NewRequest(t, "GET", fmt.Sprintf("%s/blobs/%s", url, emptyDigest)).AddTokenAuth(userToken)
+ resp = MakeRequest(t, req, http.StatusOK)
+ assert.Equal(t, "0", resp.Header().Get("Content-Length"))
+ })
+
t.Run("GetTagList", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
@@ -631,27 +662,27 @@ func TestPackageContainer(t *testing.T) {
ExpectedLink string
}{
{
- URL: fmt.Sprintf("%s/tags/list", url),
+ URL: url + "/tags/list",
ExpectedTags: []string{"latest", "main", "multi"},
ExpectedLink: fmt.Sprintf(`</v2/%s/%s/tags/list?last=multi>; rel="next"`, user.Name, image),
},
{
- URL: fmt.Sprintf("%s/tags/list?n=0", url),
+ URL: url + "/tags/list?n=0",
ExpectedTags: []string{},
ExpectedLink: "",
},
{
- URL: fmt.Sprintf("%s/tags/list?n=2", url),
+ URL: url + "/tags/list?n=2",
ExpectedTags: []string{"latest", "main"},
ExpectedLink: fmt.Sprintf(`</v2/%s/%s/tags/list?last=main&n=2>; rel="next"`, user.Name, image),
},
{
- URL: fmt.Sprintf("%s/tags/list?last=main", url),
+ URL: url + "/tags/list?last=main",
ExpectedTags: []string{"multi"},
ExpectedLink: fmt.Sprintf(`</v2/%s/%s/tags/list?last=multi>; rel="next"`, user.Name, image),
},
{
- URL: fmt.Sprintf("%s/tags/list?n=1&last=latest", url),
+ URL: url + "/tags/list?n=1&last=latest",
ExpectedTags: []string{"main"},
ExpectedLink: fmt.Sprintf(`</v2/%s/%s/tags/list?last=main&n=1>; rel="next"`, user.Name, image),
},
@@ -731,7 +762,7 @@ func TestPackageContainer(t *testing.T) {
url := fmt.Sprintf("%sv2/%s/parallel", setting.AppURL, user.Name)
var wg sync.WaitGroup
- for i := 0; i < 10; i++ {
+ for i := range 10 {
wg.Add(1)
content := []byte{byte(i)}
@@ -757,7 +788,7 @@ func TestPackageContainer(t *testing.T) {
return func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("%sv2/_catalog", setting.AppURL)).
+ req := NewRequest(t, "GET", setting.AppURL+"v2/_catalog").
AddTokenAuth(userToken)
resp := MakeRequest(t, req, http.StatusOK)
diff --git a/tests/integration/api_packages_cran_test.go b/tests/integration/api_packages_cran_test.go
index 667ba0908c..bd4a99f331 100644
--- a/tests/integration/api_packages_cran_test.go
+++ b/tests/integration/api_packages_cran_test.go
@@ -133,8 +133,8 @@ func TestPackageCran(t *testing.T) {
assert.Contains(t, resp.Header().Get("Content-Type"), "text/plain")
body := resp.Body.String()
- assert.Contains(t, body, fmt.Sprintf("Package: %s", packageName))
- assert.Contains(t, body, fmt.Sprintf("Version: %s", packageVersion))
+ assert.Contains(t, body, "Package: "+packageName)
+ assert.Contains(t, body, "Version: "+packageVersion)
req = NewRequest(t, "GET", url+"/src/contrib/PACKAGES.gz").
AddBasicAuth(user.Name)
@@ -230,8 +230,8 @@ func TestPackageCran(t *testing.T) {
assert.Contains(t, resp.Header().Get("Content-Type"), "text/plain")
body := resp.Body.String()
- assert.Contains(t, body, fmt.Sprintf("Package: %s", packageName))
- assert.Contains(t, body, fmt.Sprintf("Version: %s", packageVersion))
+ assert.Contains(t, body, "Package: "+packageName)
+ assert.Contains(t, body, "Version: "+packageVersion)
req = NewRequest(t, "GET", url+"/bin/windows/contrib/4.2/PACKAGES.gz").
AddBasicAuth(user.Name)
diff --git a/tests/integration/api_packages_debian_test.go b/tests/integration/api_packages_debian_test.go
index 98027d774c..3ae60d2aa2 100644
--- a/tests/integration/api_packages_debian_test.go
+++ b/tests/integration/api_packages_debian_test.go
@@ -284,7 +284,7 @@ func TestPackageDebian(t *testing.T) {
// because "Iterate" keeps a dangling SQL session but the callback function still uses the same session to execute statements.
// The "Iterate" problem has been checked by TestContextSafety now, so here we only need to check the cleanup logic with a small number
packagesCount := 2
- for i := 0; i < packagesCount; i++ {
+ for i := range packagesCount {
uploadURL := fmt.Sprintf("%s/pool/%s/%s/upload", rootURL, "test", "main")
req := NewRequestWithBody(t, "PUT", uploadURL, createArchive(packageName, "1.0."+strconv.Itoa(i), "all")).AddBasicAuth(user.Name)
MakeRequest(t, req, http.StatusCreated)
diff --git a/tests/integration/api_packages_generic_test.go b/tests/integration/api_packages_generic_test.go
index baa8dd66c8..94e2c6072c 100644
--- a/tests/integration/api_packages_generic_test.go
+++ b/tests/integration/api_packages_generic_test.go
@@ -15,6 +15,7 @@ import (
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
@@ -131,11 +132,7 @@ func TestPackageGeneric(t *testing.T) {
t.Run("RequireSignInView", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
-
- setting.Service.RequireSignInView = true
- defer func() {
- setting.Service.RequireSignInView = false
- }()
+ defer test.MockVariableValue(&setting.Service.RequireSignInViewStrict, true)()
req = NewRequest(t, "GET", url+"/dummy.bin")
MakeRequest(t, req, http.StatusUnauthorized)
@@ -144,37 +141,25 @@ func TestPackageGeneric(t *testing.T) {
t.Run("ServeDirect", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- if setting.Packages.Storage.Type != setting.MinioStorageType && setting.Packages.Storage.Type != setting.AzureBlobStorageType {
- t.Skip("Test skipped for non-Minio-storage and non-AzureBlob-storage.")
- return
- }
-
if setting.Packages.Storage.Type == setting.MinioStorageType {
- if !setting.Packages.Storage.MinioConfig.ServeDirect {
- old := setting.Packages.Storage.MinioConfig.ServeDirect
- defer func() {
- setting.Packages.Storage.MinioConfig.ServeDirect = old
- }()
-
- setting.Packages.Storage.MinioConfig.ServeDirect = true
- }
+ defer test.MockVariableValue(&setting.Packages.Storage.MinioConfig.ServeDirect, true)()
} else if setting.Packages.Storage.Type == setting.AzureBlobStorageType {
- if !setting.Packages.Storage.AzureBlobConfig.ServeDirect {
- old := setting.Packages.Storage.AzureBlobConfig.ServeDirect
- defer func() {
- setting.Packages.Storage.AzureBlobConfig.ServeDirect = old
- }()
-
- setting.Packages.Storage.AzureBlobConfig.ServeDirect = true
- }
+ defer test.MockVariableValue(&setting.Packages.Storage.AzureBlobConfig.ServeDirect, true)()
+ } else {
+ t.Skip("Test skipped for non-Minio-storage and non-AzureBlob-storage.")
}
- req := NewRequest(t, "GET", url+"/"+filename)
- resp := MakeRequest(t, req, http.StatusSeeOther)
+ req = NewRequest(t, "HEAD", url+"/"+filename)
+ resp = MakeRequest(t, req, http.StatusSeeOther)
+ location := resp.Header().Get("Location")
+ assert.NotEmpty(t, location)
+ checkDownloadCount(2)
+ req = NewRequest(t, "GET", url+"/"+filename)
+ resp = MakeRequest(t, req, http.StatusSeeOther)
checkDownloadCount(3)
- location := resp.Header().Get("Location")
+ location = resp.Header().Get("Location")
assert.NotEmpty(t, location)
resp2, err := (&http.Client{}).Get(location)
diff --git a/tests/integration/api_packages_goproxy_test.go b/tests/integration/api_packages_goproxy_test.go
index dab9fefc5e..fa0ee5b901 100644
--- a/tests/integration/api_packages_goproxy_test.go
+++ b/tests/integration/api_packages_goproxy_test.go
@@ -87,7 +87,7 @@ func TestPackageGo(t *testing.T) {
AddBasicAuth(user.Name)
MakeRequest(t, req, http.StatusConflict)
- time.Sleep(time.Second)
+ time.Sleep(time.Second) // Ensure the timestamp is different, then the "list" below can have stable order
content = createArchive(map[string][]byte{
packageName + "@" + packageVersion2 + "/go.mod": []byte(goModContent),
diff --git a/tests/integration/api_packages_helm_test.go b/tests/integration/api_packages_helm_test.go
index 76285add11..8f5c6ac571 100644
--- a/tests/integration/api_packages_helm_test.go
+++ b/tests/integration/api_packages_helm_test.go
@@ -52,7 +52,7 @@ dependencies:
zw := gzip.NewWriter(&buf)
archive := tar.NewWriter(zw)
archive.WriteHeader(&tar.Header{
- Name: fmt.Sprintf("%s/Chart.yaml", packageName),
+ Name: packageName + "/Chart.yaml",
Mode: 0o600,
Size: int64(len(chartContent)),
})
@@ -122,7 +122,7 @@ dependencies:
t.Run("Index", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("%s/index.yaml", url)).
+ req := NewRequest(t, "GET", url+"/index.yaml").
AddBasicAuth(user.Name)
resp := MakeRequest(t, req, http.StatusOK)
diff --git a/tests/integration/api_packages_maven_test.go b/tests/integration/api_packages_maven_test.go
index e54238858c..30ef1884cd 100644
--- a/tests/integration/api_packages_maven_test.go
+++ b/tests/integration/api_packages_maven_test.go
@@ -6,6 +6,7 @@ package integration
import (
"fmt"
"net/http"
+ "net/url"
"strconv"
"strings"
"sync"
@@ -20,6 +21,7 @@ import (
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func TestPackageMaven(t *testing.T) {
@@ -29,16 +31,14 @@ func TestPackageMaven(t *testing.T) {
groupID := "com.gitea"
artifactID := "test-project"
- packageName := groupID + "-" + artifactID
packageVersion := "1.0.1"
packageDescription := "Test Description"
- root := fmt.Sprintf("/api/packages/%s/maven/%s/%s", user.Name, strings.ReplaceAll(groupID, ".", "/"), artifactID)
- filename := fmt.Sprintf("%s-%s.jar", packageName, packageVersion)
+ root := "/api/packages/user2/maven/com/gitea/test-project"
+ filename := "any-name.jar"
putFile := func(t *testing.T, path, content string, expectedStatus int) {
- req := NewRequestWithBody(t, "PUT", root+path, strings.NewReader(content)).
- AddBasicAuth(user.Name)
+ req := NewRequestWithBody(t, "PUT", root+path, strings.NewReader(content)).AddBasicAuth(user.Name)
MakeRequest(t, req, expectedStatus)
}
@@ -56,27 +56,81 @@ func TestPackageMaven(t *testing.T) {
putFile(t, "/maven-metadata.xml", "test", http.StatusOK)
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
- assert.NoError(t, err)
+ require.NoError(t, err)
assert.Len(t, pvs, 1)
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
- assert.NoError(t, err)
+ require.NoError(t, err)
assert.Nil(t, pd.SemVer)
assert.Nil(t, pd.Metadata)
- assert.Equal(t, packageName, pd.Package.Name)
+ assert.Equal(t, groupID+":"+artifactID, pd.Package.Name)
assert.Equal(t, packageVersion, pd.Version.Version)
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
- assert.NoError(t, err)
+ require.NoError(t, err)
assert.Len(t, pfs, 1)
assert.Equal(t, filename, pfs[0].Name)
assert.False(t, pfs[0].IsLead)
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
- assert.NoError(t, err)
+ require.NoError(t, err)
assert.Equal(t, int64(4), pb.Size)
})
+ t.Run("UploadLegacy", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ // try to upload a package with legacy package name (will be saved as "GroupID-ArtifactID")
+ legacyRootLink := "/api/packages/user2/maven/com/gitea/legacy-project"
+ req := NewRequestWithBody(t, "PUT", legacyRootLink+"/1.0.2/any-file-name?use_legacy_package_name=1", strings.NewReader("test-content")).AddBasicAuth(user.Name)
+ MakeRequest(t, req, http.StatusCreated)
+ p, err := packages.GetPackageByName(db.DefaultContext, user.ID, packages.TypeMaven, "com.gitea-legacy-project")
+ require.NoError(t, err)
+ assert.Equal(t, "com.gitea-legacy-project", p.Name)
+
+ req = NewRequest(t, "HEAD", legacyRootLink+"/1.0.2/any-file-name").AddBasicAuth(user.Name)
+ MakeRequest(t, req, http.StatusOK)
+
+ req = NewRequest(t, "GET", "/user2/-/packages/maven/com.gitea-legacy-project/1.0.2")
+ MakeRequest(t, req, http.StatusOK)
+ req = NewRequest(t, "GET", "/user2/-/packages/maven/com.gitea:legacy-project/1.0.2")
+ MakeRequest(t, req, http.StatusNotFound)
+ req = NewRequest(t, "GET", "/user2/-/packages/maven/com.gitea%3Alegacy-project/1.0.2")
+ MakeRequest(t, req, http.StatusNotFound)
+
+ // legacy package names should also be able to be listed
+ req = NewRequest(t, "GET", legacyRootLink+"/maven-metadata.xml").AddBasicAuth(user.Name)
+ resp := MakeRequest(t, req, http.StatusOK)
+ respBody := resp.Body.String()
+ assert.Contains(t, respBody, "<version>1.0.2</version>")
+
+ // then upload a package with correct package name (will be saved as "GroupID:ArtifactID")
+ req = NewRequestWithBody(t, "PUT", legacyRootLink+"/1.0.3/any-file-name", strings.NewReader("test-content")).AddBasicAuth(user.Name)
+ MakeRequest(t, req, http.StatusCreated)
+ _, err = packages.GetPackageByName(db.DefaultContext, user.ID, packages.TypeMaven, "com.gitea-legacy-project")
+ require.ErrorIs(t, err, packages.ErrPackageNotExist)
+ p, err = packages.GetPackageByName(db.DefaultContext, user.ID, packages.TypeMaven, "com.gitea:legacy-project")
+ require.NoError(t, err)
+ assert.Equal(t, "com.gitea:legacy-project", p.Name)
+ req = NewRequest(t, "HEAD", legacyRootLink+"/1.0.2/any-file-name").AddBasicAuth(user.Name)
+ MakeRequest(t, req, http.StatusOK)
+
+ req = NewRequest(t, "GET", "/user2/-/packages/maven/com.gitea-legacy-project/1.0.2")
+ MakeRequest(t, req, http.StatusNotFound)
+ req = NewRequest(t, "GET", "/user2/-/packages/maven/com.gitea:legacy-project/1.0.2")
+ MakeRequest(t, req, http.StatusOK)
+ req = NewRequest(t, "GET", "/user2/-/packages/maven/com.gitea%3Alegacy-project/1.0.2")
+ MakeRequest(t, req, http.StatusOK)
+
+ // now 2 packages should be listed
+ req = NewRequest(t, "GET", legacyRootLink+"/maven-metadata.xml").AddBasicAuth(user.Name)
+ resp = MakeRequest(t, req, http.StatusOK)
+ respBody = resp.Body.String()
+ assert.Contains(t, respBody, "<version>1.0.2</version>")
+ assert.Contains(t, respBody, "<version>1.0.3</version>")
+ require.NoError(t, packages.DeletePackageByID(db.DefaultContext, p.ID))
+ })
+
t.Run("UploadExists", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
@@ -86,14 +140,12 @@ func TestPackageMaven(t *testing.T) {
t.Run("Download", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "HEAD", fmt.Sprintf("%s/%s/%s", root, packageVersion, filename)).
- AddBasicAuth(user.Name)
+ req := NewRequest(t, "HEAD", fmt.Sprintf("%s/%s/%s", root, packageVersion, filename)).AddBasicAuth(user.Name)
resp := MakeRequest(t, req, http.StatusOK)
checkHeaders(t, resp.Header(), "application/java-archive", 4)
- req = NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s", root, packageVersion, filename)).
- AddBasicAuth(user.Name)
+ req = NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s", root, packageVersion, filename)).AddBasicAuth(user.Name)
resp = MakeRequest(t, req, http.StatusOK)
checkHeaders(t, resp.Header(), "application/java-archive", 4)
@@ -101,7 +153,7 @@ func TestPackageMaven(t *testing.T) {
assert.Equal(t, []byte("test"), resp.Body.Bytes())
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
- assert.NoError(t, err)
+ require.NoError(t, err)
assert.Len(t, pvs, 1)
assert.Equal(t, int64(0), pvs[0].DownloadCount)
})
@@ -133,26 +185,26 @@ func TestPackageMaven(t *testing.T) {
defer tests.PrintCurrentTest(t)()
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
- assert.NoError(t, err)
+ require.NoError(t, err)
assert.Len(t, pvs, 1)
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
- assert.NoError(t, err)
+ require.NoError(t, err)
assert.Nil(t, pd.Metadata)
putFile(t, fmt.Sprintf("/%s/%s.pom", packageVersion, filename), pomContent, http.StatusCreated)
pvs, err = packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
- assert.NoError(t, err)
+ require.NoError(t, err)
assert.Len(t, pvs, 1)
pd, err = packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
- assert.NoError(t, err)
+ require.NoError(t, err)
assert.IsType(t, &maven.Metadata{}, pd.Metadata)
assert.Equal(t, packageDescription, pd.Metadata.(*maven.Metadata).Description)
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
- assert.NoError(t, err)
+ require.NoError(t, err)
assert.Len(t, pfs, 2)
for _, pf := range pfs {
if strings.HasSuffix(pf.Name, ".pom") {
@@ -167,14 +219,12 @@ func TestPackageMaven(t *testing.T) {
t.Run("DownloadPOM", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "HEAD", fmt.Sprintf("%s/%s/%s.pom", root, packageVersion, filename)).
- AddBasicAuth(user.Name)
+ req := NewRequest(t, "HEAD", fmt.Sprintf("%s/%s/%s.pom", root, packageVersion, filename)).AddBasicAuth(user.Name)
resp := MakeRequest(t, req, http.StatusOK)
checkHeaders(t, resp.Header(), "text/xml", int64(len(pomContent)))
- req = NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s.pom", root, packageVersion, filename)).
- AddBasicAuth(user.Name)
+ req = NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s.pom", root, packageVersion, filename)).AddBasicAuth(user.Name)
resp = MakeRequest(t, req, http.StatusOK)
checkHeaders(t, resp.Header(), "text/xml", int64(len(pomContent)))
@@ -182,7 +232,7 @@ func TestPackageMaven(t *testing.T) {
assert.Equal(t, []byte(pomContent), resp.Body.Bytes())
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
- assert.NoError(t, err)
+ require.NoError(t, err)
assert.Len(t, pvs, 1)
assert.Equal(t, int64(1), pvs[0].DownloadCount)
})
@@ -190,8 +240,7 @@ func TestPackageMaven(t *testing.T) {
t.Run("DownloadChecksums", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("%s/1.2.3/%s", root, filename)).
- AddBasicAuth(user.Name)
+ req := NewRequest(t, "GET", fmt.Sprintf("%s/1.2.3/%s", root, filename)).AddBasicAuth(user.Name)
MakeRequest(t, req, http.StatusNotFound)
for key, checksum := range map[string]string{
@@ -200,8 +249,7 @@ func TestPackageMaven(t *testing.T) {
"sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
"sha512": "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff",
} {
- req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s.%s", root, packageVersion, filename, key)).
- AddBasicAuth(user.Name)
+ req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s.%s", root, packageVersion, filename, key)).AddBasicAuth(user.Name)
resp := MakeRequest(t, req, http.StatusOK)
assert.Equal(t, checksum, resp.Body.String())
@@ -211,8 +259,7 @@ func TestPackageMaven(t *testing.T) {
t.Run("DownloadMetadata", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", root+"/maven-metadata.xml").
- AddBasicAuth(user.Name)
+ req := NewRequest(t, "GET", root+"/maven-metadata.xml").AddBasicAuth(user.Name)
resp := MakeRequest(t, req, http.StatusOK)
expectedMetadata := `<?xml version="1.0" encoding="UTF-8"?>` + "\n<metadata><groupId>com.gitea</groupId><artifactId>test-project</artifactId><versioning><release>1.0.1</release><latest>1.0.1</latest><versions><version>1.0.1</version></versions></versioning></metadata>"
@@ -227,8 +274,7 @@ func TestPackageMaven(t *testing.T) {
"sha256": "3f48322f81c4b2c3bb8649ae1e5c9801476162b520e1c2734ac06b2c06143208",
"sha512": "cb075aa2e2ef1a83cdc14dd1e08c505b72d633399b39e73a21f00f0deecb39a3e2c79f157c1163f8a3854828750706e0dec3a0f5e4778e91f8ec2cf351a855f2",
} {
- req := NewRequest(t, "GET", fmt.Sprintf("%s/maven-metadata.xml.%s", root, key)).
- AddBasicAuth(user.Name)
+ req := NewRequest(t, "GET", fmt.Sprintf("%s/maven-metadata.xml.%s", root, key)).AddBasicAuth(user.Name)
resp := MakeRequest(t, req, http.StatusOK)
assert.Equal(t, checksum, resp.Body.String())
@@ -245,9 +291,10 @@ func TestPackageMaven(t *testing.T) {
})
t.Run("InvalidFile", func(t *testing.T) {
- ver := packageVersion + "-invalid"
- putFile(t, fmt.Sprintf("/%s/%s", ver, filename), "any invalid content", http.StatusCreated)
- req := NewRequestf(t, "GET", "/%s/-/packages/maven/%s-%s/%s", user.Name, groupID, artifactID, ver)
+ invalidVersion := packageVersion + "-invalid"
+ putFile(t, fmt.Sprintf("/%s/%s", invalidVersion, filename), "any invalid content", http.StatusCreated)
+
+ req := NewRequestf(t, "GET", "/%s/-/packages/maven/%s/%s", user.Name, url.QueryEscape(groupID+":"+artifactID), invalidVersion)
resp := MakeRequest(t, req, http.StatusOK)
assert.Contains(t, resp.Body.String(), "No metadata.")
assert.True(t, test.IsNormalPageCompleted(resp.Body.String()))
@@ -266,8 +313,7 @@ func TestPackageMavenConcurrent(t *testing.T) {
root := fmt.Sprintf("/api/packages/%s/maven/%s/%s", user.Name, strings.ReplaceAll(groupID, ".", "/"), artifactID)
putFile := func(t *testing.T, path, content string, expectedStatus int) {
- req := NewRequestWithBody(t, "PUT", root+path, strings.NewReader(content)).
- AddBasicAuth(user.Name)
+ req := NewRequestWithBody(t, "PUT", root+path, strings.NewReader(content)).AddBasicAuth(user.Name)
MakeRequest(t, req, expectedStatus)
}
@@ -275,7 +321,7 @@ func TestPackageMavenConcurrent(t *testing.T) {
defer tests.PrintCurrentTest(t)()
var wg sync.WaitGroup
- for i := 0; i < 10; i++ {
+ for i := range 10 {
wg.Add(1)
go func(i int) {
putFile(t, fmt.Sprintf("/%s/%s.jar", packageVersion, strconv.Itoa(i)), "test", http.StatusCreated)
diff --git a/tests/integration/api_packages_npm_test.go b/tests/integration/api_packages_npm_test.go
index b9660aeeb9..a190ed679d 100644
--- a/tests/integration/api_packages_npm_test.go
+++ b/tests/integration/api_packages_npm_test.go
@@ -28,7 +28,7 @@ func TestPackageNpm(t *testing.T) {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
- token := fmt.Sprintf("Bearer %s", getTokenForLoggedInUser(t, loginUser(t, user.Name), auth_model.AccessTokenScopeWritePackage))
+ token := "Bearer " + getTokenForLoggedInUser(t, loginUser(t, user.Name), auth_model.AccessTokenScopeWritePackage)
packageName := "@scope/test-package"
packageVersion := "1.0.1-pre"
@@ -52,24 +52,33 @@ func TestPackageNpm(t *testing.T) {
"` + packageTag + `": "` + version + `"
},
"versions": {
- "` + version + `": {
- "name": "` + packageName + `",
- "version": "` + version + `",
- "description": "` + packageDescription + `",
- "author": {
- "name": "` + packageAuthor + `"
- },
- "bin": {
- "` + packageBinName + `": "` + packageBinPath + `"
- },
- "dist": {
- "integrity": "sha512-yA4FJsVhetynGfOC1jFf79BuS+jrHbm0fhh+aHzCQkOaOBXKf9oBnC4a6DnLLnEsHQDRLYd00cwj8sCXpC+wIg==",
- "shasum": "aaa7eaf852a948b0aa05afeda35b1badca155d90"
- },
- "repository": {
- "type": "` + repoType + `",
- "url": "` + repoURL + `"
- }
+ "` + version + `": {
+ "name": "` + packageName + `",
+ "version": "` + version + `",
+ "description": "` + packageDescription + `",
+ "author": {
+ "name": "` + packageAuthor + `"
+ },
+ "bin": {
+ "` + packageBinName + `": "` + packageBinPath + `"
+ },
+ "dist": {
+ "integrity": "sha512-yA4FJsVhetynGfOC1jFf79BuS+jrHbm0fhh+aHzCQkOaOBXKf9oBnC4a6DnLLnEsHQDRLYd00cwj8sCXpC+wIg==",
+ "shasum": "aaa7eaf852a948b0aa05afeda35b1badca155d90"
+ },
+ "repository": {
+ "type": "` + repoType + `",
+ "url": "` + repoURL + `"
+ },
+ "peerDependencies": {
+ "tea": "2.x",
+ "soy-milk": "1.2"
+ },
+ "peerDependenciesMeta": {
+ "soy-milk": {
+ "optional": true
+ }
+ }
}
},
"_attachments": {
@@ -178,6 +187,8 @@ func TestPackageNpm(t *testing.T) {
assert.Equal(t, fmt.Sprintf("%s%s/-/%s/%s", setting.AppURL, root[1:], packageVersion, filename), pmv.Dist.Tarball)
assert.Equal(t, repoType, result.Repository.Type)
assert.Equal(t, repoURL, result.Repository.URL)
+ assert.Equal(t, map[string]string{"tea": "2.x", "soy-milk": "1.2"}, pmv.PeerDependencies)
+ assert.Equal(t, map[string]any{"soy-milk": map[string]any{"optional": true}}, pmv.PeerDependenciesMeta)
})
t.Run("AddTag", func(t *testing.T) {
diff --git a/tests/integration/api_packages_nuget_test.go b/tests/integration/api_packages_nuget_test.go
index 622c2c4394..529b540062 100644
--- a/tests/integration/api_packages_nuget_test.go
+++ b/tests/integration/api_packages_nuget_test.go
@@ -14,6 +14,7 @@ import (
"net/http/httptest"
neturl "net/url"
"strconv"
+ "strings"
"testing"
"time"
@@ -46,21 +47,30 @@ func TestPackageNuGet(t *testing.T) {
defer tests.PrepareTestEnv(t)()
type FeedEntryProperties struct {
- Version string `xml:"Version"`
- NormalizedVersion string `xml:"NormalizedVersion"`
Authors string `xml:"Authors"`
+ Copyright string `xml:"Copyright,omitempty"`
+ Created nuget.TypedValue[time.Time] `xml:"Created"`
Dependencies string `xml:"Dependencies"`
Description string `xml:"Description"`
- VersionDownloadCount nuget.TypedValue[int64] `xml:"VersionDownloadCount"`
+ DevelopmentDependency nuget.TypedValue[bool] `xml:"DevelopmentDependency"`
DownloadCount nuget.TypedValue[int64] `xml:"DownloadCount"`
- PackageSize nuget.TypedValue[int64] `xml:"PackageSize"`
- Created nuget.TypedValue[time.Time] `xml:"Created"`
+ ID string `xml:"Id"`
+ IconURL string `xml:"IconUrl,omitempty"`
+ Language string `xml:"Language,omitempty"`
LastUpdated nuget.TypedValue[time.Time] `xml:"LastUpdated"`
- Published nuget.TypedValue[time.Time] `xml:"Published"`
+ LicenseURL string `xml:"LicenseUrl,omitempty"`
+ MinClientVersion string `xml:"MinClientVersion,omitempty"`
+ NormalizedVersion string `xml:"NormalizedVersion"`
+ Owners string `xml:"Owners,omitempty"`
+ PackageSize nuget.TypedValue[int64] `xml:"PackageSize"`
ProjectURL string `xml:"ProjectUrl,omitempty"`
+ Published nuget.TypedValue[time.Time] `xml:"Published"`
ReleaseNotes string `xml:"ReleaseNotes,omitempty"`
RequireLicenseAcceptance nuget.TypedValue[bool] `xml:"RequireLicenseAcceptance"`
+ Tags string `xml:"Tags,omitempty"`
Title string `xml:"Title"`
+ Version string `xml:"Version"`
+ VersionDownloadCount nuget.TypedValue[int64] `xml:"VersionDownloadCount"`
}
type FeedEntry struct {
@@ -86,28 +96,62 @@ func TestPackageNuGet(t *testing.T) {
readToken := getUserToken(t, user.Name, auth_model.AccessTokenScopeReadPackage)
badToken := getUserToken(t, user.Name, auth_model.AccessTokenScopeReadNotification)
- packageName := "test.package"
+ packageName := "test.package" // id
+ packageID := packageName
packageVersion := "1.0.3"
packageAuthors := "KN4CK3R"
packageDescription := "Gitea Test Package"
+ isPrerelease := strings.Contains(packageVersion, "-")
+
symbolFilename := "test.pdb"
symbolID := "d910bb6948bd4c6cb40155bcf52c3c94"
+ packageCopyright := "Package Copyright"
+ packageIconURL := "https://gitea.io/favicon.png"
+ packageLanguage := "Package Language"
+ packageLicenseURL := "https://gitea.io/license"
+ packageMinClientVersion := "1.0.0.0"
+ packageOwners := "Package Owners"
+ packageProjectURL := "https://gitea.io"
+ packageReleaseNotes := "Package Release Notes"
+ summary := "This is a test package."
+ packageTags := "tag_1 tag_2 tag_3"
+ packageTitle := "Package Title"
+ packageDevelopmentDependency := true
+ packageRequireLicenseAcceptance := true
+
+ dependencyCount := 1
+ dependencyTargetFramework := ".NETStandard2.0"
+ dependencyID := "Microsoft.CSharp"
+ dependencyVersion := "4.5.0"
+
createNuspec := func(id, version string) string {
return `<?xml version="1.0" encoding="utf-8"?>
-<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
- <metadata>
- <id>` + id + `</id>
- <version>` + version + `</version>
- <authors>` + packageAuthors + `</authors>
- <description>` + packageDescription + `</description>
- <dependencies>
- <group targetFramework=".NETStandard2.0">
- <dependency id="Microsoft.CSharp" version="4.5.0" />
- </group>
- </dependencies>
- </metadata>
-</package>`
+ <package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
+ <metadata minClientVersion="` + packageMinClientVersion + `">
+ <authors>` + packageAuthors + `</authors>
+ <copyright>` + packageCopyright + `</copyright>
+ <description>` + packageDescription + `</description>
+ <developmentDependency>true</developmentDependency>
+ <iconUrl>` + packageIconURL + `</iconUrl>
+ <id>` + id + `</id>
+ <language>` + packageLanguage + `</language>
+ <licenseUrl>` + packageLicenseURL + `</licenseUrl>
+ <owners>` + packageOwners + `</owners>
+ <projectUrl>` + packageProjectURL + `</projectUrl>
+ <releaseNotes>` + packageReleaseNotes + `</releaseNotes>
+ <requireLicenseAcceptance>true</requireLicenseAcceptance>
+ <summary>` + summary + `</summary>
+ <tags>` + packageTags + `</tags>
+ <title>` + packageTitle + `</title>
+ <version>` + version + `</version>
+ <dependencies>
+ <group targetFramework="` + dependencyTargetFramework + `">
+ <dependency id="` + dependencyID + `" version="` + dependencyVersion + `" />
+ </group>
+ </dependencies>
+ </metadata>
+ </package>`
}
createPackage := func(id, version string) *bytes.Buffer {
@@ -198,7 +242,7 @@ func TestPackageNuGet(t *testing.T) {
t.Run(c.Owner, func(t *testing.T) {
url := fmt.Sprintf("/api/packages/%s/nuget", c.Owner)
- req := NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
+ req := NewRequest(t, "GET", url+"/index.json")
if c.UseBasicAuth {
req.AddBasicAuth(user.Name)
} else if c.token != "" {
@@ -273,10 +317,10 @@ func TestPackageNuGet(t *testing.T) {
pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID)
assert.NoError(t, err)
assert.Equal(t, int64(len(content)), pb.Size)
- case fmt.Sprintf("%s.nuspec", packageName):
+ case packageName + ".nuspec":
assert.False(t, pf.IsLead)
default:
- assert.Fail(t, "unexpected filename: %v", pf.Name)
+ assert.Fail(t, "unexpected filename", "unexpected filename: %v", pf.Name)
}
}
@@ -319,10 +363,10 @@ func TestPackageNuGet(t *testing.T) {
pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID)
assert.NoError(t, err)
assert.Equal(t, int64(len(content)), pb.Size)
- case fmt.Sprintf("%s.nuspec", packageName):
+ case packageName + ".nuspec":
assert.False(t, pf.IsLead)
default:
- assert.Fail(t, "unexpected filename: %v", pf.Name)
+ assert.Fail(t, "unexpected filename", "unexpected filename: %v", pf.Name)
}
}
@@ -360,15 +404,15 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
return &buf
}
- req := NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/symbolpackage", url), createSymbolPackage("unknown-package", "SymbolsPackage")).
+ req := NewRequestWithBody(t, "PUT", url+"/symbolpackage", createSymbolPackage("unknown-package", "SymbolsPackage")).
AddBasicAuth(user.Name)
MakeRequest(t, req, http.StatusNotFound)
- req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/symbolpackage", url), createSymbolPackage(packageName, "DummyPackage")).
+ req = NewRequestWithBody(t, "PUT", url+"/symbolpackage", createSymbolPackage(packageName, "DummyPackage")).
AddBasicAuth(user.Name)
MakeRequest(t, req, http.StatusBadRequest)
- req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/symbolpackage", url), createSymbolPackage(packageName, "SymbolsPackage")).
+ req = NewRequestWithBody(t, "PUT", url+"/symbolpackage", createSymbolPackage(packageName, "SymbolsPackage")).
AddBasicAuth(user.Name)
MakeRequest(t, req, http.StatusCreated)
@@ -393,19 +437,19 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID)
assert.NoError(t, err)
- assert.Equal(t, int64(412), pb.Size)
+ assert.Equal(t, int64(633), pb.Size)
case fmt.Sprintf("%s.%s.snupkg", packageName, packageVersion):
assert.False(t, pf.IsLead)
pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID)
assert.NoError(t, err)
assert.Equal(t, int64(616), pb.Size)
- case fmt.Sprintf("%s.nuspec", packageName):
+ case packageName + ".nuspec":
assert.False(t, pf.IsLead)
pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID)
assert.NoError(t, err)
- assert.Equal(t, int64(427), pb.Size)
+ assert.Equal(t, int64(1043), pb.Size)
case symbolFilename:
assert.False(t, pf.IsLead)
@@ -419,11 +463,11 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
assert.Equal(t, nuget_module.PropertySymbolID, pps[0].Name)
assert.Equal(t, symbolID, pps[0].Value)
default:
- assert.FailNow(t, "unexpected file: %v", pf.Name)
+ assert.FailNow(t, "unexpected file", "unexpected file: %v", pf.Name)
}
}
- req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/symbolpackage", url), createSymbolPackage(packageName, "SymbolsPackage")).
+ req = NewRequestWithBody(t, "PUT", url+"/symbolpackage", createSymbolPackage(packageName, "SymbolsPackage")).
AddBasicAuth(user.Name)
MakeRequest(t, req, http.StatusConflict)
})
@@ -631,7 +675,7 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
})
t.Run("Next", func(t *testing.T) {
- req := NewRequest(t, "GET", fmt.Sprintf("%s/Search()?searchTerm='test'&$skip=0&$top=1", url)).
+ req := NewRequest(t, "GET", url+"/Search()?searchTerm='test'&$skip=0&$top=1").
AddBasicAuth(user.Name)
resp := MakeRequest(t, req, http.StatusOK)
@@ -712,17 +756,39 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
assert.Equal(t, indexURL, result.RegistrationIndexURL)
assert.Equal(t, 1, result.Count)
assert.Len(t, result.Pages, 1)
- assert.Equal(t, indexURL, result.Pages[0].RegistrationPageURL)
- assert.Equal(t, packageVersion, result.Pages[0].Lower)
- assert.Equal(t, packageVersion, result.Pages[0].Upper)
- assert.Equal(t, 1, result.Pages[0].Count)
- assert.Len(t, result.Pages[0].Items, 1)
- assert.Equal(t, packageName, result.Pages[0].Items[0].CatalogEntry.ID)
- assert.Equal(t, packageVersion, result.Pages[0].Items[0].CatalogEntry.Version)
- assert.Equal(t, packageAuthors, result.Pages[0].Items[0].CatalogEntry.Authors)
- assert.Equal(t, packageDescription, result.Pages[0].Items[0].CatalogEntry.Description)
- assert.Equal(t, leafURL, result.Pages[0].Items[0].CatalogEntry.CatalogLeafURL)
- assert.Equal(t, contentURL, result.Pages[0].Items[0].CatalogEntry.PackageContentURL)
+
+ page := result.Pages[0]
+ assert.Equal(t, indexURL, page.RegistrationPageURL)
+ assert.Equal(t, packageVersion, page.Lower)
+ assert.Equal(t, packageVersion, page.Upper)
+ assert.Equal(t, 1, page.Count)
+ assert.Len(t, page.Items, 1)
+
+ item := page.Items[0]
+ assert.Equal(t, packageName, item.CatalogEntry.ID)
+ assert.Equal(t, packageVersion, item.CatalogEntry.Version)
+ assert.Equal(t, packageAuthors, item.CatalogEntry.Authors)
+ assert.Equal(t, packageDescription, item.CatalogEntry.Description)
+ assert.Equal(t, leafURL, item.CatalogEntry.CatalogLeafURL)
+ assert.Equal(t, contentURL, item.CatalogEntry.PackageContentURL)
+ assert.Equal(t, packageIconURL, item.CatalogEntry.IconURL)
+ assert.Equal(t, packageLanguage, item.CatalogEntry.Language)
+ assert.Equal(t, packageLicenseURL, item.CatalogEntry.LicenseURL)
+ assert.Equal(t, packageProjectURL, item.CatalogEntry.ProjectURL)
+ assert.Equal(t, packageReleaseNotes, item.CatalogEntry.ReleaseNotes)
+ assert.Equal(t, packageRequireLicenseAcceptance, item.CatalogEntry.RequireLicenseAcceptance)
+ assert.Equal(t, packageTags, item.CatalogEntry.Tags)
+ assert.Equal(t, summary, item.CatalogEntry.Summary)
+ assert.Equal(t, isPrerelease, item.CatalogEntry.IsPrerelease)
+ assert.Len(t, item.CatalogEntry.DependencyGroups, dependencyCount)
+
+ dependencyGroup := item.CatalogEntry.DependencyGroups[0]
+ assert.Equal(t, dependencyTargetFramework, dependencyGroup.TargetFramework)
+ assert.Len(t, dependencyGroup.Dependencies, dependencyCount)
+
+ dependency := dependencyGroup.Dependencies[0]
+ assert.Equal(t, dependencyID, dependency.ID)
+ assert.Equal(t, dependencyVersion, dependency.Range)
})
t.Run("RegistrationLeaf", func(t *testing.T) {
@@ -736,11 +802,26 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
var result FeedEntry
decodeXML(t, resp, &result)
- assert.Equal(t, packageName, result.Properties.Title)
- assert.Equal(t, packageVersion, result.Properties.Version)
assert.Equal(t, packageAuthors, result.Properties.Authors)
assert.Equal(t, packageDescription, result.Properties.Description)
- assert.Equal(t, "Microsoft.CSharp:4.5.0:.NETStandard2.0", result.Properties.Dependencies)
+ assert.Equal(t, packageID, result.Properties.ID)
+ assert.Equal(t, packageVersion, result.Properties.Version)
+
+ assert.Equal(t, packageCopyright, result.Properties.Copyright)
+ assert.Equal(t, packageDevelopmentDependency, result.Properties.DevelopmentDependency.Value)
+ assert.Equal(t, packageIconURL, result.Properties.IconURL)
+ assert.Equal(t, packageLanguage, result.Properties.Language)
+ assert.Equal(t, packageLicenseURL, result.Properties.LicenseURL)
+ assert.Equal(t, packageMinClientVersion, result.Properties.MinClientVersion)
+ assert.Equal(t, packageOwners, result.Properties.Owners)
+ assert.Equal(t, packageProjectURL, result.Properties.ProjectURL)
+ assert.Equal(t, packageReleaseNotes, result.Properties.ReleaseNotes)
+ assert.Equal(t, packageRequireLicenseAcceptance, result.Properties.RequireLicenseAcceptance.Value)
+ assert.Equal(t, packageTags, result.Properties.Tags)
+ assert.Equal(t, packageTitle, result.Properties.Title)
+
+ packageVersion := strings.Join([]string{dependencyID, dependencyVersion, dependencyTargetFramework}, ":")
+ assert.Equal(t, packageVersion, result.Properties.Dependencies)
})
t.Run("v3", func(t *testing.T) {
@@ -754,8 +835,30 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
DecodeJSON(t, resp, &result)
assert.Equal(t, leafURL, result.RegistrationLeafURL)
- assert.Equal(t, contentURL, result.PackageContentURL)
assert.Equal(t, indexURL, result.RegistrationIndexURL)
+ assert.Equal(t, packageAuthors, result.CatalogEntry.Authors)
+ assert.Equal(t, packageCopyright, result.CatalogEntry.Copyright)
+
+ dependencyGroup := result.CatalogEntry.DependencyGroups[0]
+ assert.Equal(t, dependencyTargetFramework, dependencyGroup.TargetFramework)
+ assert.Len(t, dependencyGroup.Dependencies, dependencyCount)
+
+ dependency := dependencyGroup.Dependencies[0]
+ assert.Equal(t, dependencyID, dependency.ID)
+ assert.Equal(t, dependencyVersion, dependency.Range)
+
+ assert.Equal(t, packageDescription, result.CatalogEntry.Description)
+ assert.Equal(t, packageID, result.CatalogEntry.ID)
+ assert.Equal(t, packageIconURL, result.CatalogEntry.IconURL)
+ assert.Equal(t, isPrerelease, result.CatalogEntry.IsPrerelease)
+ assert.Equal(t, packageLanguage, result.CatalogEntry.Language)
+ assert.Equal(t, packageLicenseURL, result.CatalogEntry.LicenseURL)
+ assert.Equal(t, contentURL, result.PackageContentURL)
+ assert.Equal(t, packageProjectURL, result.CatalogEntry.ProjectURL)
+ assert.Equal(t, packageRequireLicenseAcceptance, result.CatalogEntry.RequireLicenseAcceptance)
+ assert.Equal(t, summary, result.CatalogEntry.Summary)
+ assert.Equal(t, packageTags, result.CatalogEntry.Tags)
+ assert.Equal(t, packageVersion, result.CatalogEntry.Version)
})
})
})
diff --git a/tests/integration/api_packages_pub_test.go b/tests/integration/api_packages_pub_test.go
index 11da894ddf..3c1bca908e 100644
--- a/tests/integration/api_packages_pub_test.go
+++ b/tests/integration/api_packages_pub_test.go
@@ -37,7 +37,7 @@ func TestPackagePub(t *testing.T) {
packageVersion := "1.0.1"
packageDescription := "Test Description"
- filename := fmt.Sprintf("%s.tar.gz", packageVersion)
+ filename := packageVersion + ".tar.gz"
pubspecContent := `name: ` + packageName + `
version: ` + packageVersion + `
diff --git a/tests/integration/api_packages_pypi_test.go b/tests/integration/api_packages_pypi_test.go
index e973f6a52a..54db45f1ac 100644
--- a/tests/integration/api_packages_pypi_test.go
+++ b/tests/integration/api_packages_pypi_test.go
@@ -32,15 +32,16 @@ func TestPackagePyPI(t *testing.T) {
packageVersion := "1!1.0.1+r1234"
packageAuthor := "KN4CK3R"
packageDescription := "Test Description"
+ projectURL := "https://example.com"
content := "test"
hashSHA256 := "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
root := fmt.Sprintf("/api/packages/%s/pypi", user.Name)
- uploadFile := func(t *testing.T, filename, content string, expectedStatus int) {
- body := &bytes.Buffer{}
- writer := multipart.NewWriter(body)
+ createBasicMultipartFile := func(filename, packageName, content string) (body *bytes.Buffer, writer *multipart.Writer, closer func() error) {
+ body = &bytes.Buffer{}
+ writer = multipart.NewWriter(body)
part, _ := writer.CreateFormFile("content", filename)
_, _ = io.Copy(part, strings.NewReader(content))
@@ -52,14 +53,27 @@ func TestPackagePyPI(t *testing.T) {
writer.WriteField("sha256_digest", hashSHA256)
writer.WriteField("requires_python", "3.6")
- _ = writer.Close()
+ return body, writer, writer.Close
+ }
+ uploadHelper := func(t *testing.T, body *bytes.Buffer, contentType string, expectedStatus int) {
req := NewRequestWithBody(t, "POST", root, body).
- SetHeader("Content-Type", writer.FormDataContentType()).
+ SetHeader("Content-Type", contentType).
AddBasicAuth(user.Name)
MakeRequest(t, req, expectedStatus)
}
+ uploadFile := func(t *testing.T, filename, content string, expectedStatus int) {
+ body, writer, closeFunc := createBasicMultipartFile(filename, packageName, content)
+
+ writer.WriteField("project_urls", "DOCUMENTATION , https://readthedocs.org")
+ writer.WriteField("project_urls", "Home-page, "+projectURL)
+
+ _ = closeFunc()
+
+ uploadHelper(t, body, writer.FormDataContentType(), expectedStatus)
+ }
+
t.Run("Upload", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
@@ -74,6 +88,7 @@ func TestPackagePyPI(t *testing.T) {
assert.NoError(t, err)
assert.Nil(t, pd.SemVer)
assert.IsType(t, &pypi.Metadata{}, pd.Metadata)
+ assert.Equal(t, projectURL, pd.Metadata.(*pypi.Metadata).ProjectURL)
assert.Equal(t, packageName, pd.Package.Name)
assert.Equal(t, packageVersion, pd.Version.Version)
@@ -133,6 +148,48 @@ func TestPackagePyPI(t *testing.T) {
uploadFile(t, "test.tar.gz", content, http.StatusConflict)
})
+ t.Run("UploadUsingDeprecatedHomepageMetadata", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ pkgName := "homepage-package"
+ body, writer, closeFunc := createBasicMultipartFile("test.whl", pkgName, content)
+
+ writer.WriteField("home_page", projectURL)
+
+ _ = closeFunc()
+
+ uploadHelper(t, body, writer.FormDataContentType(), http.StatusCreated)
+
+ pvs, err := packages.GetVersionsByPackageName(db.DefaultContext, user.ID, packages.TypePyPI, pkgName)
+ assert.NoError(t, err)
+ assert.Len(t, pvs, 1)
+
+ pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
+ assert.NoError(t, err)
+ assert.IsType(t, &pypi.Metadata{}, pd.Metadata)
+ assert.Equal(t, projectURL, pd.Metadata.(*pypi.Metadata).ProjectURL)
+ })
+
+ t.Run("UploadWithoutAnyHomepageURLMetadata", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ pkgName := "no-project-url-or-homepage-package"
+ body, writer, closeFunc := createBasicMultipartFile("test.whl", pkgName, content)
+
+ _ = closeFunc()
+
+ uploadHelper(t, body, writer.FormDataContentType(), http.StatusCreated)
+
+ pvs, err := packages.GetVersionsByPackageName(db.DefaultContext, user.ID, packages.TypePyPI, pkgName)
+ assert.NoError(t, err)
+ assert.Len(t, pvs, 1)
+
+ pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
+ assert.NoError(t, err)
+ assert.IsType(t, &pypi.Metadata{}, pd.Metadata)
+ assert.Empty(t, pd.Metadata.(*pypi.Metadata).ProjectURL)
+ })
+
t.Run("Download", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
@@ -147,7 +204,7 @@ func TestPackagePyPI(t *testing.T) {
downloadFile("test.whl")
downloadFile("test.tar.gz")
- pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypePyPI)
+ pvs, err := packages.GetVersionsByPackageName(db.DefaultContext, user.ID, packages.TypePyPI, packageName)
assert.NoError(t, err)
assert.Len(t, pvs, 1)
assert.Equal(t, int64(2), pvs[0].DownloadCount)
diff --git a/tests/integration/api_packages_rpm_test.go b/tests/integration/api_packages_rpm_test.go
index 6feceaeb78..bd1959f64e 100644
--- a/tests/integration/api_packages_rpm_test.go
+++ b/tests/integration/api_packages_rpm_test.go
@@ -157,9 +157,14 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`,
t.Run("Download", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
+ // download the package without the file name
req := NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s", groupURL, packageName, packageVersion, packageArchitecture))
resp := MakeRequest(t, req, http.StatusOK)
+ assert.Equal(t, content, resp.Body.Bytes())
+ // download the package with a file name (it can be anything)
+ req = NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s/any-file-name", groupURL, packageName, packageVersion, packageArchitecture))
+ resp = MakeRequest(t, req, http.StatusOK)
assert.Equal(t, content, resp.Body.Bytes())
})
@@ -317,7 +322,7 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`,
var result Metadata
decodeGzipXML(t, resp, &result)
- assert.EqualValues(t, 1, result.PackageCount)
+ assert.Equal(t, 1, result.PackageCount)
assert.Len(t, result.Packages, 1)
p := result.Packages[0]
assert.Equal(t, "rpm", p.Type)
@@ -366,7 +371,7 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`,
var result Filelists
decodeGzipXML(t, resp, &result)
- assert.EqualValues(t, 1, result.PackageCount)
+ assert.Equal(t, 1, result.PackageCount)
assert.Len(t, result.Packages, 1)
p := result.Packages[0]
assert.NotEmpty(t, p.Pkgid)
@@ -403,7 +408,7 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`,
var result Other
decodeGzipXML(t, resp, &result)
- assert.EqualValues(t, 1, result.PackageCount)
+ assert.Equal(t, 1, result.PackageCount)
assert.Len(t, result.Packages, 1)
p := result.Packages[0]
assert.NotEmpty(t, p.Pkgid)
@@ -447,7 +452,8 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`,
pub, err := openpgp.ReadArmoredKeyRing(gpgResp.Body)
require.NoError(t, err)
- req = NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s", groupURL, packageName, packageVersion, packageArchitecture))
+ rpmFileName := fmt.Sprintf("%s-%s.%s.rpm", packageName, packageVersion, packageArchitecture)
+ req = NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s/%s", groupURL, packageName, packageVersion, packageArchitecture, rpmFileName))
resp := MakeRequest(t, req, http.StatusOK)
_, sigs, err := rpmutils.Verify(resp.Body, pub)
diff --git a/tests/integration/api_packages_rubygems_test.go b/tests/integration/api_packages_rubygems_test.go
index fe9283df4d..ab76c52440 100644
--- a/tests/integration/api_packages_rubygems_test.go
+++ b/tests/integration/api_packages_rubygems_test.go
@@ -185,7 +185,7 @@ func TestPackageRubyGems(t *testing.T) {
root := fmt.Sprintf("/api/packages/%s/rubygems", user.Name)
uploadFile := func(t *testing.T, content []byte, expectedStatus int) {
- req := NewRequestWithBody(t, "POST", fmt.Sprintf("%s/api/v1/gems", root), bytes.NewReader(content)).
+ req := NewRequestWithBody(t, "POST", root+"/api/v1/gems", bytes.NewReader(content)).
AddBasicAuth(user.Name)
MakeRequest(t, req, expectedStatus)
}
@@ -293,7 +293,7 @@ gAAAAP//MS06Gw==`)
t.Run("Versions", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("%s/versions", root)).AddBasicAuth(user.Name)
+ req := NewRequest(t, "GET", root+"/versions").AddBasicAuth(user.Name)
resp := MakeRequest(t, req, http.StatusOK)
assert.Equal(t, `---
gitea 1.0.5 08843c2dd0ea19910e6b056b98e38f1c
@@ -307,7 +307,7 @@ gitea-another 0.99 8b639e4048d282941485368ec42609be
_ = writer.WriteField("gem_name", packageName)
_ = writer.WriteField("version", packageVersion)
_ = writer.Close()
- req := NewRequestWithBody(t, "DELETE", fmt.Sprintf("%s/api/v1/gems/yank", root), &body).
+ req := NewRequestWithBody(t, "DELETE", root+"/api/v1/gems/yank", &body).
SetHeader("Content-Type", writer.FormDataContentType()).
AddBasicAuth(user.Name)
MakeRequest(t, req, http.StatusOK)
@@ -330,7 +330,7 @@ gitea-another 0.99 8b639e4048d282941485368ec42609be
t.Run("VersionsAfterDelete", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("%s/versions", root)).AddBasicAuth(user.Name)
+ req := NewRequest(t, "GET", root+"/versions").AddBasicAuth(user.Name)
resp := MakeRequest(t, req, http.StatusOK)
assert.Equal(t, "---\n", resp.Body.String())
})
diff --git a/tests/integration/api_packages_swift_test.go b/tests/integration/api_packages_swift_test.go
index c0e0dccfab..b29e8459ff 100644
--- a/tests/integration/api_packages_swift_test.go
+++ b/tests/integration/api_packages_swift_test.go
@@ -23,6 +23,7 @@ import (
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func TestPackageSwift(t *testing.T) {
@@ -34,6 +35,7 @@ func TestPackageSwift(t *testing.T) {
packageName := "test_package"
packageID := packageScope + "." + packageName
packageVersion := "1.0.3"
+ packageVersion2 := "1.0.4"
packageAuthor := "KN4CK3R"
packageDescription := "Gitea Test Package"
packageRepositoryURL := "https://gitea.io/gitea/gitea"
@@ -183,6 +185,94 @@ func TestPackageSwift(t *testing.T) {
)
})
+ t.Run("UploadMultipart", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ uploadPackage := func(t *testing.T, url string, expectedStatus int, sr io.Reader, metadata string) {
+ var body bytes.Buffer
+ mpw := multipart.NewWriter(&body)
+
+ // Read the source archive content
+ sourceContent, err := io.ReadAll(sr)
+ assert.NoError(t, err)
+ mpw.WriteField("source-archive", string(sourceContent))
+
+ if metadata != "" {
+ mpw.WriteField("metadata", metadata)
+ }
+
+ mpw.Close()
+
+ req := NewRequestWithBody(t, "PUT", url, &body).
+ SetHeader("Content-Type", mpw.FormDataContentType()).
+ SetHeader("Accept", swift_router.AcceptJSON).
+ AddBasicAuth(user.Name)
+ MakeRequest(t, req, expectedStatus)
+ }
+
+ createArchive := func(files map[string]string) *bytes.Buffer {
+ var buf bytes.Buffer
+ zw := zip.NewWriter(&buf)
+ for filename, content := range files {
+ w, _ := zw.Create(filename)
+ w.Write([]byte(content))
+ }
+ zw.Close()
+ return &buf
+ }
+
+ uploadURL := fmt.Sprintf("%s/%s/%s/%s", url, packageScope, packageName, packageVersion2)
+
+ req := NewRequestWithBody(t, "PUT", uploadURL, bytes.NewReader([]byte{}))
+ MakeRequest(t, req, http.StatusUnauthorized)
+
+ // Test with metadata as form field
+ uploadPackage(
+ t,
+ uploadURL,
+ http.StatusCreated,
+ createArchive(map[string]string{
+ "Package.swift": contentManifest1,
+ "Package@swift-5.6.swift": contentManifest2,
+ }),
+ `{"name":"`+packageName+`","version":"`+packageVersion2+`","description":"`+packageDescription+`","codeRepository":"`+packageRepositoryURL+`","author":{"givenName":"`+packageAuthor+`"},"repositoryURLs":["`+packageRepositoryURL+`"]}`,
+ )
+
+ pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeSwift)
+ assert.NoError(t, err)
+ require.Len(t, pvs, 2) // ATTENTION: many subtests are unable to run separately, they depend on the results of previous tests
+ thisPackageVersion := pvs[0]
+ pd, err := packages.GetPackageDescriptor(db.DefaultContext, thisPackageVersion)
+ assert.NoError(t, err)
+ assert.NotNil(t, pd.SemVer)
+ assert.Equal(t, packageID, pd.Package.Name)
+ assert.Equal(t, packageVersion2, pd.Version.Version)
+ assert.IsType(t, &swift_module.Metadata{}, pd.Metadata)
+ metadata := pd.Metadata.(*swift_module.Metadata)
+ assert.Equal(t, packageDescription, metadata.Description)
+ assert.Len(t, metadata.Manifests, 2)
+ assert.Equal(t, contentManifest1, metadata.Manifests[""].Content)
+ assert.Equal(t, contentManifest2, metadata.Manifests["5.6"].Content)
+ assert.Len(t, pd.VersionProperties, 1)
+ assert.Equal(t, packageRepositoryURL, pd.VersionProperties.GetByName(swift_module.PropertyRepositoryURL))
+
+ pfs, err := packages.GetFilesByVersionID(db.DefaultContext, thisPackageVersion.ID)
+ assert.NoError(t, err)
+ assert.Len(t, pfs, 1)
+ assert.Equal(t, fmt.Sprintf("%s-%s.zip", packageName, packageVersion2), pfs[0].Name)
+ assert.True(t, pfs[0].IsLead)
+
+ uploadPackage(
+ t,
+ uploadURL,
+ http.StatusConflict,
+ createArchive(map[string]string{
+ "Package.swift": contentManifest1,
+ }),
+ "",
+ )
+ })
+
t.Run("Download", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
@@ -211,7 +301,7 @@ func TestPackageSwift(t *testing.T) {
SetHeader("Accept", swift_router.AcceptJSON)
resp := MakeRequest(t, req, http.StatusOK)
- versionURL := setting.AppURL + url[1:] + fmt.Sprintf("/%s/%s/%s", packageScope, packageName, packageVersion)
+ versionURL := setting.AppURL + url[1:] + fmt.Sprintf("/%s/%s/%s", packageScope, packageName, packageVersion2)
assert.Equal(t, "1", resp.Header().Get("Content-Version"))
assert.Equal(t, fmt.Sprintf(`<%s>; rel="latest-version"`, versionURL), resp.Header().Get("Link"))
@@ -221,9 +311,9 @@ func TestPackageSwift(t *testing.T) {
var result *swift_router.EnumeratePackageVersionsResponse
DecodeJSON(t, resp, &result)
- assert.Len(t, result.Releases, 1)
- assert.Contains(t, result.Releases, packageVersion)
- assert.Equal(t, versionURL, result.Releases[packageVersion].URL)
+ assert.Len(t, result.Releases, 2)
+ assert.Contains(t, result.Releases, packageVersion2)
+ assert.Equal(t, versionURL, result.Releases[packageVersion2].URL)
req = NewRequest(t, "GET", fmt.Sprintf("%s/%s/%s.json", url, packageScope, packageName)).
AddBasicAuth(user.Name)
diff --git a/tests/integration/api_packages_test.go b/tests/integration/api_packages_test.go
index daf32e82f9..f10b098885 100644
--- a/tests/integration/api_packages_test.go
+++ b/tests/integration/api_packages_test.go
@@ -15,14 +15,15 @@ import (
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
packages_model "code.gitea.io/gitea/models/packages"
- container_model "code.gitea.io/gitea/models/packages/container"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
+ container_module "code.gitea.io/gitea/modules/packages/container"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
packages_service "code.gitea.io/gitea/services/packages"
packages_cleanup_service "code.gitea.io/gitea/services/packages/cleanup"
+ repo_service "code.gitea.io/gitea/services/repository"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
@@ -34,7 +35,7 @@ func TestPackageAPI(t *testing.T) {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
session := loginUser(t, user.Name)
tokenReadPackage := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadPackage)
- tokenDeletePackage := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWritePackage)
+ tokenWritePackage := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWritePackage)
packageName := "test-package"
packageVersion := "1.0.3"
@@ -48,7 +49,7 @@ func TestPackageAPI(t *testing.T) {
t.Run("ListPackages", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s", user.Name)).
+ req := NewRequest(t, "GET", "/api/v1/packages/"+user.Name).
AddTokenAuth(tokenReadPackage)
resp := MakeRequest(t, req, http.StatusOK)
@@ -82,47 +83,101 @@ func TestPackageAPI(t *testing.T) {
assert.Equal(t, packageVersion, p.Version)
assert.NotNil(t, p.Creator)
assert.Equal(t, user.Name, p.Creator.UserName)
+ })
- t.Run("RepositoryLink", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
+ t.Run("ListPackageVersions", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
- p, err := packages_model.GetPackageByName(db.DefaultContext, user.ID, packages_model.TypeGeneric, packageName)
- assert.NoError(t, err)
+ req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s", user.Name, packageName)).
+ AddTokenAuth(tokenReadPackage)
+ resp := MakeRequest(t, req, http.StatusOK)
- // no repository link
- req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s", user.Name, packageName, packageVersion)).
- AddTokenAuth(tokenReadPackage)
- resp := MakeRequest(t, req, http.StatusOK)
+ var apiPackages []*api.Package
+ DecodeJSON(t, resp, &apiPackages)
+
+ assert.Len(t, apiPackages, 1)
+ assert.Equal(t, string(packages_model.TypeGeneric), apiPackages[0].Type)
+ assert.Equal(t, packageName, apiPackages[0].Name)
+ assert.Equal(t, packageVersion, apiPackages[0].Version)
+ })
+
+ t.Run("LatestPackageVersion", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
- var ap1 *api.Package
- DecodeJSON(t, resp, &ap1)
- assert.Nil(t, ap1.Repository)
+ req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/-/latest", user.Name, packageName)).
+ AddTokenAuth(tokenReadPackage)
+ resp := MakeRequest(t, req, http.StatusOK)
- // link to public repository
- assert.NoError(t, packages_model.SetRepositoryLink(db.DefaultContext, p.ID, 1))
+ var apiPackage *api.Package
+ DecodeJSON(t, resp, &apiPackage)
- req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s", user.Name, packageName, packageVersion)).
- AddTokenAuth(tokenReadPackage)
- resp = MakeRequest(t, req, http.StatusOK)
+ assert.Equal(t, string(packages_model.TypeGeneric), apiPackage.Type)
+ assert.Equal(t, packageName, apiPackage.Name)
+ assert.Equal(t, packageVersion, apiPackage.Version)
+ })
- var ap2 *api.Package
- DecodeJSON(t, resp, &ap2)
- assert.NotNil(t, ap2.Repository)
- assert.EqualValues(t, 1, ap2.Repository.ID)
+ t.Run("RepositoryLink", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
- // link to private repository
- assert.NoError(t, packages_model.SetRepositoryLink(db.DefaultContext, p.ID, 2))
+ _, err := packages_model.GetPackageByName(db.DefaultContext, user.ID, packages_model.TypeGeneric, packageName)
+ assert.NoError(t, err)
- req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s", user.Name, packageName, packageVersion)).
- AddTokenAuth(tokenReadPackage)
- resp = MakeRequest(t, req, http.StatusOK)
+ // no repository link
+ req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s", user.Name, packageName, packageVersion)).
+ AddTokenAuth(tokenReadPackage)
+ resp := MakeRequest(t, req, http.StatusOK)
- var ap3 *api.Package
- DecodeJSON(t, resp, &ap3)
- assert.Nil(t, ap3.Repository)
+ var ap1 *api.Package
+ DecodeJSON(t, resp, &ap1)
+ assert.Nil(t, ap1.Repository)
- assert.NoError(t, packages_model.UnlinkRepositoryFromAllPackages(db.DefaultContext, 2))
+ // create a repository
+ newRepo, err := repo_service.CreateRepository(db.DefaultContext, user, user, repo_service.CreateRepoOptions{
+ Name: "repo4",
})
+ assert.NoError(t, err)
+
+ // link to public repository
+ req = NewRequest(t, "POST", fmt.Sprintf("/api/v1/packages/%s/generic/%s/-/link/%s", user.Name, packageName, newRepo.Name)).AddTokenAuth(tokenWritePackage)
+ MakeRequest(t, req, http.StatusCreated)
+
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s", user.Name, packageName, packageVersion)).
+ AddTokenAuth(tokenReadPackage)
+ resp = MakeRequest(t, req, http.StatusOK)
+
+ var ap2 *api.Package
+ DecodeJSON(t, resp, &ap2)
+ assert.NotNil(t, ap2.Repository)
+ assert.Equal(t, newRepo.ID, ap2.Repository.ID)
+
+ // link to repository without write access, should fail
+ req = NewRequest(t, "POST", fmt.Sprintf("/api/v1/packages/%s/generic/%s/-/link/%s", user.Name, packageName, "repo3")).AddTokenAuth(tokenWritePackage)
+ MakeRequest(t, req, http.StatusNotFound)
+
+ // remove link
+ req = NewRequest(t, "POST", fmt.Sprintf("/api/v1/packages/%s/generic/%s/-/unlink", user.Name, packageName)).AddTokenAuth(tokenWritePackage)
+ MakeRequest(t, req, http.StatusNoContent)
+
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s", user.Name, packageName, packageVersion)).
+ AddTokenAuth(tokenReadPackage)
+ resp = MakeRequest(t, req, http.StatusOK)
+
+ var ap3 *api.Package
+ DecodeJSON(t, resp, &ap3)
+ assert.Nil(t, ap3.Repository)
+
+ // force link to a repository the currently logged-in user doesn't have access to
+ privateRepoID := int64(6)
+ assert.NoError(t, packages_model.SetRepositoryLink(db.DefaultContext, ap1.ID, privateRepoID))
+
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s", user.Name, packageName, packageVersion)).AddTokenAuth(tokenReadPackage)
+ resp = MakeRequest(t, req, http.StatusOK)
+
+ var ap4 *api.Package
+ DecodeJSON(t, resp, &ap4)
+ assert.Nil(t, ap4.Repository)
+
+ assert.NoError(t, packages_model.UnlinkRepositoryFromAllPackages(db.DefaultContext, privateRepoID))
})
t.Run("ListPackageFiles", func(t *testing.T) {
@@ -152,11 +207,11 @@ func TestPackageAPI(t *testing.T) {
defer tests.PrintCurrentTest(t)()
req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/packages/%s/dummy/%s/%s", user.Name, packageName, packageVersion)).
- AddTokenAuth(tokenDeletePackage)
+ AddTokenAuth(tokenWritePackage)
MakeRequest(t, req, http.StatusNotFound)
req = NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/packages/%s/generic/%s/%s", user.Name, packageName, packageVersion)).
- AddTokenAuth(tokenDeletePackage)
+ AddTokenAuth(tokenWritePackage)
MakeRequest(t, req, http.StatusNoContent)
})
}
@@ -384,7 +439,7 @@ func TestPackageAccess(t *testing.T) {
{limitedOrgNoMember, http.StatusOK},
{publicOrgNoMember, http.StatusOK},
} {
- req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s", target.Owner.Name)).
+ req := NewRequest(t, "GET", "/api/v1/packages/"+target.Owner.Name).
AddTokenAuth(tokenReadPackage)
MakeRequest(t, req, target.ExpectedStatus)
}
@@ -483,7 +538,7 @@ func TestPackageCleanup(t *testing.T) {
assert.NoError(t, err)
assert.NotEmpty(t, pbs)
- _, err = packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, "cleanup-test", container_model.UploadVersion)
+ _, err = packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, "cleanup-test", container_module.UploadVersion)
assert.NoError(t, err)
err = packages_cleanup_service.CleanupTask(db.DefaultContext, duration)
@@ -493,7 +548,7 @@ func TestPackageCleanup(t *testing.T) {
assert.NoError(t, err)
assert.Empty(t, pbs)
- _, err = packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, "cleanup-test", container_model.UploadVersion)
+ _, err = packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, "cleanup-test", container_module.UploadVersion)
assert.ErrorIs(t, err, packages_model.ErrPackageNotExist)
})
@@ -581,12 +636,16 @@ func TestPackageCleanup(t *testing.T) {
},
{
Name: "Mixed",
- Versions: []version{
- {Version: "keep", ShouldExist: true, Created: time.Now().Add(time.Duration(10000)).Unix()},
- {Version: "dummy", ShouldExist: true, Created: 1},
- {Version: "test-3", ShouldExist: true},
- {Version: "test-4", ShouldExist: false, Created: 1},
- },
+ Versions: func(limit, removeDays int) []version {
+ aa := []version{
+ {Version: "keep", ShouldExist: true, Created: time.Now().Add(time.Duration(10000)).Unix()},
+ {Version: "dummy", ShouldExist: true, Created: 1},
+ }
+ for i := range limit {
+ aa = append(aa, version{Version: fmt.Sprintf("test-%v", i+3), ShouldExist: util.Iif(i < removeDays, true, false), Created: time.Now().AddDate(0, 0, -i).Unix()})
+ }
+ return aa
+ }(220, 7),
Rule: &packages_model.PackageCleanupRule{
Enabled: true,
KeepCount: 1,
@@ -631,7 +690,7 @@ func TestPackageCleanup(t *testing.T) {
err = packages_service.DeletePackageVersionAndReferences(db.DefaultContext, pv)
assert.NoError(t, err)
} else {
- assert.ErrorIs(t, err, packages_model.ErrPackageNotExist)
+ assert.ErrorIs(t, err, packages_model.ErrPackageNotExist, v.Version)
}
}
diff --git a/tests/integration/api_packages_vagrant_test.go b/tests/integration/api_packages_vagrant_test.go
index a5e954f3a2..1743e37222 100644
--- a/tests/integration/api_packages_vagrant_test.go
+++ b/tests/integration/api_packages_vagrant_test.go
@@ -35,7 +35,7 @@ func TestPackageVagrant(t *testing.T) {
packageDescription := "Test Description"
packageProvider := "virtualbox"
- filename := fmt.Sprintf("%s.box", packageProvider)
+ filename := packageProvider + ".box"
infoContent, _ := json.Marshal(map[string]string{
"description": packageDescription,
@@ -59,7 +59,7 @@ func TestPackageVagrant(t *testing.T) {
t.Run("Authenticate", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- authenticateURL := fmt.Sprintf("%s/authenticate", root)
+ authenticateURL := root + "/authenticate"
req := NewRequest(t, "GET", authenticateURL)
MakeRequest(t, req, http.StatusUnauthorized)
diff --git a/tests/integration/api_private_serv_test.go b/tests/integration/api_private_serv_test.go
index 2001bb1fad..b0dd0cf049 100644
--- a/tests/integration/api_private_serv_test.go
+++ b/tests/integration/api_private_serv_test.go
@@ -17,7 +17,7 @@ import (
func TestAPIPrivateNoServ(t *testing.T) {
onGiteaRun(t, func(*testing.T, *url.URL) {
- ctx, cancel := context.WithCancel(context.Background())
+ ctx, cancel := context.WithCancel(t.Context())
defer cancel()
key, user, err := private.ServNoCommand(ctx, 1)
assert.NoError(t, err)
@@ -39,7 +39,7 @@ func TestAPIPrivateNoServ(t *testing.T) {
func TestAPIPrivateServ(t *testing.T) {
onGiteaRun(t, func(*testing.T, *url.URL) {
- ctx, cancel := context.WithCancel(context.Background())
+ ctx, cancel := context.WithCancel(t.Context())
defer cancel()
// Can push to a repo we own
diff --git a/tests/integration/api_pull_commits_test.go b/tests/integration/api_pull_commits_test.go
index 5ffc8158f3..f43ad7d3be 100644
--- a/tests/integration/api_pull_commits_test.go
+++ b/tests/integration/api_pull_commits_test.go
@@ -15,6 +15,7 @@ import (
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func TestAPIPullCommits(t *testing.T) {
@@ -29,9 +30,7 @@ func TestAPIPullCommits(t *testing.T) {
var commits []*api.Commit
DecodeJSON(t, resp, &commits)
- if !assert.Len(t, commits, 2) {
- return
- }
+ require.Len(t, commits, 2)
assert.Equal(t, "985f0301dba5e7b34be866819cd15ad3d8f508ee", commits[0].SHA)
assert.Equal(t, "5c050d3b6d2db231ab1f64e324f1b6b9a0b181c2", commits[1].SHA)
diff --git a/tests/integration/api_pull_review_test.go b/tests/integration/api_pull_review_test.go
index ba6b62d0d7..1fc65ddea8 100644
--- a/tests/integration/api_pull_review_test.go
+++ b/tests/integration/api_pull_review_test.go
@@ -21,6 +21,7 @@ import (
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
"xorm.io/builder"
)
@@ -39,21 +40,20 @@ func TestAPIPullReview(t *testing.T) {
var reviews []*api.PullReview
DecodeJSON(t, resp, &reviews)
- if !assert.Len(t, reviews, 8) {
- return
- }
+ require.Len(t, reviews, 8)
+
for _, r := range reviews {
- assert.EqualValues(t, pullIssue.HTMLURL(), r.HTMLPullURL)
+ assert.Equal(t, pullIssue.HTMLURL(), r.HTMLPullURL)
}
assert.EqualValues(t, 8, reviews[3].ID)
assert.EqualValues(t, "APPROVED", reviews[3].State)
- assert.EqualValues(t, 0, reviews[3].CodeCommentsCount)
+ assert.Equal(t, 0, reviews[3].CodeCommentsCount)
assert.True(t, reviews[3].Stale)
assert.False(t, reviews[3].Official)
assert.EqualValues(t, 10, reviews[5].ID)
assert.EqualValues(t, "REQUEST_CHANGES", reviews[5].State)
- assert.EqualValues(t, 1, reviews[5].CodeCommentsCount)
+ assert.Equal(t, 1, reviews[5].CodeCommentsCount)
assert.EqualValues(t, -1, reviews[5].Reviewer.ID) // ghost user
assert.False(t, reviews[5].Stale)
assert.True(t, reviews[5].Official)
@@ -64,13 +64,13 @@ func TestAPIPullReview(t *testing.T) {
resp = MakeRequest(t, req, http.StatusOK)
var review api.PullReview
DecodeJSON(t, resp, &review)
- assert.EqualValues(t, *reviews[3], review)
+ assert.Equal(t, *reviews[3], review)
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/pulls/%d/reviews/%d", repo.OwnerName, repo.Name, pullIssue.Index, reviews[5].ID).
AddTokenAuth(token)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &review)
- assert.EqualValues(t, *reviews[5], review)
+ assert.Equal(t, *reviews[5], review)
// test GetPullReviewComments
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 7})
@@ -80,11 +80,11 @@ func TestAPIPullReview(t *testing.T) {
var reviewComments []*api.PullReviewComment
DecodeJSON(t, resp, &reviewComments)
assert.Len(t, reviewComments, 1)
- assert.EqualValues(t, "Ghost", reviewComments[0].Poster.UserName)
- assert.EqualValues(t, "a review from a deleted user", reviewComments[0].Body)
- assert.EqualValues(t, comment.ID, reviewComments[0].ID)
+ assert.Equal(t, "Ghost", reviewComments[0].Poster.UserName)
+ assert.Equal(t, "a review from a deleted user", reviewComments[0].Body)
+ assert.Equal(t, comment.ID, reviewComments[0].ID)
assert.EqualValues(t, comment.UpdatedUnix, reviewComments[0].Updated.Unix())
- assert.EqualValues(t, comment.HTMLURL(db.DefaultContext), reviewComments[0].HTMLURL)
+ assert.Equal(t, comment.HTMLURL(db.DefaultContext), reviewComments[0].HTMLURL)
// test CreatePullReview
req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/reviews", repo.OwnerName, repo.Name, pullIssue.Index), &api.CreatePullReviewOptions{
@@ -113,7 +113,7 @@ func TestAPIPullReview(t *testing.T) {
DecodeJSON(t, resp, &review)
assert.EqualValues(t, 6, review.ID)
assert.EqualValues(t, "PENDING", review.State)
- assert.EqualValues(t, 3, review.CodeCommentsCount)
+ assert.Equal(t, 3, review.CodeCommentsCount)
// test SubmitPullReview
req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/reviews/%d", repo.OwnerName, repo.Name, pullIssue.Index, review.ID), &api.SubmitPullReviewOptions{
@@ -124,7 +124,7 @@ func TestAPIPullReview(t *testing.T) {
DecodeJSON(t, resp, &review)
assert.EqualValues(t, 6, review.ID)
assert.EqualValues(t, "APPROVED", review.State)
- assert.EqualValues(t, 3, review.CodeCommentsCount)
+ assert.Equal(t, 3, review.CodeCommentsCount)
// test dismiss review
req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/reviews/%d/dismissals", repo.OwnerName, repo.Name, pullIssue.Index, review.ID), &api.DismissPullReviewOptions{
@@ -151,7 +151,7 @@ func TestAPIPullReview(t *testing.T) {
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &review)
assert.EqualValues(t, "COMMENT", review.State)
- assert.EqualValues(t, 0, review.CodeCommentsCount)
+ assert.Equal(t, 0, review.CodeCommentsCount)
req = NewRequestf(t, http.MethodDelete, "/api/v1/repos/%s/%s/pulls/%d/reviews/%d", repo.OwnerName, repo.Name, pullIssue.Index, review.ID).
AddTokenAuth(token)
MakeRequest(t, req, http.StatusNoContent)
@@ -179,7 +179,7 @@ func TestAPIPullReview(t *testing.T) {
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &commentReview)
assert.EqualValues(t, "COMMENT", commentReview.State)
- assert.EqualValues(t, 2, commentReview.CodeCommentsCount)
+ assert.Equal(t, 2, commentReview.CodeCommentsCount)
assert.Empty(t, commentReview.Body)
assert.False(t, commentReview.Dismissed)
@@ -194,8 +194,8 @@ func TestAPIPullReview(t *testing.T) {
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &commentReview)
assert.EqualValues(t, "COMMENT", commentReview.State)
- assert.EqualValues(t, 0, commentReview.CodeCommentsCount)
- assert.EqualValues(t, commentBody, commentReview.Body)
+ assert.Equal(t, 0, commentReview.CodeCommentsCount)
+ assert.Equal(t, commentBody, commentReview.Body)
assert.False(t, commentReview.Dismissed)
// test CreatePullReview Comment without body and no comments
@@ -207,7 +207,7 @@ func TestAPIPullReview(t *testing.T) {
resp = MakeRequest(t, req, http.StatusUnprocessableEntity)
errMap := make(map[string]any)
json.Unmarshal(resp.Body.Bytes(), &errMap)
- assert.EqualValues(t, "review event COMMENT requires a body or a comment", errMap["message"].(string))
+ assert.Equal(t, "review event COMMENT requires a body or a comment", errMap["message"].(string))
// test get review requests
// to make it simple, use same api with get review
@@ -221,14 +221,14 @@ func TestAPIPullReview(t *testing.T) {
DecodeJSON(t, resp, &reviews)
assert.EqualValues(t, 11, reviews[0].ID)
assert.EqualValues(t, "REQUEST_REVIEW", reviews[0].State)
- assert.EqualValues(t, 0, reviews[0].CodeCommentsCount)
+ assert.Equal(t, 0, reviews[0].CodeCommentsCount)
assert.False(t, reviews[0].Stale)
assert.True(t, reviews[0].Official)
- assert.EqualValues(t, "test_team", reviews[0].ReviewerTeam.Name)
+ assert.Equal(t, "test_team", reviews[0].ReviewerTeam.Name)
assert.EqualValues(t, 12, reviews[1].ID)
assert.EqualValues(t, "REQUEST_REVIEW", reviews[1].State)
- assert.EqualValues(t, 0, reviews[0].CodeCommentsCount)
+ assert.Equal(t, 0, reviews[0].CodeCommentsCount)
assert.False(t, reviews[1].Stale)
assert.True(t, reviews[1].Official)
assert.EqualValues(t, 1, reviews[1].Reviewer.ID)
diff --git a/tests/integration/api_pull_test.go b/tests/integration/api_pull_test.go
index 969e110895..f2df6021e1 100644
--- a/tests/integration/api_pull_test.go
+++ b/tests/integration/api_pull_test.go
@@ -5,11 +5,13 @@ package integration
import (
"bytes"
- "context"
"fmt"
"io"
"net/http"
+ "net/url"
+ "strings"
"testing"
+ "time"
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
@@ -18,11 +20,15 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/services/convert"
"code.gitea.io/gitea/services/forms"
"code.gitea.io/gitea/services/gitdiff"
issue_service "code.gitea.io/gitea/services/issue"
+ pull_service "code.gitea.io/gitea/services/pull"
+ files_service "code.gitea.io/gitea/services/repository/files"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
@@ -51,30 +57,30 @@ func TestAPIViewPulls(t *testing.T) {
assert.Empty(t, pull.RequestedReviewersTeams)
assert.EqualValues(t, 5, pull.RequestedReviewers[0].ID)
assert.EqualValues(t, 6, pull.RequestedReviewers[1].ID)
- assert.EqualValues(t, 1, pull.ChangedFiles)
if assert.EqualValues(t, 5, pull.ID) {
resp = ctx.Session.MakeRequest(t, NewRequest(t, "GET", pull.DiffURL), http.StatusOK)
bs, err := io.ReadAll(resp.Body)
assert.NoError(t, err)
- patch, err := gitdiff.ParsePatch(context.Background(), 1000, 5000, 10, bytes.NewReader(bs), "")
+ patch, err := gitdiff.ParsePatch(t.Context(), 1000, 5000, 10, bytes.NewReader(bs), "")
assert.NoError(t, err)
- if assert.Len(t, patch.Files, pull.ChangedFiles) {
+ if assert.Len(t, patch.Files, 1) {
assert.Equal(t, "File-WoW", patch.Files[0].Name)
// FIXME: The old name should be empty if it's a file add type
assert.Equal(t, "File-WoW", patch.Files[0].OldName)
- assert.EqualValues(t, pull.Additions, patch.Files[0].Addition)
- assert.EqualValues(t, pull.Deletions, patch.Files[0].Deletion)
+ assert.Equal(t, 1, patch.Files[0].Addition)
+ assert.Equal(t, 0, patch.Files[0].Deletion)
assert.Equal(t, gitdiff.DiffFileAdd, patch.Files[0].Type)
}
t.Run(fmt.Sprintf("APIGetPullFiles_%d", pull.ID),
doAPIGetPullFiles(ctx, pull, func(t *testing.T, files []*api.ChangedFile) {
- if assert.Len(t, files, pull.ChangedFiles) {
+ if assert.Len(t, files, 1) {
assert.Equal(t, "File-WoW", files[0].Filename)
assert.Empty(t, files[0].PreviousFilename)
- assert.EqualValues(t, pull.Additions, files[0].Additions)
- assert.EqualValues(t, pull.Deletions, files[0].Deletions)
+ assert.Equal(t, 1, files[0].Additions)
+ assert.Equal(t, 1, files[0].Changes)
+ assert.Equal(t, 0, files[0].Deletions)
assert.Equal(t, "added", files[0].Status)
}
}))
@@ -88,53 +94,51 @@ func TestAPIViewPulls(t *testing.T) {
assert.EqualValues(t, 4, pull.RequestedReviewers[1].ID)
assert.EqualValues(t, 2, pull.RequestedReviewers[2].ID)
assert.EqualValues(t, 5, pull.RequestedReviewers[3].ID)
- assert.EqualValues(t, 1, pull.ChangedFiles)
if assert.EqualValues(t, 2, pull.ID) {
resp = ctx.Session.MakeRequest(t, NewRequest(t, "GET", pull.DiffURL), http.StatusOK)
bs, err := io.ReadAll(resp.Body)
assert.NoError(t, err)
- patch, err := gitdiff.ParsePatch(context.Background(), 1000, 5000, 10, bytes.NewReader(bs), "")
+ patch, err := gitdiff.ParsePatch(t.Context(), 1000, 5000, 10, bytes.NewReader(bs), "")
assert.NoError(t, err)
- if assert.Len(t, patch.Files, pull.ChangedFiles) {
+ if assert.Len(t, patch.Files, 1) {
assert.Equal(t, "README.md", patch.Files[0].Name)
assert.Equal(t, "README.md", patch.Files[0].OldName)
- assert.EqualValues(t, pull.Additions, patch.Files[0].Addition)
- assert.EqualValues(t, pull.Deletions, patch.Files[0].Deletion)
+ assert.Equal(t, 4, patch.Files[0].Addition)
+ assert.Equal(t, 1, patch.Files[0].Deletion)
assert.Equal(t, gitdiff.DiffFileChange, patch.Files[0].Type)
}
t.Run(fmt.Sprintf("APIGetPullFiles_%d", pull.ID),
doAPIGetPullFiles(ctx, pull, func(t *testing.T, files []*api.ChangedFile) {
- if assert.Len(t, files, pull.ChangedFiles) {
+ if assert.Len(t, files, 1) {
assert.Equal(t, "README.md", files[0].Filename)
// FIXME: The PreviousFilename name should be the same as Filename if it's a file change
- assert.Equal(t, "", files[0].PreviousFilename)
- assert.EqualValues(t, pull.Additions, files[0].Additions)
- assert.EqualValues(t, pull.Deletions, files[0].Deletions)
+ assert.Empty(t, files[0].PreviousFilename)
+ assert.Equal(t, 4, files[0].Additions)
+ assert.Equal(t, 1, files[0].Deletions)
assert.Equal(t, "changed", files[0].Status)
}
}))
}
- pull = pulls[2]
+ pull = pulls[0]
assert.EqualValues(t, 1, pull.Poster.ID)
- assert.Len(t, pull.RequestedReviewers, 1)
+ assert.Len(t, pull.RequestedReviewers, 2)
assert.Empty(t, pull.RequestedReviewersTeams)
- assert.EqualValues(t, 1, pull.RequestedReviewers[0].ID)
- assert.EqualValues(t, 0, pull.ChangedFiles)
+ assert.EqualValues(t, 5, pull.RequestedReviewers[0].ID)
- if assert.EqualValues(t, 1, pull.ID) {
+ if assert.EqualValues(t, 5, pull.ID) {
resp = ctx.Session.MakeRequest(t, NewRequest(t, "GET", pull.DiffURL), http.StatusOK)
bs, err := io.ReadAll(resp.Body)
assert.NoError(t, err)
- patch, err := gitdiff.ParsePatch(context.Background(), 1000, 5000, 10, bytes.NewReader(bs), "")
+ patch, err := gitdiff.ParsePatch(t.Context(), 1000, 5000, 10, bytes.NewReader(bs), "")
assert.NoError(t, err)
- assert.EqualValues(t, pull.ChangedFiles, patch.NumFiles)
+ assert.Len(t, patch.Files, 1)
t.Run(fmt.Sprintf("APIGetPullFiles_%d", pull.ID),
doAPIGetPullFiles(ctx, pull, func(t *testing.T, files []*api.ChangedFile) {
- assert.Len(t, files, pull.ChangedFiles)
+ assert.Len(t, files, 1)
}))
}
}
@@ -196,7 +200,7 @@ func TestAPICreatePullSuccess(t *testing.T) {
session := loginUser(t, owner11.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls", owner10.Name, repo10.Name), &api.CreatePullRequestOption{
- Head: fmt.Sprintf("%s:master", owner11.Name),
+ Head: owner11.Name + ":master",
Base: "master",
Title: "create a failure pr",
}).AddTokenAuth(token)
@@ -216,7 +220,7 @@ func TestAPICreatePullBasePermission(t *testing.T) {
session := loginUser(t, user4.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
opts := &api.CreatePullRequestOption{
- Head: fmt.Sprintf("%s:master", repo11.OwnerName),
+ Head: repo11.OwnerName + ":master",
Base: "master",
Title: "create a failure pr",
}
@@ -244,7 +248,7 @@ func TestAPICreatePullHeadPermission(t *testing.T) {
session := loginUser(t, user4.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
opts := &api.CreatePullRequestOption{
- Head: fmt.Sprintf("%s:master", repo11.OwnerName),
+ Head: repo11.OwnerName + ":master",
Base: "master",
Title: "create a failure pr",
}
@@ -272,7 +276,7 @@ func TestAPICreatePullSameRepoSuccess(t *testing.T) {
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls", owner.Name, repo.Name), &api.CreatePullRequestOption{
- Head: fmt.Sprintf("%s:pr-to-update", owner.Name),
+ Head: owner.Name + ":pr-to-update",
Base: "master",
Title: "successfully create a PR between branches of the same repository",
}).AddTokenAuth(token)
@@ -293,7 +297,7 @@ func TestAPICreatePullWithFieldsSuccess(t *testing.T) {
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
opts := &api.CreatePullRequestOption{
- Head: fmt.Sprintf("%s:master", owner11.Name),
+ Head: owner11.Name + ":master",
Base: "master",
Title: "create a failure pr",
Body: "foobaaar",
@@ -310,12 +314,12 @@ func TestAPICreatePullWithFieldsSuccess(t *testing.T) {
DecodeJSON(t, res, pull)
assert.NotNil(t, pull.Milestone)
- assert.EqualValues(t, opts.Milestone, pull.Milestone.ID)
+ assert.Equal(t, opts.Milestone, pull.Milestone.ID)
if assert.Len(t, pull.Assignees, 1) {
- assert.EqualValues(t, opts.Assignees[0], owner10.Name)
+ assert.Equal(t, opts.Assignees[0], owner10.Name)
}
assert.NotNil(t, pull.Labels)
- assert.EqualValues(t, opts.Labels[0], pull.Labels[0].ID)
+ assert.Equal(t, opts.Labels[0], pull.Labels[0].ID)
}
func TestAPICreatePullWithFieldsFailure(t *testing.T) {
@@ -331,7 +335,7 @@ func TestAPICreatePullWithFieldsFailure(t *testing.T) {
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
opts := &api.CreatePullRequestOption{
- Head: fmt.Sprintf("%s:master", owner11.Name),
+ Head: owner11.Name + ":master",
Base: "master",
}
@@ -369,7 +373,7 @@ func TestAPIEditPull(t *testing.T) {
apiPull := new(api.PullRequest)
resp := MakeRequest(t, req, http.StatusCreated)
DecodeJSON(t, resp, apiPull)
- assert.EqualValues(t, "master", apiPull.Base.Name)
+ assert.Equal(t, "master", apiPull.Base.Name)
newTitle := "edit a this pr"
newBody := "edited body"
@@ -380,7 +384,7 @@ func TestAPIEditPull(t *testing.T) {
}).AddTokenAuth(token)
resp = MakeRequest(t, req, http.StatusCreated)
DecodeJSON(t, resp, apiPull)
- assert.EqualValues(t, "feature/1", apiPull.Base.Name)
+ assert.Equal(t, "feature/1", apiPull.Base.Name)
// check comment history
pull := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: apiPull.ID})
err := pull.LoadIssue(db.DefaultContext)
@@ -427,3 +431,94 @@ func TestAPICommitPullRequest(t *testing.T) {
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/commits/%s/pull", owner.Name, repo.Name, invalidCommitSHA).AddTokenAuth(ctx.Token)
ctx.Session.MakeRequest(t, req, http.StatusNotFound)
}
+
+func TestAPIViewPullFilesWithHeadRepoDeleted(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+ user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
+
+ ctx := NewAPITestContext(t, "user1", baseRepo.Name, auth_model.AccessTokenScopeAll)
+
+ doAPIForkRepository(ctx, "user2")(t)
+
+ forkedRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ForkID: baseRepo.ID, OwnerName: "user1"})
+
+ // add a new file to the forked repo
+ addFileToForkedResp, err := files_service.ChangeRepoFiles(git.DefaultContext, forkedRepo, user1, &files_service.ChangeRepoFilesOptions{
+ Files: []*files_service.ChangeRepoFile{
+ {
+ Operation: "create",
+ TreePath: "file_1.txt",
+ ContentReader: strings.NewReader("file1"),
+ },
+ },
+ Message: "add file1",
+ OldBranch: "master",
+ NewBranch: "fork-branch-1",
+ Author: &files_service.IdentityOptions{
+ GitUserName: user1.Name,
+ GitUserEmail: user1.Email,
+ },
+ Committer: &files_service.IdentityOptions{
+ GitUserName: user1.Name,
+ GitUserEmail: user1.Email,
+ },
+ Dates: &files_service.CommitDateOptions{
+ Author: time.Now(),
+ Committer: time.Now(),
+ },
+ })
+ assert.NoError(t, err)
+ assert.NotEmpty(t, addFileToForkedResp)
+
+ // create Pull
+ pullIssue := &issues_model.Issue{
+ RepoID: baseRepo.ID,
+ Title: "Test pull-request-target-event",
+ PosterID: user1.ID,
+ Poster: user1,
+ IsPull: true,
+ }
+ pullRequest := &issues_model.PullRequest{
+ HeadRepoID: forkedRepo.ID,
+ BaseRepoID: baseRepo.ID,
+ HeadBranch: "fork-branch-1",
+ BaseBranch: "master",
+ HeadRepo: forkedRepo,
+ BaseRepo: baseRepo,
+ Type: issues_model.PullRequestGitea,
+ }
+
+ prOpts := &pull_service.NewPullRequestOptions{Repo: baseRepo, Issue: pullIssue, PullRequest: pullRequest}
+ err = pull_service.NewPullRequest(git.DefaultContext, prOpts)
+ assert.NoError(t, err)
+ pr := convert.ToAPIPullRequest(t.Context(), pullRequest, user1)
+
+ ctx = NewAPITestContext(t, "user2", baseRepo.Name, auth_model.AccessTokenScopeAll)
+ doAPIGetPullFiles(ctx, pr, func(t *testing.T, files []*api.ChangedFile) {
+ if assert.Len(t, files, 1) {
+ assert.Equal(t, "file_1.txt", files[0].Filename)
+ assert.Empty(t, files[0].PreviousFilename)
+ assert.Equal(t, 1, files[0].Additions)
+ assert.Equal(t, 1, files[0].Changes)
+ assert.Equal(t, 0, files[0].Deletions)
+ assert.Equal(t, "added", files[0].Status)
+ }
+ })(t)
+
+ // delete the head repository of the pull request
+ forkCtx := NewAPITestContext(t, "user1", forkedRepo.Name, auth_model.AccessTokenScopeAll)
+ doAPIDeleteRepository(forkCtx)(t)
+
+ doAPIGetPullFiles(ctx, pr, func(t *testing.T, files []*api.ChangedFile) {
+ if assert.Len(t, files, 1) {
+ assert.Equal(t, "file_1.txt", files[0].Filename)
+ assert.Empty(t, files[0].PreviousFilename)
+ assert.Equal(t, 1, files[0].Additions)
+ assert.Equal(t, 1, files[0].Changes)
+ assert.Equal(t, 0, files[0].Deletions)
+ assert.Equal(t, "added", files[0].Status)
+ }
+ })(t)
+ })
+}
diff --git a/tests/integration/api_releases_test.go b/tests/integration/api_releases_test.go
index b3d4928b7b..a3dbc0363b 100644
--- a/tests/integration/api_releases_test.go
+++ b/tests/integration/api_releases_test.go
@@ -97,7 +97,7 @@ func createNewReleaseUsingAPI(t *testing.T, token string, owner *user_model.User
Title: newRelease.Title,
}
unittest.AssertExistsAndLoadBean(t, rel)
- assert.EqualValues(t, newRelease.Note, rel.Note)
+ assert.Equal(t, newRelease.Note, rel.Note)
return &newRelease
}
@@ -151,7 +151,7 @@ func TestAPICreateAndUpdateRelease(t *testing.T) {
Title: newRelease.Title,
}
unittest.AssertExistsAndLoadBean(t, rel)
- assert.EqualValues(t, rel.Note, newRelease.Note)
+ assert.Equal(t, rel.Note, newRelease.Note)
}
func TestAPICreateProtectedTagRelease(t *testing.T) {
@@ -329,7 +329,7 @@ func TestAPIUploadAssetRelease(t *testing.T) {
var attachment *api.Attachment
DecodeJSON(t, resp, &attachment)
- assert.EqualValues(t, filename, attachment.Name)
+ assert.Equal(t, filename, attachment.Name)
assert.EqualValues(t, 104, attachment.Size)
req = NewRequestWithBody(t, http.MethodPost, assetURL+"?name=test-asset", bytes.NewReader(body.Bytes())).
@@ -340,7 +340,7 @@ func TestAPIUploadAssetRelease(t *testing.T) {
var attachment2 *api.Attachment
DecodeJSON(t, resp, &attachment2)
- assert.EqualValues(t, "test-asset", attachment2.Name)
+ assert.Equal(t, "test-asset", attachment2.Name)
assert.EqualValues(t, 104, attachment2.Size)
})
@@ -358,7 +358,7 @@ func TestAPIUploadAssetRelease(t *testing.T) {
var attachment *api.Attachment
DecodeJSON(t, resp, &attachment)
- assert.EqualValues(t, "stream.bin", attachment.Name)
+ assert.Equal(t, "stream.bin", attachment.Name)
assert.EqualValues(t, 104, attachment.Size)
})
}
diff --git a/tests/integration/api_repo_archive_test.go b/tests/integration/api_repo_archive_test.go
index 8589199da3..97c2c0d54b 100644
--- a/tests/integration/api_repo_archive_test.go
+++ b/tests/integration/api_repo_archive_test.go
@@ -12,7 +12,9 @@ import (
"testing"
auth_model "code.gitea.io/gitea/models/auth"
+ "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/tests"
@@ -48,7 +50,7 @@ func TestAPIDownloadArchive(t *testing.T) {
bs2, err := io.ReadAll(resp.Body)
assert.NoError(t, err)
// The locked URL should give the same bytes as the non-locked one
- assert.EqualValues(t, bs, bs2)
+ assert.Equal(t, bs, bs2)
link, _ = url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/archive/master.bundle", user2.Name, repo.Name))
resp = MakeRequest(t, NewRequest(t, "GET", link.String()).AddTokenAuth(token), http.StatusOK)
@@ -58,9 +60,12 @@ func TestAPIDownloadArchive(t *testing.T) {
link, _ = url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/archive/master", user2.Name, repo.Name))
MakeRequest(t, NewRequest(t, "GET", link.String()).AddTokenAuth(token), http.StatusBadRequest)
+
+ t.Run("GitHubStyle", testAPIDownloadArchiveGitHubStyle)
+ t.Run("PrivateRepo", testAPIDownloadArchivePrivateRepo)
}
-func TestAPIDownloadArchive2(t *testing.T) {
+func testAPIDownloadArchiveGitHubStyle(t *testing.T) {
defer tests.PrepareTestEnv(t)()
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
@@ -88,14 +93,20 @@ func TestAPIDownloadArchive2(t *testing.T) {
bs2, err := io.ReadAll(resp.Body)
assert.NoError(t, err)
// The locked URL should give the same bytes as the non-locked one
- assert.EqualValues(t, bs, bs2)
+ assert.Equal(t, bs, bs2)
link, _ = url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/bundle/master", user2.Name, repo.Name))
resp = MakeRequest(t, NewRequest(t, "GET", link.String()).AddTokenAuth(token), http.StatusOK)
bs, err = io.ReadAll(resp.Body)
assert.NoError(t, err)
assert.Len(t, bs, 382)
+}
- link, _ = url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/archive/master", user2.Name, repo.Name))
- MakeRequest(t, NewRequest(t, "GET", link.String()).AddTokenAuth(token), http.StatusBadRequest)
+func testAPIDownloadArchivePrivateRepo(t *testing.T) {
+ _ = repo_model.UpdateRepositoryColsNoAutoTime(t.Context(), &repo_model.Repository{ID: 1, IsPrivate: true}, "is_private")
+ MakeRequest(t, NewRequest(t, "HEAD", "/api/v1/repos/user2/repo1/archive/master.zip"), http.StatusNotFound)
+ MakeRequest(t, NewRequest(t, "HEAD", "/api/v1/repos/user2/repo1/zipball/master"), http.StatusNotFound)
+ _ = repo_model.UpdateRepoUnitPublicAccess(t.Context(), &repo_model.RepoUnit{RepoID: 1, Type: unit.TypeCode, AnonymousAccessMode: perm.AccessModeRead})
+ MakeRequest(t, NewRequest(t, "HEAD", "/api/v1/repos/user2/repo1/archive/master.zip"), http.StatusOK)
+ MakeRequest(t, NewRequest(t, "HEAD", "/api/v1/repos/user2/repo1/zipball/master"), http.StatusOK)
}
diff --git a/tests/integration/api_repo_branch_test.go b/tests/integration/api_repo_branch_test.go
index 63080b308c..066eb366b1 100644
--- a/tests/integration/api_repo_branch_test.go
+++ b/tests/integration/api_repo_branch_test.go
@@ -4,11 +4,11 @@
package integration
import (
- "bytes"
"fmt"
"io"
"net/http"
"net/url"
+ "strings"
"testing"
auth_model "code.gitea.io/gitea/models/auth"
@@ -42,8 +42,8 @@ func TestAPIRepoBranchesPlain(t *testing.T) {
var branches []*api.Branch
assert.NoError(t, json.Unmarshal(bs, &branches))
assert.Len(t, branches, 2)
- assert.EqualValues(t, "test_branch", branches[0].Name)
- assert.EqualValues(t, "master", branches[1].Name)
+ assert.Equal(t, "test_branch", branches[0].Name)
+ assert.Equal(t, "master", branches[1].Name)
link2, _ := url.Parse(fmt.Sprintf("/api/v1/repos/org3/%s/branches/test_branch", repo3.Name))
MakeRequest(t, NewRequest(t, "GET", link2.String()).AddTokenAuth(publicOnlyToken), http.StatusForbidden)
@@ -53,20 +53,20 @@ func TestAPIRepoBranchesPlain(t *testing.T) {
assert.NoError(t, err)
var branch api.Branch
assert.NoError(t, json.Unmarshal(bs, &branch))
- assert.EqualValues(t, "test_branch", branch.Name)
+ assert.Equal(t, "test_branch", branch.Name)
MakeRequest(t, NewRequest(t, "POST", link.String()).AddTokenAuth(publicOnlyToken), http.StatusForbidden)
req := NewRequest(t, "POST", link.String()).AddTokenAuth(token)
req.Header.Add("Content-Type", "application/json")
- req.Body = io.NopCloser(bytes.NewBufferString(`{"new_branch_name":"test_branch2", "old_branch_name": "test_branch", "old_ref_name":"refs/heads/test_branch"}`))
+ req.Body = io.NopCloser(strings.NewReader(`{"new_branch_name":"test_branch2", "old_branch_name": "test_branch", "old_ref_name":"refs/heads/test_branch"}`))
resp = MakeRequest(t, req, http.StatusCreated)
bs, err = io.ReadAll(resp.Body)
assert.NoError(t, err)
var branch2 api.Branch
assert.NoError(t, json.Unmarshal(bs, &branch2))
- assert.EqualValues(t, "test_branch2", branch2.Name)
- assert.EqualValues(t, branch.Commit.ID, branch2.Commit.ID)
+ assert.Equal(t, "test_branch2", branch2.Name)
+ assert.Equal(t, branch.Commit.ID, branch2.Commit.ID)
resp = MakeRequest(t, NewRequest(t, "GET", link.String()).AddTokenAuth(token), http.StatusOK)
bs, err = io.ReadAll(resp.Body)
@@ -75,9 +75,9 @@ func TestAPIRepoBranchesPlain(t *testing.T) {
branches = []*api.Branch{}
assert.NoError(t, json.Unmarshal(bs, &branches))
assert.Len(t, branches, 3)
- assert.EqualValues(t, "test_branch", branches[0].Name)
- assert.EqualValues(t, "test_branch2", branches[1].Name)
- assert.EqualValues(t, "master", branches[2].Name)
+ assert.Equal(t, "test_branch", branches[0].Name)
+ assert.Equal(t, "test_branch2", branches[1].Name)
+ assert.Equal(t, "master", branches[2].Name)
link3, _ := url.Parse(fmt.Sprintf("/api/v1/repos/org3/%s/branches/test_branch2", repo3.Name))
MakeRequest(t, NewRequest(t, "DELETE", link3.String()), http.StatusNotFound)
@@ -104,8 +104,8 @@ func TestAPIRepoBranchesMirror(t *testing.T) {
var branches []*api.Branch
assert.NoError(t, json.Unmarshal(bs, &branches))
assert.Len(t, branches, 2)
- assert.EqualValues(t, "test_branch", branches[0].Name)
- assert.EqualValues(t, "master", branches[1].Name)
+ assert.Equal(t, "test_branch", branches[0].Name)
+ assert.Equal(t, "master", branches[1].Name)
link2, _ := url.Parse(fmt.Sprintf("/api/v1/repos/org3/%s/branches/test_branch", repo5.Name))
resp = MakeRequest(t, NewRequest(t, "GET", link2.String()).AddTokenAuth(token), http.StatusOK)
@@ -113,18 +113,18 @@ func TestAPIRepoBranchesMirror(t *testing.T) {
assert.NoError(t, err)
var branch api.Branch
assert.NoError(t, json.Unmarshal(bs, &branch))
- assert.EqualValues(t, "test_branch", branch.Name)
+ assert.Equal(t, "test_branch", branch.Name)
req := NewRequest(t, "POST", link.String()).AddTokenAuth(token)
req.Header.Add("Content-Type", "application/json")
- req.Body = io.NopCloser(bytes.NewBufferString(`{"new_branch_name":"test_branch2", "old_branch_name": "test_branch", "old_ref_name":"refs/heads/test_branch"}`))
+ req.Body = io.NopCloser(strings.NewReader(`{"new_branch_name":"test_branch2", "old_branch_name": "test_branch", "old_ref_name":"refs/heads/test_branch"}`))
resp = MakeRequest(t, req, http.StatusForbidden)
bs, err = io.ReadAll(resp.Body)
assert.NoError(t, err)
- assert.EqualValues(t, "{\"message\":\"Git Repository is a mirror.\",\"url\":\""+setting.AppURL+"api/swagger\"}\n", string(bs))
+ assert.Equal(t, "{\"message\":\"Git Repository is a mirror.\",\"url\":\""+setting.AppURL+"api/swagger\"}\n", string(bs))
resp = MakeRequest(t, NewRequest(t, "DELETE", link2.String()).AddTokenAuth(token), http.StatusForbidden)
bs, err = io.ReadAll(resp.Body)
assert.NoError(t, err)
- assert.EqualValues(t, "{\"message\":\"Git Repository is a mirror.\",\"url\":\""+setting.AppURL+"api/swagger\"}\n", string(bs))
+ assert.Equal(t, "{\"message\":\"Git Repository is a mirror.\",\"url\":\""+setting.AppURL+"api/swagger\"}\n", string(bs))
}
diff --git a/tests/integration/api_repo_collaborator_test.go b/tests/integration/api_repo_collaborator_test.go
index 463db1dfb1..11e2924e84 100644
--- a/tests/integration/api_repo_collaborator_test.go
+++ b/tests/integration/api_repo_collaborator_test.go
@@ -5,7 +5,6 @@ package integration
import (
"net/http"
- "net/url"
"testing"
auth_model "code.gitea.io/gitea/models/auth"
@@ -14,132 +13,145 @@ import (
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
)
func TestAPIRepoCollaboratorPermission(t *testing.T) {
- onGiteaRun(t, func(t *testing.T, u *url.URL) {
- repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
- repo2Owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo2.OwnerID})
+ defer tests.PrepareTestEnv(t)()
+ repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
+ repo2Owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo2.OwnerID})
- user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
- user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
- user10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 10})
- user11 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 11})
- user34 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 34})
+ user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
+ user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
+ user10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 10})
+ user11 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 11})
+ user34 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 34})
- testCtx := NewAPITestContext(t, repo2Owner.Name, repo2.Name, auth_model.AccessTokenScopeWriteRepository)
+ testCtx := NewAPITestContext(t, repo2Owner.Name, repo2.Name, auth_model.AccessTokenScopeWriteRepository)
- t.Run("RepoOwnerShouldBeOwner", func(t *testing.T) {
- req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, repo2Owner.Name).
- AddTokenAuth(testCtx.Token)
- resp := MakeRequest(t, req, http.StatusOK)
+ t.Run("RepoOwnerShouldBeOwner", func(t *testing.T) {
+ req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, repo2Owner.Name).
+ AddTokenAuth(testCtx.Token)
+ resp := MakeRequest(t, req, http.StatusOK)
- var repoPermission api.RepoCollaboratorPermission
- DecodeJSON(t, resp, &repoPermission)
+ var repoPermission api.RepoCollaboratorPermission
+ DecodeJSON(t, resp, &repoPermission)
- assert.Equal(t, "owner", repoPermission.Permission)
- })
+ assert.Equal(t, "owner", repoPermission.Permission)
+ })
- t.Run("CollaboratorWithReadAccess", func(t *testing.T) {
- t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user4.Name, perm.AccessModeRead))
+ t.Run("CollaboratorWithReadAccess", func(t *testing.T) {
+ t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user4.Name, perm.AccessModeRead))
- req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user4.Name).
- AddTokenAuth(testCtx.Token)
- resp := MakeRequest(t, req, http.StatusOK)
+ req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user4.Name).
+ AddTokenAuth(testCtx.Token)
+ resp := MakeRequest(t, req, http.StatusOK)
- var repoPermission api.RepoCollaboratorPermission
- DecodeJSON(t, resp, &repoPermission)
+ var repoPermission api.RepoCollaboratorPermission
+ DecodeJSON(t, resp, &repoPermission)
- assert.Equal(t, "read", repoPermission.Permission)
- })
+ assert.Equal(t, "read", repoPermission.Permission)
+ })
- t.Run("CollaboratorWithWriteAccess", func(t *testing.T) {
- t.Run("AddUserAsCollaboratorWithWriteAccess", doAPIAddCollaborator(testCtx, user4.Name, perm.AccessModeWrite))
+ t.Run("CollaboratorWithWriteAccess", func(t *testing.T) {
+ t.Run("AddUserAsCollaboratorWithWriteAccess", doAPIAddCollaborator(testCtx, user4.Name, perm.AccessModeWrite))
- req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user4.Name).
- AddTokenAuth(testCtx.Token)
- resp := MakeRequest(t, req, http.StatusOK)
+ req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user4.Name).
+ AddTokenAuth(testCtx.Token)
+ resp := MakeRequest(t, req, http.StatusOK)
- var repoPermission api.RepoCollaboratorPermission
- DecodeJSON(t, resp, &repoPermission)
+ var repoPermission api.RepoCollaboratorPermission
+ DecodeJSON(t, resp, &repoPermission)
- assert.Equal(t, "write", repoPermission.Permission)
- })
+ assert.Equal(t, "write", repoPermission.Permission)
+ })
- t.Run("CollaboratorWithAdminAccess", func(t *testing.T) {
- t.Run("AddUserAsCollaboratorWithAdminAccess", doAPIAddCollaborator(testCtx, user4.Name, perm.AccessModeAdmin))
+ t.Run("CollaboratorWithAdminAccess", func(t *testing.T) {
+ t.Run("AddUserAsCollaboratorWithAdminAccess", doAPIAddCollaborator(testCtx, user4.Name, perm.AccessModeAdmin))
- req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user4.Name).
- AddTokenAuth(testCtx.Token)
- resp := MakeRequest(t, req, http.StatusOK)
+ req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user4.Name).
+ AddTokenAuth(testCtx.Token)
+ resp := MakeRequest(t, req, http.StatusOK)
- var repoPermission api.RepoCollaboratorPermission
- DecodeJSON(t, resp, &repoPermission)
+ var repoPermission api.RepoCollaboratorPermission
+ DecodeJSON(t, resp, &repoPermission)
- assert.Equal(t, "admin", repoPermission.Permission)
- })
+ assert.Equal(t, "admin", repoPermission.Permission)
+ })
- t.Run("CollaboratorNotFound", func(t *testing.T) {
- req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, "non-existent-user").
- AddTokenAuth(testCtx.Token)
- MakeRequest(t, req, http.StatusNotFound)
- })
+ t.Run("CollaboratorNotFound", func(t *testing.T) {
+ req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, "non-existent-user").
+ AddTokenAuth(testCtx.Token)
+ MakeRequest(t, req, http.StatusNotFound)
+ })
- t.Run("CollaboratorBlocked", func(t *testing.T) {
- ctx := NewAPITestContext(t, repo2Owner.Name, repo2.Name, auth_model.AccessTokenScopeWriteRepository)
- ctx.ExpectedCode = http.StatusForbidden
- doAPIAddCollaborator(ctx, user34.Name, perm.AccessModeAdmin)(t)
- })
+ t.Run("CollaboratorBlocked", func(t *testing.T) {
+ ctx := NewAPITestContext(t, repo2Owner.Name, repo2.Name, auth_model.AccessTokenScopeWriteRepository)
+ ctx.ExpectedCode = http.StatusForbidden
+ doAPIAddCollaborator(ctx, user34.Name, perm.AccessModeAdmin)(t)
+ })
+
+ t.Run("CollaboratorCanQueryItsPermissions", func(t *testing.T) {
+ t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user5.Name, perm.AccessModeRead))
+
+ _session := loginUser(t, user5.Name)
+ _testCtx := NewAPITestContext(t, user5.Name, repo2.Name, auth_model.AccessTokenScopeReadRepository)
+
+ req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user5.Name).
+ AddTokenAuth(_testCtx.Token)
+ resp := _session.MakeRequest(t, req, http.StatusOK)
- t.Run("CollaboratorCanQueryItsPermissions", func(t *testing.T) {
- t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user5.Name, perm.AccessModeRead))
+ var repoPermission api.RepoCollaboratorPermission
+ DecodeJSON(t, resp, &repoPermission)
- _session := loginUser(t, user5.Name)
- _testCtx := NewAPITestContext(t, user5.Name, repo2.Name, auth_model.AccessTokenScopeReadRepository)
+ assert.Equal(t, "read", repoPermission.Permission)
- req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user5.Name).
- AddTokenAuth(_testCtx.Token)
- resp := _session.MakeRequest(t, req, http.StatusOK)
+ t.Run("CollaboratorCanReadOwnPermission", func(t *testing.T) {
+ session := loginUser(t, user5.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository)
- var repoPermission api.RepoCollaboratorPermission
- DecodeJSON(t, resp, &repoPermission)
+ req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user5.Name).AddTokenAuth(token)
+ resp = MakeRequest(t, req, http.StatusOK)
- assert.Equal(t, "read", repoPermission.Permission)
+ repoCollPerm := api.RepoCollaboratorPermission{}
+ DecodeJSON(t, resp, &repoCollPerm)
+
+ assert.Equal(t, "read", repoCollPerm.Permission)
})
+ })
- t.Run("CollaboratorCanQueryItsPermissions", func(t *testing.T) {
- t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user5.Name, perm.AccessModeRead))
+ t.Run("CollaboratorCanQueryItsPermissions", func(t *testing.T) {
+ t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user5.Name, perm.AccessModeRead))
- _session := loginUser(t, user5.Name)
- _testCtx := NewAPITestContext(t, user5.Name, repo2.Name, auth_model.AccessTokenScopeReadRepository)
+ _session := loginUser(t, user5.Name)
+ _testCtx := NewAPITestContext(t, user5.Name, repo2.Name, auth_model.AccessTokenScopeReadRepository)
- req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user5.Name).
- AddTokenAuth(_testCtx.Token)
- resp := _session.MakeRequest(t, req, http.StatusOK)
+ req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user5.Name).
+ AddTokenAuth(_testCtx.Token)
+ resp := _session.MakeRequest(t, req, http.StatusOK)
- var repoPermission api.RepoCollaboratorPermission
- DecodeJSON(t, resp, &repoPermission)
+ var repoPermission api.RepoCollaboratorPermission
+ DecodeJSON(t, resp, &repoPermission)
- assert.Equal(t, "read", repoPermission.Permission)
- })
+ assert.Equal(t, "read", repoPermission.Permission)
+ })
- t.Run("RepoAdminCanQueryACollaboratorsPermissions", func(t *testing.T) {
- t.Run("AddUserAsCollaboratorWithAdminAccess", doAPIAddCollaborator(testCtx, user10.Name, perm.AccessModeAdmin))
- t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user11.Name, perm.AccessModeRead))
+ t.Run("RepoAdminCanQueryACollaboratorsPermissions", func(t *testing.T) {
+ t.Run("AddUserAsCollaboratorWithAdminAccess", doAPIAddCollaborator(testCtx, user10.Name, perm.AccessModeAdmin))
+ t.Run("AddUserAsCollaboratorWithReadAccess", doAPIAddCollaborator(testCtx, user11.Name, perm.AccessModeRead))
- _session := loginUser(t, user10.Name)
- _testCtx := NewAPITestContext(t, user10.Name, repo2.Name, auth_model.AccessTokenScopeReadRepository)
+ _session := loginUser(t, user10.Name)
+ _testCtx := NewAPITestContext(t, user10.Name, repo2.Name, auth_model.AccessTokenScopeReadRepository)
- req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user11.Name).
- AddTokenAuth(_testCtx.Token)
- resp := _session.MakeRequest(t, req, http.StatusOK)
+ req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/collaborators/%s/permission", repo2Owner.Name, repo2.Name, user11.Name).
+ AddTokenAuth(_testCtx.Token)
+ resp := _session.MakeRequest(t, req, http.StatusOK)
- var repoPermission api.RepoCollaboratorPermission
- DecodeJSON(t, resp, &repoPermission)
+ var repoPermission api.RepoCollaboratorPermission
+ DecodeJSON(t, resp, &repoPermission)
- assert.Equal(t, "read", repoPermission.Permission)
- })
+ assert.Equal(t, "read", repoPermission.Permission)
})
}
diff --git a/tests/integration/api_repo_edit_test.go b/tests/integration/api_repo_edit_test.go
index 7de8910ee0..7fe59c0d09 100644
--- a/tests/integration/api_repo_edit_test.go
+++ b/tests/integration/api_repo_edit_test.go
@@ -53,9 +53,8 @@ func getRepoEditOptionFromRepo(repo *repo_model.Repository) *api.EditRepoOption
hasWiki = true
} else if unit, err := repo.GetUnit(db.DefaultContext, unit_model.TypeExternalWiki); err == nil {
hasWiki = true
- config := unit.ExternalWikiConfig()
externalWiki = &api.ExternalWiki{
- ExternalWikiURL: config.ExternalWikiURL,
+ ExternalWikiURL: unit.ExternalWikiConfig().ExternalWikiURL,
}
}
defaultBranch := repo.DefaultBranch
@@ -77,12 +76,36 @@ func getRepoEditOptionFromRepo(repo *repo_model.Repository) *api.EditRepoOption
allowFastForwardOnly = config.AllowFastForwardOnly
}
archived := repo.IsArchived
+ hasProjects := false
+ var projectsMode *string
+ if unit, err := repo.GetUnit(db.DefaultContext, unit_model.TypeProjects); err == nil && unit != nil {
+ hasProjects = true
+ pm := string(unit.ProjectsConfig().ProjectsMode)
+ projectsMode = &pm
+ }
+ hasCode := repo.UnitEnabled(db.DefaultContext, unit_model.TypeCode)
+ hasPackages := repo.UnitEnabled(db.DefaultContext, unit_model.TypePackages)
+ hasReleases := repo.UnitEnabled(db.DefaultContext, unit_model.TypeReleases)
+ hasActions := false
+ if unit, err := repo.GetUnit(db.DefaultContext, unit_model.TypeActions); err == nil && unit != nil {
+ hasActions = true
+ // TODO: expose action config of repo to api
+ // actionsConfig = &api.RepoActionsConfig{
+ // DisabledWorkflows: unit.ActionsConfig().DisabledWorkflows,
+ // }
+ }
return &api.EditRepoOption{
Name: &name,
Description: &description,
Website: &website,
Private: &private,
HasIssues: &hasIssues,
+ HasProjects: &hasProjects,
+ ProjectsMode: projectsMode,
+ HasCode: &hasCode,
+ HasPackages: &hasPackages,
+ HasReleases: &hasReleases,
+ HasActions: &hasActions,
ExternalTracker: externalTracker,
InternalTracker: internalTracker,
HasWiki: &hasWiki,
@@ -109,6 +132,11 @@ func getNewRepoEditOption(opts *api.EditRepoOption) *api.EditRepoOption {
private := !*opts.Private
hasIssues := !*opts.HasIssues
hasWiki := !*opts.HasWiki
+ hasProjects := !*opts.HasProjects
+ hasCode := !*opts.HasCode
+ hasPackages := !*opts.HasPackages
+ hasReleases := !*opts.HasReleases
+ hasActions := !*opts.HasActions
defaultBranch := "master"
hasPullRequests := !*opts.HasPullRequests
ignoreWhitespaceConflicts := !*opts.IgnoreWhitespaceConflicts
@@ -126,6 +154,11 @@ func getNewRepoEditOption(opts *api.EditRepoOption) *api.EditRepoOption {
DefaultBranch: &defaultBranch,
HasIssues: &hasIssues,
HasWiki: &hasWiki,
+ HasProjects: &hasProjects,
+ HasCode: &hasCode,
+ HasPackages: &hasPackages,
+ HasReleases: &hasReleases,
+ HasActions: &hasActions,
HasPullRequests: &hasPullRequests,
IgnoreWhitespaceConflicts: &ignoreWhitespaceConflicts,
AllowMerge: &allowMerge,
@@ -157,6 +190,11 @@ func TestAPIRepoEdit(t *testing.T) {
// Test editing a repo1 which user2 owns, changing name and many properties
origRepoEditOption := getRepoEditOptionFromRepo(repo1)
+ assert.True(t, *origRepoEditOption.HasCode)
+ assert.True(t, *origRepoEditOption.HasPackages)
+ assert.True(t, *origRepoEditOption.HasProjects)
+ assert.True(t, *origRepoEditOption.HasReleases)
+ assert.True(t, *origRepoEditOption.HasActions)
repoEditOption := getNewRepoEditOption(origRepoEditOption)
req := NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/repos/%s/%s", user2.Name, repo1.Name), &repoEditOption).
AddTokenAuth(token2)
@@ -178,6 +216,11 @@ func TestAPIRepoEdit(t *testing.T) {
assert.Equal(t, *repoEditOption.Archived, *repo1editedOption.Archived)
assert.Equal(t, *repoEditOption.Private, *repo1editedOption.Private)
assert.Equal(t, *repoEditOption.HasWiki, *repo1editedOption.HasWiki)
+ assert.Equal(t, *repoEditOption.HasCode, *repo1editedOption.HasCode)
+ assert.Equal(t, *repoEditOption.HasPackages, *repo1editedOption.HasPackages)
+ assert.Equal(t, *repoEditOption.HasProjects, *repo1editedOption.HasProjects)
+ assert.Equal(t, *repoEditOption.HasReleases, *repo1editedOption.HasReleases)
+ assert.Equal(t, *repoEditOption.HasActions, *repo1editedOption.HasActions)
// Test editing repo1 to use internal issue and wiki (default)
*repoEditOption.HasIssues = true
@@ -225,6 +268,11 @@ func TestAPIRepoEdit(t *testing.T) {
assert.Equal(t, *repo1editedOption.ExternalTracker, *repoEditOption.ExternalTracker)
assert.True(t, *repo1editedOption.HasWiki)
assert.Equal(t, *repo1editedOption.ExternalWiki, *repoEditOption.ExternalWiki)
+ assert.False(t, *repo1editedOption.HasCode)
+ assert.False(t, *repo1editedOption.HasPackages)
+ assert.False(t, *repo1editedOption.HasProjects)
+ assert.False(t, *repo1editedOption.HasReleases)
+ assert.False(t, *repo1editedOption.HasActions)
repoEditOption.ExternalTracker.ExternalTrackerStyle = "regexp"
repoEditOption.ExternalTracker.ExternalTrackerRegexpPattern = `(\d+)`
@@ -273,6 +321,11 @@ func TestAPIRepoEdit(t *testing.T) {
assert.NotNil(t, *repo1editedOption.ExternalTracker)
assert.True(t, *repo1editedOption.HasWiki)
assert.NotNil(t, *repo1editedOption.ExternalWiki)
+ assert.False(t, *repo1editedOption.HasCode)
+ assert.False(t, *repo1editedOption.HasPackages)
+ assert.False(t, *repo1editedOption.HasProjects)
+ assert.False(t, *repo1editedOption.HasReleases)
+ assert.False(t, *repo1editedOption.HasActions)
// reset repo in db
req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/repos/%s/%s", user2.Name, *repoEditOption.Name), &origRepoEditOption).
diff --git a/tests/integration/api_repo_file_create_test.go b/tests/integration/api_repo_file_create_test.go
index 41ad7211ff..af3bc54680 100644
--- a/tests/integration/api_repo_file_create_test.go
+++ b/tests/integration/api_repo_file_create_test.go
@@ -4,12 +4,11 @@
package integration
import (
- stdCtx "context"
"encoding/base64"
"fmt"
"net/http"
"net/url"
- "path/filepath"
+ "path"
"testing"
"time"
@@ -20,6 +19,7 @@ import (
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/context"
"github.com/stretchr/testify/assert"
@@ -50,28 +50,42 @@ func getCreateFileOptions() api.CreateFileOptions {
}
}
-func getExpectedFileResponseForCreate(repoFullName, commitID, treePath, latestCommitSHA string) *api.FileResponse {
+func normalizeFileContentResponseCommitTime(c *api.ContentsResponse) {
+ // decoded JSON response may contain different timezone from the one parsed by git commit
+ // so we need to normalize the time to UTC to make "assert.Equal" pass
+ c.LastCommitterDate = util.ToPointer(c.LastCommitterDate.UTC())
+ c.LastAuthorDate = util.ToPointer(c.LastAuthorDate.UTC())
+}
+
+type apiFileResponseInfo struct {
+ repoFullName, commitID, treePath, lastCommitSHA string
+ lastCommitterWhen, lastAuthorWhen time.Time
+}
+
+func getExpectedFileResponseForCreate(info apiFileResponseInfo) *api.FileResponse {
sha := "a635aa942442ddfdba07468cf9661c08fbdf0ebf"
encoding := "base64"
content := "VGhpcyBpcyBuZXcgdGV4dA=="
- selfURL := setting.AppURL + "api/v1/repos/" + repoFullName + "/contents/" + treePath + "?ref=master"
- htmlURL := setting.AppURL + repoFullName + "/src/branch/master/" + treePath
- gitURL := setting.AppURL + "api/v1/repos/" + repoFullName + "/git/blobs/" + sha
- downloadURL := setting.AppURL + repoFullName + "/raw/branch/master/" + treePath
- return &api.FileResponse{
+ selfURL := setting.AppURL + "api/v1/repos/" + info.repoFullName + "/contents/" + info.treePath + "?ref=master"
+ htmlURL := setting.AppURL + info.repoFullName + "/src/branch/master/" + info.treePath
+ gitURL := setting.AppURL + "api/v1/repos/" + info.repoFullName + "/git/blobs/" + sha
+ downloadURL := setting.AppURL + info.repoFullName + "/raw/branch/master/" + info.treePath
+ ret := &api.FileResponse{
Content: &api.ContentsResponse{
- Name: filepath.Base(treePath),
- Path: treePath,
- SHA: sha,
- LastCommitSHA: latestCommitSHA,
- Size: 16,
- Type: "file",
- Encoding: &encoding,
- Content: &content,
- URL: &selfURL,
- HTMLURL: &htmlURL,
- GitURL: &gitURL,
- DownloadURL: &downloadURL,
+ Name: path.Base(info.treePath),
+ Path: info.treePath,
+ SHA: sha,
+ LastCommitSHA: util.ToPointer(info.lastCommitSHA),
+ LastCommitterDate: util.ToPointer(info.lastCommitterWhen),
+ LastAuthorDate: util.ToPointer(info.lastAuthorWhen),
+ Size: 16,
+ Type: "file",
+ Encoding: &encoding,
+ Content: &content,
+ URL: &selfURL,
+ HTMLURL: &htmlURL,
+ GitURL: &gitURL,
+ DownloadURL: &downloadURL,
Links: &api.FileLinksResponse{
Self: &selfURL,
GitURL: &gitURL,
@@ -80,10 +94,10 @@ func getExpectedFileResponseForCreate(repoFullName, commitID, treePath, latestCo
},
Commit: &api.FileCommitResponse{
CommitMeta: api.CommitMeta{
- URL: setting.AppURL + "api/v1/repos/" + repoFullName + "/git/commits/" + commitID,
- SHA: commitID,
+ URL: setting.AppURL + "api/v1/repos/" + info.repoFullName + "/git/commits/" + info.commitID,
+ SHA: info.commitID,
},
- HTMLURL: setting.AppURL + repoFullName + "/commit/" + commitID,
+ HTMLURL: setting.AppURL + info.repoFullName + "/commit/" + info.commitID,
Author: &api.CommitUser{
Identity: api.Identity{
Name: "Anne Doe",
@@ -107,6 +121,8 @@ func getExpectedFileResponseForCreate(repoFullName, commitID, treePath, latestCo
Payload: "",
},
}
+ normalizeFileContentResponseCommitTime(ret.Content)
+ return ret
}
func BenchmarkAPICreateFileSmall(b *testing.B) {
@@ -115,7 +131,7 @@ func BenchmarkAPICreateFileSmall(b *testing.B) {
repo1 := unittest.AssertExistsAndLoadBean(b, &repo_model.Repository{ID: 1}) // public repo
b.ResetTimer()
- for n := 0; n < b.N; n++ {
+ for n := 0; b.Loop(); n++ {
treePath := fmt.Sprintf("update/file%d.txt", n)
_, _ = createFileInBranch(user2, repo1, treePath, repo1.DefaultBranch, treePath)
}
@@ -130,7 +146,7 @@ func BenchmarkAPICreateFileMedium(b *testing.B) {
repo1 := unittest.AssertExistsAndLoadBean(b, &repo_model.Repository{ID: 1}) // public repo
b.ResetTimer()
- for n := 0; n < b.N; n++ {
+ for n := 0; b.Loop(); n++ {
treePath := fmt.Sprintf("update/file%d.txt", n)
copy(data, treePath)
_, _ = createFileInBranch(user2, repo1, treePath, repo1.DefaultBranch, treePath)
@@ -167,22 +183,30 @@ func TestAPICreateFile(t *testing.T) {
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user2.Name, repo1.Name, treePath), &createFileOptions).
AddTokenAuth(token2)
resp := MakeRequest(t, req, http.StatusCreated)
- gitRepo, _ := gitrepo.OpenRepository(stdCtx.Background(), repo1)
+ gitRepo, _ := gitrepo.OpenRepository(t.Context(), repo1)
+ defer gitRepo.Close()
commitID, _ := gitRepo.GetBranchCommitID(createFileOptions.NewBranchName)
- latestCommit, _ := gitRepo.GetCommitByPath(treePath)
- expectedFileResponse := getExpectedFileResponseForCreate("user2/repo1", commitID, treePath, latestCommit.ID.String())
+ lastCommit, _ := gitRepo.GetCommitByPath(treePath)
+ expectedFileResponse := getExpectedFileResponseForCreate(apiFileResponseInfo{
+ repoFullName: "user2/repo1",
+ commitID: commitID,
+ treePath: treePath,
+ lastCommitSHA: lastCommit.ID.String(),
+ lastCommitterWhen: lastCommit.Committer.When,
+ lastAuthorWhen: lastCommit.Author.When,
+ })
var fileResponse api.FileResponse
DecodeJSON(t, resp, &fileResponse)
- assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
- assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
- assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
- assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email)
- assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name)
- assert.EqualValues(t, expectedFileResponse.Commit.Author.Date, fileResponse.Commit.Author.Date)
- assert.EqualValues(t, expectedFileResponse.Commit.Committer.Email, fileResponse.Commit.Committer.Email)
- assert.EqualValues(t, expectedFileResponse.Commit.Committer.Name, fileResponse.Commit.Committer.Name)
- assert.EqualValues(t, expectedFileResponse.Commit.Committer.Date, fileResponse.Commit.Committer.Date)
- gitRepo.Close()
+ normalizeFileContentResponseCommitTime(fileResponse.Content)
+ assert.Equal(t, expectedFileResponse.Content, fileResponse.Content)
+ assert.Equal(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
+ assert.Equal(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
+ assert.Equal(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email)
+ assert.Equal(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name)
+ assert.Equal(t, expectedFileResponse.Commit.Author.Date, fileResponse.Commit.Author.Date)
+ assert.Equal(t, expectedFileResponse.Commit.Committer.Email, fileResponse.Commit.Committer.Email)
+ assert.Equal(t, expectedFileResponse.Commit.Committer.Name, fileResponse.Commit.Committer.Name)
+ assert.Equal(t, expectedFileResponse.Commit.Committer.Date, fileResponse.Commit.Committer.Date)
}
// Test creating a file in a new branch
@@ -199,10 +223,10 @@ func TestAPICreateFile(t *testing.T) {
expectedSHA := "a635aa942442ddfdba07468cf9661c08fbdf0ebf"
expectedHTMLURL := fmt.Sprintf(setting.AppURL+"user2/repo1/src/branch/new_branch/new/file%d.txt", fileID)
expectedDownloadURL := fmt.Sprintf(setting.AppURL+"user2/repo1/raw/branch/new_branch/new/file%d.txt", fileID)
- assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA)
- assert.EqualValues(t, expectedHTMLURL, *fileResponse.Content.HTMLURL)
- assert.EqualValues(t, expectedDownloadURL, *fileResponse.Content.DownloadURL)
- assert.EqualValues(t, createFileOptions.Message+"\n", fileResponse.Commit.Message)
+ assert.Equal(t, expectedSHA, fileResponse.Content.SHA)
+ assert.Equal(t, expectedHTMLURL, *fileResponse.Content.HTMLURL)
+ assert.Equal(t, expectedDownloadURL, *fileResponse.Content.DownloadURL)
+ assert.Equal(t, createFileOptions.Message+"\n", fileResponse.Commit.Message)
// Test creating a file without a message
createFileOptions = getCreateFileOptions()
@@ -214,7 +238,7 @@ func TestAPICreateFile(t *testing.T) {
resp = MakeRequest(t, req, http.StatusCreated)
DecodeJSON(t, resp, &fileResponse)
expectedMessage := "Add " + treePath + "\n"
- assert.EqualValues(t, expectedMessage, fileResponse.Commit.Message)
+ assert.Equal(t, expectedMessage, fileResponse.Commit.Message)
// Test trying to create a file that already exists, should fail
createFileOptions = getCreateFileOptions()
@@ -285,20 +309,28 @@ func TestAPICreateFile(t *testing.T) {
AddTokenAuth(token2)
resp = MakeRequest(t, req, http.StatusCreated)
emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "empty-repo"}) // public repo
- gitRepo, _ := gitrepo.OpenRepository(stdCtx.Background(), emptyRepo)
+ gitRepo, _ := gitrepo.OpenRepository(t.Context(), emptyRepo)
+ defer gitRepo.Close()
commitID, _ := gitRepo.GetBranchCommitID(createFileOptions.NewBranchName)
latestCommit, _ := gitRepo.GetCommitByPath(treePath)
- expectedFileResponse := getExpectedFileResponseForCreate("user2/empty-repo", commitID, treePath, latestCommit.ID.String())
+ expectedFileResponse := getExpectedFileResponseForCreate(apiFileResponseInfo{
+ repoFullName: "user2/empty-repo",
+ commitID: commitID,
+ treePath: treePath,
+ lastCommitSHA: latestCommit.ID.String(),
+ lastCommitterWhen: latestCommit.Committer.When,
+ lastAuthorWhen: latestCommit.Author.When,
+ })
DecodeJSON(t, resp, &fileResponse)
- assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
- assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
- assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
- assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email)
- assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name)
- assert.EqualValues(t, expectedFileResponse.Commit.Author.Date, fileResponse.Commit.Author.Date)
- assert.EqualValues(t, expectedFileResponse.Commit.Committer.Email, fileResponse.Commit.Committer.Email)
- assert.EqualValues(t, expectedFileResponse.Commit.Committer.Name, fileResponse.Commit.Committer.Name)
- assert.EqualValues(t, expectedFileResponse.Commit.Committer.Date, fileResponse.Commit.Committer.Date)
- gitRepo.Close()
+ normalizeFileContentResponseCommitTime(fileResponse.Content)
+ assert.Equal(t, expectedFileResponse.Content, fileResponse.Content)
+ assert.Equal(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
+ assert.Equal(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
+ assert.Equal(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email)
+ assert.Equal(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name)
+ assert.Equal(t, expectedFileResponse.Commit.Author.Date, fileResponse.Commit.Author.Date)
+ assert.Equal(t, expectedFileResponse.Commit.Committer.Email, fileResponse.Commit.Committer.Email)
+ assert.Equal(t, expectedFileResponse.Commit.Committer.Name, fileResponse.Commit.Committer.Name)
+ assert.Equal(t, expectedFileResponse.Commit.Committer.Date, fileResponse.Commit.Committer.Date)
})
}
diff --git a/tests/integration/api_repo_file_delete_test.go b/tests/integration/api_repo_file_delete_test.go
index 7c93307e19..9dd47f93e6 100644
--- a/tests/integration/api_repo_file_delete_test.go
+++ b/tests/integration/api_repo_file_delete_test.go
@@ -20,20 +20,22 @@ import (
func getDeleteFileOptions() *api.DeleteFileOptions {
return &api.DeleteFileOptions{
- FileOptions: api.FileOptions{
- BranchName: "master",
- NewBranchName: "master",
- Message: "Removing the file new/file.txt",
- Author: api.Identity{
- Name: "John Doe",
- Email: "johndoe@example.com",
- },
- Committer: api.Identity{
- Name: "Jane Doe",
- Email: "janedoe@example.com",
+ FileOptionsWithSHA: api.FileOptionsWithSHA{
+ FileOptions: api.FileOptions{
+ BranchName: "master",
+ NewBranchName: "master",
+ Message: "Removing the file new/file.txt",
+ Author: api.Identity{
+ Name: "John Doe",
+ Email: "johndoe@example.com",
+ },
+ Committer: api.Identity{
+ Name: "Jane Doe",
+ Email: "janedoe@example.com",
+ },
},
+ SHA: "103ff9234cefeee5ec5361d22b49fbb04d385885",
},
- SHA: "103ff9234cefeee5ec5361d22b49fbb04d385885",
}
}
@@ -87,7 +89,7 @@ func TestAPIDeleteFile(t *testing.T) {
DecodeJSON(t, resp, &fileResponse)
assert.NotNil(t, fileResponse)
assert.Nil(t, fileResponse.Content)
- assert.EqualValues(t, deleteFileOptions.Message+"\n", fileResponse.Commit.Message)
+ assert.Equal(t, deleteFileOptions.Message+"\n", fileResponse.Commit.Message)
// Test deleting file without a message
fileID++
@@ -100,7 +102,7 @@ func TestAPIDeleteFile(t *testing.T) {
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &fileResponse)
expectedMessage := "Delete " + treePath + "\n"
- assert.EqualValues(t, expectedMessage, fileResponse.Commit.Message)
+ assert.Equal(t, expectedMessage, fileResponse.Commit.Message)
// Test deleting a file with the wrong SHA
fileID++
@@ -110,7 +112,7 @@ func TestAPIDeleteFile(t *testing.T) {
deleteFileOptions.SHA = "badsha"
req = NewRequestWithJSON(t, "DELETE", fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user2.Name, repo1.Name, treePath), &deleteFileOptions).
AddTokenAuth(token2)
- MakeRequest(t, req, http.StatusBadRequest)
+ MakeRequest(t, req, http.StatusUnprocessableEntity)
// Test creating a file in repo16 by user4 who does not have write access
fileID++
diff --git a/tests/integration/api_repo_file_get_test.go b/tests/integration/api_repo_file_get_test.go
index 2f897093ee..379851b689 100644
--- a/tests/integration/api_repo_file_get_test.go
+++ b/tests/integration/api_repo_file_get_test.go
@@ -44,8 +44,6 @@ func TestAPIGetRawFileOrLFS(t *testing.T) {
reqLFS := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/media/"+lfs)
respLFS := MakeRequestNilResponseRecorder(t, reqLFS, http.StatusOK)
assert.Equal(t, testFileSizeSmall, respLFS.Length)
-
- doAPIDeleteRepository(httpContext)
})
})
}
diff --git a/tests/integration/api_repo_file_update_test.go b/tests/integration/api_repo_file_update_test.go
index ac28e0c0a2..9a56711da6 100644
--- a/tests/integration/api_repo_file_update_test.go
+++ b/tests/integration/api_repo_file_update_test.go
@@ -4,12 +4,11 @@
package integration
import (
- stdCtx "context"
"encoding/base64"
"fmt"
"net/http"
"net/url"
- "path/filepath"
+ "path"
"testing"
auth_model "code.gitea.io/gitea/models/auth"
@@ -19,6 +18,7 @@ import (
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/context"
"github.com/stretchr/testify/assert"
@@ -28,7 +28,7 @@ func getUpdateFileOptions() *api.UpdateFileOptions {
content := "This is updated text"
contentEncoded := base64.StdEncoding.EncodeToString([]byte(content))
return &api.UpdateFileOptions{
- DeleteFileOptions: api.DeleteFileOptions{
+ FileOptionsWithSHA: api.FileOptionsWithSHA{
FileOptions: api.FileOptions{
BranchName: "master",
NewBranchName: "master",
@@ -48,28 +48,30 @@ func getUpdateFileOptions() *api.UpdateFileOptions {
}
}
-func getExpectedFileResponseForUpdate(commitID, treePath, lastCommitSHA string) *api.FileResponse {
+func getExpectedFileResponseForUpdate(info apiFileResponseInfo) *api.FileResponse {
sha := "08bd14b2e2852529157324de9c226b3364e76136"
encoding := "base64"
content := "VGhpcyBpcyB1cGRhdGVkIHRleHQ="
- selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath + "?ref=master"
- htmlURL := setting.AppURL + "user2/repo1/src/branch/master/" + treePath
+ selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + info.treePath + "?ref=master"
+ htmlURL := setting.AppURL + "user2/repo1/src/branch/master/" + info.treePath
gitURL := setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/" + sha
- downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + treePath
- return &api.FileResponse{
+ downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + info.treePath
+ ret := &api.FileResponse{
Content: &api.ContentsResponse{
- Name: filepath.Base(treePath),
- Path: treePath,
- SHA: sha,
- LastCommitSHA: lastCommitSHA,
- Type: "file",
- Size: 20,
- Encoding: &encoding,
- Content: &content,
- URL: &selfURL,
- HTMLURL: &htmlURL,
- GitURL: &gitURL,
- DownloadURL: &downloadURL,
+ Name: path.Base(info.treePath),
+ Path: info.treePath,
+ SHA: sha,
+ LastCommitSHA: util.ToPointer(info.lastCommitSHA),
+ LastCommitterDate: util.ToPointer(info.lastCommitterWhen),
+ LastAuthorDate: util.ToPointer(info.lastAuthorWhen),
+ Type: "file",
+ Size: 20,
+ Encoding: &encoding,
+ Content: &content,
+ URL: &selfURL,
+ HTMLURL: &htmlURL,
+ GitURL: &gitURL,
+ DownloadURL: &downloadURL,
Links: &api.FileLinksResponse{
Self: &selfURL,
GitURL: &gitURL,
@@ -78,10 +80,10 @@ func getExpectedFileResponseForUpdate(commitID, treePath, lastCommitSHA string)
},
Commit: &api.FileCommitResponse{
CommitMeta: api.CommitMeta{
- URL: setting.AppURL + "api/v1/repos/user2/repo1/git/commits/" + commitID,
- SHA: commitID,
+ URL: setting.AppURL + "api/v1/repos/user2/repo1/git/commits/" + info.commitID,
+ SHA: info.commitID,
},
- HTMLURL: setting.AppURL + "user2/repo1/commit/" + commitID,
+ HTMLURL: setting.AppURL + "user2/repo1/commit/" + info.commitID,
Author: &api.CommitUser{
Identity: api.Identity{
Name: "John Doe",
@@ -103,6 +105,8 @@ func getExpectedFileResponseForUpdate(commitID, treePath, lastCommitSHA string)
Payload: "",
},
}
+ normalizeFileContentResponseCommitTime(ret.Content)
+ return ret
}
func TestAPIUpdateFile(t *testing.T) {
@@ -135,18 +139,25 @@ func TestAPIUpdateFile(t *testing.T) {
req := NewRequestWithJSON(t, "PUT", fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", user2.Name, repo1.Name, treePath), &updateFileOptions).
AddTokenAuth(token2)
resp := MakeRequest(t, req, http.StatusOK)
- gitRepo, _ := gitrepo.OpenRepository(stdCtx.Background(), repo1)
+ gitRepo, _ := gitrepo.OpenRepository(t.Context(), repo1)
+ defer gitRepo.Close()
commitID, _ := gitRepo.GetBranchCommitID(updateFileOptions.NewBranchName)
lasCommit, _ := gitRepo.GetCommitByPath(treePath)
- expectedFileResponse := getExpectedFileResponseForUpdate(commitID, treePath, lasCommit.ID.String())
+ expectedFileResponse := getExpectedFileResponseForUpdate(apiFileResponseInfo{
+ commitID: commitID,
+ treePath: treePath,
+ lastCommitSHA: lasCommit.ID.String(),
+ lastCommitterWhen: lasCommit.Committer.When,
+ lastAuthorWhen: lasCommit.Author.When,
+ })
var fileResponse api.FileResponse
DecodeJSON(t, resp, &fileResponse)
- assert.EqualValues(t, expectedFileResponse.Content, fileResponse.Content)
- assert.EqualValues(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
- assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
- assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email)
- assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name)
- gitRepo.Close()
+ normalizeFileContentResponseCommitTime(fileResponse.Content)
+ assert.Equal(t, expectedFileResponse.Content, fileResponse.Content)
+ assert.Equal(t, expectedFileResponse.Commit.SHA, fileResponse.Commit.SHA)
+ assert.Equal(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL)
+ assert.Equal(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email)
+ assert.Equal(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name)
}
// Test updating a file in a new branch
@@ -164,10 +175,10 @@ func TestAPIUpdateFile(t *testing.T) {
expectedSHA := "08bd14b2e2852529157324de9c226b3364e76136"
expectedHTMLURL := fmt.Sprintf(setting.AppURL+"user2/repo1/src/branch/new_branch/update/file%d.txt", fileID)
expectedDownloadURL := fmt.Sprintf(setting.AppURL+"user2/repo1/raw/branch/new_branch/update/file%d.txt", fileID)
- assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA)
- assert.EqualValues(t, expectedHTMLURL, *fileResponse.Content.HTMLURL)
- assert.EqualValues(t, expectedDownloadURL, *fileResponse.Content.DownloadURL)
- assert.EqualValues(t, updateFileOptions.Message+"\n", fileResponse.Commit.Message)
+ assert.Equal(t, expectedSHA, fileResponse.Content.SHA)
+ assert.Equal(t, expectedHTMLURL, *fileResponse.Content.HTMLURL)
+ assert.Equal(t, expectedDownloadURL, *fileResponse.Content.DownloadURL)
+ assert.Equal(t, updateFileOptions.Message+"\n", fileResponse.Commit.Message)
// Test updating a file and renaming it
updateFileOptions = getUpdateFileOptions()
@@ -184,9 +195,9 @@ func TestAPIUpdateFile(t *testing.T) {
expectedSHA = "08bd14b2e2852529157324de9c226b3364e76136"
expectedHTMLURL = fmt.Sprintf(setting.AppURL+"user2/repo1/src/branch/master/rename/update/file%d.txt", fileID)
expectedDownloadURL = fmt.Sprintf(setting.AppURL+"user2/repo1/raw/branch/master/rename/update/file%d.txt", fileID)
- assert.EqualValues(t, expectedSHA, fileResponse.Content.SHA)
- assert.EqualValues(t, expectedHTMLURL, *fileResponse.Content.HTMLURL)
- assert.EqualValues(t, expectedDownloadURL, *fileResponse.Content.DownloadURL)
+ assert.Equal(t, expectedSHA, fileResponse.Content.SHA)
+ assert.Equal(t, expectedHTMLURL, *fileResponse.Content.HTMLURL)
+ assert.Equal(t, expectedDownloadURL, *fileResponse.Content.DownloadURL)
// Test updating a file without a message
updateFileOptions = getUpdateFileOptions()
@@ -200,7 +211,7 @@ func TestAPIUpdateFile(t *testing.T) {
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &fileResponse)
expectedMessage := "Update " + treePath + "\n"
- assert.EqualValues(t, expectedMessage, fileResponse.Commit.Message)
+ assert.Equal(t, expectedMessage, fileResponse.Commit.Message)
// Test updating a file with the wrong SHA
fileID++
diff --git a/tests/integration/api_repo_files_change_test.go b/tests/integration/api_repo_files_change_test.go
index fb3ae5e4dd..999bcdc680 100644
--- a/tests/integration/api_repo_files_change_test.go
+++ b/tests/integration/api_repo_files_change_test.go
@@ -4,7 +4,6 @@
package integration
import (
- stdCtx "context"
"encoding/base64"
"fmt"
"net/http"
@@ -78,51 +77,56 @@ func TestAPIChangeFiles(t *testing.T) {
token4 := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
// Test changing files in repo1 which user2 owns, try both with branch and empty branch
- for _, branch := range [...]string{
- "master", // Branch
- "", // Empty branch
- } {
- fileID++
- createTreePath := fmt.Sprintf("new/file%d.txt", fileID)
- updateTreePath := fmt.Sprintf("update/file%d.txt", fileID)
- deleteTreePath := fmt.Sprintf("delete/file%d.txt", fileID)
- createFile(user2, repo1, updateTreePath)
- createFile(user2, repo1, deleteTreePath)
- changeFilesOptions := getChangeFilesOptions()
- changeFilesOptions.BranchName = branch
- changeFilesOptions.Files[0].Path = createTreePath
- changeFilesOptions.Files[1].Path = updateTreePath
- changeFilesOptions.Files[2].Path = deleteTreePath
- req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/contents", user2.Name, repo1.Name), &changeFilesOptions).
- AddTokenAuth(token2)
- resp := MakeRequest(t, req, http.StatusCreated)
- gitRepo, _ := gitrepo.OpenRepository(stdCtx.Background(), repo1)
- commitID, _ := gitRepo.GetBranchCommitID(changeFilesOptions.NewBranchName)
- createLasCommit, _ := gitRepo.GetCommitByPath(createTreePath)
- updateLastCommit, _ := gitRepo.GetCommitByPath(updateTreePath)
- expectedCreateFileResponse := getExpectedFileResponseForCreate(fmt.Sprintf("%v/%v", user2.Name, repo1.Name), commitID, createTreePath, createLasCommit.ID.String())
- expectedUpdateFileResponse := getExpectedFileResponseForUpdate(commitID, updateTreePath, updateLastCommit.ID.String())
- var filesResponse api.FilesResponse
- DecodeJSON(t, resp, &filesResponse)
-
- // check create file
- assert.EqualValues(t, expectedCreateFileResponse.Content, filesResponse.Files[0])
-
- // check update file
- assert.EqualValues(t, expectedUpdateFileResponse.Content, filesResponse.Files[1])
-
- // test commit info
- assert.EqualValues(t, expectedCreateFileResponse.Commit.SHA, filesResponse.Commit.SHA)
- assert.EqualValues(t, expectedCreateFileResponse.Commit.HTMLURL, filesResponse.Commit.HTMLURL)
- assert.EqualValues(t, expectedCreateFileResponse.Commit.Author.Email, filesResponse.Commit.Author.Email)
- assert.EqualValues(t, expectedCreateFileResponse.Commit.Author.Name, filesResponse.Commit.Author.Name)
- assert.EqualValues(t, expectedCreateFileResponse.Commit.Committer.Email, filesResponse.Commit.Committer.Email)
- assert.EqualValues(t, expectedCreateFileResponse.Commit.Committer.Name, filesResponse.Commit.Committer.Name)
-
- // test delete file
- assert.Nil(t, filesResponse.Files[2])
-
- gitRepo.Close()
+ for _, branch := range []string{"master", ""} {
+ t.Run("Branch-"+branch, func(t *testing.T) {
+ fileID++
+ createTreePath := fmt.Sprintf("new/file%d.txt", fileID)
+ updateTreePath := fmt.Sprintf("update/file%d.txt", fileID)
+ deleteTreePath := fmt.Sprintf("delete/file%d.txt", fileID)
+ _, _ = createFile(user2, repo1, updateTreePath)
+ _, _ = createFile(user2, repo1, deleteTreePath)
+ changeFilesOptions := getChangeFilesOptions()
+ changeFilesOptions.BranchName = branch
+ changeFilesOptions.Files[0].Path = createTreePath
+ changeFilesOptions.Files[1].Path = updateTreePath
+ changeFilesOptions.Files[2].Path = deleteTreePath
+ req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/contents", user2.Name, repo1.Name), &changeFilesOptions).
+ AddTokenAuth(token2)
+ resp := MakeRequest(t, req, http.StatusCreated)
+ gitRepo, _ := gitrepo.OpenRepository(t.Context(), repo1)
+ defer gitRepo.Close()
+ commitID, _ := gitRepo.GetBranchCommitID(changeFilesOptions.NewBranchName)
+ createLasCommit, _ := gitRepo.GetCommitByPath(createTreePath)
+ updateLastCommit, _ := gitRepo.GetCommitByPath(updateTreePath)
+ expectedCreateFileResponse := getExpectedFileResponseForCreate(apiFileResponseInfo{
+ repoFullName: fmt.Sprintf("%s/%s", user2.Name, repo1.Name),
+ commitID: commitID,
+ treePath: createTreePath,
+ lastCommitSHA: createLasCommit.ID.String(),
+ lastCommitterWhen: createLasCommit.Committer.When,
+ lastAuthorWhen: createLasCommit.Author.When,
+ })
+ expectedUpdateFileResponse := getExpectedFileResponseForUpdate(apiFileResponseInfo{
+ commitID: commitID,
+ treePath: updateTreePath,
+ lastCommitSHA: updateLastCommit.ID.String(),
+ lastCommitterWhen: updateLastCommit.Committer.When,
+ lastAuthorWhen: updateLastCommit.Author.When,
+ })
+ var filesResponse api.FilesResponse
+ DecodeJSON(t, resp, &filesResponse)
+ normalizeFileContentResponseCommitTime(filesResponse.Files[0])
+ normalizeFileContentResponseCommitTime(filesResponse.Files[1])
+ assert.Equal(t, expectedCreateFileResponse.Content, filesResponse.Files[0]) // check create file
+ assert.Equal(t, expectedUpdateFileResponse.Content, filesResponse.Files[1]) // check update file
+ assert.Equal(t, expectedCreateFileResponse.Commit.SHA, filesResponse.Commit.SHA)
+ assert.Equal(t, expectedCreateFileResponse.Commit.HTMLURL, filesResponse.Commit.HTMLURL)
+ assert.Equal(t, expectedCreateFileResponse.Commit.Author.Email, filesResponse.Commit.Author.Email)
+ assert.Equal(t, expectedCreateFileResponse.Commit.Author.Name, filesResponse.Commit.Author.Name)
+ assert.Equal(t, expectedCreateFileResponse.Commit.Committer.Email, filesResponse.Commit.Committer.Email)
+ assert.Equal(t, expectedCreateFileResponse.Commit.Committer.Name, filesResponse.Commit.Committer.Name)
+ assert.Nil(t, filesResponse.Files[2]) // test delete file
+ })
}
// Test changing files in a new branch
@@ -150,15 +154,15 @@ func TestAPIChangeFiles(t *testing.T) {
expectedUpdateSHA := "08bd14b2e2852529157324de9c226b3364e76136"
expectedUpdateHTMLURL := fmt.Sprintf(setting.AppURL+"user2/repo1/src/branch/new_branch/update/file%d.txt", fileID)
expectedUpdateDownloadURL := fmt.Sprintf(setting.AppURL+"user2/repo1/raw/branch/new_branch/update/file%d.txt", fileID)
- assert.EqualValues(t, expectedCreateSHA, filesResponse.Files[0].SHA)
- assert.EqualValues(t, expectedCreateHTMLURL, *filesResponse.Files[0].HTMLURL)
- assert.EqualValues(t, expectedCreateDownloadURL, *filesResponse.Files[0].DownloadURL)
- assert.EqualValues(t, expectedUpdateSHA, filesResponse.Files[1].SHA)
- assert.EqualValues(t, expectedUpdateHTMLURL, *filesResponse.Files[1].HTMLURL)
- assert.EqualValues(t, expectedUpdateDownloadURL, *filesResponse.Files[1].DownloadURL)
+ assert.Equal(t, expectedCreateSHA, filesResponse.Files[0].SHA)
+ assert.Equal(t, expectedCreateHTMLURL, *filesResponse.Files[0].HTMLURL)
+ assert.Equal(t, expectedCreateDownloadURL, *filesResponse.Files[0].DownloadURL)
+ assert.Equal(t, expectedUpdateSHA, filesResponse.Files[1].SHA)
+ assert.Equal(t, expectedUpdateHTMLURL, *filesResponse.Files[1].HTMLURL)
+ assert.Equal(t, expectedUpdateDownloadURL, *filesResponse.Files[1].DownloadURL)
assert.Nil(t, filesResponse.Files[2])
- assert.EqualValues(t, changeFilesOptions.Message+"\n", filesResponse.Commit.Message)
+ assert.Equal(t, changeFilesOptions.Message+"\n", filesResponse.Commit.Message)
// Test updating a file and renaming it
changeFilesOptions = getChangeFilesOptions()
@@ -176,9 +180,9 @@ func TestAPIChangeFiles(t *testing.T) {
expectedUpdateSHA = "08bd14b2e2852529157324de9c226b3364e76136"
expectedUpdateHTMLURL = fmt.Sprintf(setting.AppURL+"user2/repo1/src/branch/master/rename/update/file%d.txt", fileID)
expectedUpdateDownloadURL = fmt.Sprintf(setting.AppURL+"user2/repo1/raw/branch/master/rename/update/file%d.txt", fileID)
- assert.EqualValues(t, expectedUpdateSHA, filesResponse.Files[0].SHA)
- assert.EqualValues(t, expectedUpdateHTMLURL, *filesResponse.Files[0].HTMLURL)
- assert.EqualValues(t, expectedUpdateDownloadURL, *filesResponse.Files[0].DownloadURL)
+ assert.Equal(t, expectedUpdateSHA, filesResponse.Files[0].SHA)
+ assert.Equal(t, expectedUpdateHTMLURL, *filesResponse.Files[0].HTMLURL)
+ assert.Equal(t, expectedUpdateDownloadURL, *filesResponse.Files[0].DownloadURL)
// Test updating a file without a message
changeFilesOptions = getChangeFilesOptions()
@@ -198,7 +202,7 @@ func TestAPIChangeFiles(t *testing.T) {
resp = MakeRequest(t, req, http.StatusCreated)
DecodeJSON(t, resp, &filesResponse)
expectedMessage := fmt.Sprintf("Add %v\nUpdate %v\nDelete %v\n", createTreePath, updateTreePath, deleteTreePath)
- assert.EqualValues(t, expectedMessage, filesResponse.Commit.Message)
+ assert.Equal(t, expectedMessage, filesResponse.Commit.Message)
// Test updating a file with the wrong SHA
fileID++
diff --git a/tests/integration/api_repo_files_get_test.go b/tests/integration/api_repo_files_get_test.go
new file mode 100644
index 0000000000..a4ded7da3f
--- /dev/null
+++ b/tests/integration/api_repo_files_get_test.go
@@ -0,0 +1,157 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package integration
+
+import (
+ "fmt"
+ "net/http"
+ "net/url"
+ "testing"
+
+ auth_model "code.gitea.io/gitea/models/auth"
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/gitrepo"
+ "code.gitea.io/gitea/modules/json"
+ "code.gitea.io/gitea/modules/setting"
+ api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/test"
+ "code.gitea.io/gitea/modules/util"
+ "code.gitea.io/gitea/tests"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestAPIGetRequestedFiles(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16
+ org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the repo3, is an org
+ user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // owner of neither repos
+ repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo
+ repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // public repo
+ repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) // private repo
+
+ // Get user2's token
+ session := loginUser(t, user2.Name)
+ token2 := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+ // Get user4's token
+ session = loginUser(t, user4.Name)
+ token4 := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo1)
+ assert.NoError(t, err)
+ defer gitRepo.Close()
+ lastCommit, _ := gitRepo.GetCommitByPath("README.md")
+
+ requestFiles := func(t *testing.T, url string, files []string, expectedStatusCode ...int) (ret []*api.ContentsResponse) {
+ req := NewRequestWithJSON(t, "POST", url, &api.GetFilesOptions{Files: files})
+ resp := MakeRequest(t, req, util.OptionalArg(expectedStatusCode, http.StatusOK))
+ if resp.Code != http.StatusOK {
+ return nil
+ }
+ DecodeJSON(t, resp, &ret)
+ return ret
+ }
+
+ t.Run("User2Get", func(t *testing.T) {
+ reqBodyOpt := &api.GetFilesOptions{Files: []string{"README.md"}}
+ reqBodyParam, _ := json.Marshal(reqBodyOpt)
+ req := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/file-contents?body="+url.QueryEscape(string(reqBodyParam)))
+ resp := MakeRequest(t, req, http.StatusOK)
+ var ret []*api.ContentsResponse
+ DecodeJSON(t, resp, &ret)
+ expected := []*api.ContentsResponse{getExpectedContentsResponseForContents(repo1.DefaultBranch, "branch", lastCommit.ID.String())}
+ assert.Equal(t, expected, ret)
+ })
+ t.Run("User2NoRef", func(t *testing.T) {
+ ret := requestFiles(t, "/api/v1/repos/user2/repo1/file-contents", []string{"README.md"})
+ expected := []*api.ContentsResponse{getExpectedContentsResponseForContents(repo1.DefaultBranch, "branch", lastCommit.ID.String())}
+ assert.Equal(t, expected, ret)
+ })
+ t.Run("User2RefBranch", func(t *testing.T) {
+ ret := requestFiles(t, "/api/v1/repos/user2/repo1/file-contents?ref=master", []string{"README.md"})
+ expected := []*api.ContentsResponse{getExpectedContentsResponseForContents(repo1.DefaultBranch, "branch", lastCommit.ID.String())}
+ assert.Equal(t, expected, ret)
+ })
+ t.Run("User2RefTag", func(t *testing.T) {
+ ret := requestFiles(t, "/api/v1/repos/user2/repo1/file-contents?ref=v1.1", []string{"README.md"})
+ expected := []*api.ContentsResponse{getExpectedContentsResponseForContents("v1.1", "tag", lastCommit.ID.String())}
+ assert.Equal(t, expected, ret)
+ })
+ t.Run("User2RefCommit", func(t *testing.T) {
+ ret := requestFiles(t, "/api/v1/repos/user2/repo1/file-contents?ref=65f1bf27bc3bf70f64657658635e66094edbcb4d", []string{"README.md"})
+ expected := []*api.ContentsResponse{getExpectedContentsResponseForContents("65f1bf27bc3bf70f64657658635e66094edbcb4d", "commit", lastCommit.ID.String())}
+ assert.Equal(t, expected, ret)
+ })
+ t.Run("User2RefNotExist", func(t *testing.T) {
+ ret := requestFiles(t, "/api/v1/repos/user2/repo1/file-contents?ref=not-exist", []string{"README.md"}, http.StatusNotFound)
+ assert.Empty(t, ret)
+ })
+
+ t.Run("PermissionCheck", func(t *testing.T) {
+ filesOptions := &api.GetFilesOptions{Files: []string{"README.md"}}
+ // Test accessing private ref with user token that does not have access - should fail
+ req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/file-contents", user2.Name, repo16.Name), &filesOptions).AddTokenAuth(token4)
+ MakeRequest(t, req, http.StatusNotFound)
+ // Test access private ref of owner of token
+ req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/file-contents", user2.Name, repo16.Name), &filesOptions).AddTokenAuth(token2)
+ MakeRequest(t, req, http.StatusOK)
+ // Test access of org org3 private repo file by owner user2
+ req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/file-contents", org3.Name, repo3.Name), &filesOptions).AddTokenAuth(token2)
+ MakeRequest(t, req, http.StatusOK)
+ })
+
+ t.Run("ResponseList", func(t *testing.T) {
+ defer test.MockVariableValue(&setting.API.DefaultPagingNum)()
+ defer test.MockVariableValue(&setting.API.DefaultMaxBlobSize)()
+ defer test.MockVariableValue(&setting.API.DefaultMaxResponseSize)()
+
+ type expected struct {
+ Name string
+ HasContent bool
+ }
+ assertResponse := func(t *testing.T, expected []*expected, ret []*api.ContentsResponse) {
+ require.Len(t, ret, len(expected))
+ for i, e := range expected {
+ if e == nil {
+ assert.Nil(t, ret[i], "item %d", i)
+ continue
+ }
+ assert.Equal(t, e.Name, ret[i].Name, "item %d name", i)
+ if e.HasContent {
+ require.NotNil(t, ret[i].Content, "item %d content", i)
+ assert.NotEmpty(t, *ret[i].Content, "item %d content", i)
+ } else {
+ assert.Nil(t, ret[i].Content, "item %d content", i)
+ }
+ }
+ }
+
+ // repo1 "DefaultBranch" has 2 files: LICENSE (1064 bytes), README.md (30 bytes)
+ ret := requestFiles(t, "/api/v1/repos/user2/repo1/file-contents?ref=DefaultBranch", []string{"no-such.txt", "LICENSE", "README.md"})
+ assertResponse(t, []*expected{nil, {"LICENSE", true}, {"README.md", true}}, ret)
+
+ // the returned file list is limited by the DefaultPagingNum
+ setting.API.DefaultPagingNum = 2
+ ret = requestFiles(t, "/api/v1/repos/user2/repo1/file-contents?ref=DefaultBranch", []string{"no-such.txt", "LICENSE", "README.md"})
+ assertResponse(t, []*expected{nil, {"LICENSE", true}}, ret)
+ setting.API.DefaultPagingNum = 100
+
+ // if a file exceeds the DefaultMaxBlobSize, the content is not returned
+ setting.API.DefaultMaxBlobSize = 200
+ ret = requestFiles(t, "/api/v1/repos/user2/repo1/file-contents?ref=DefaultBranch", []string{"no-such.txt", "LICENSE", "README.md"})
+ assertResponse(t, []*expected{nil, {"LICENSE", false}, {"README.md", true}}, ret)
+ setting.API.DefaultMaxBlobSize = 20000
+
+ // if the total response size would exceed the DefaultMaxResponseSize, then the list stops
+ setting.API.DefaultMaxResponseSize = ret[1].Size*4/3 + 10
+ ret = requestFiles(t, "/api/v1/repos/user2/repo1/file-contents?ref=DefaultBranch", []string{"no-such.txt", "LICENSE", "README.md"})
+ assertResponse(t, []*expected{nil, {"LICENSE", true}}, ret)
+ setting.API.DefaultMaxBlobSize = 20000
+ })
+}
diff --git a/tests/integration/api_repo_get_contents_list_test.go b/tests/integration/api_repo_get_contents_list_test.go
index 1ba74490a3..563d6fcc10 100644
--- a/tests/integration/api_repo_get_contents_list_test.go
+++ b/tests/integration/api_repo_get_contents_list_test.go
@@ -6,8 +6,9 @@ package integration
import (
"net/http"
"net/url"
- "path/filepath"
+ "path"
"testing"
+ "time"
auth_model "code.gitea.io/gitea/models/auth"
repo_model "code.gitea.io/gitea/models/repo"
@@ -17,6 +18,7 @@ import (
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/util"
repo_service "code.gitea.io/gitea/services/repository"
"github.com/stretchr/testify/assert"
@@ -31,16 +33,18 @@ func getExpectedContentsListResponseForContents(ref, refType, lastCommitSHA stri
downloadURL := setting.AppURL + "user2/repo1/raw/" + refType + "/" + ref + "/" + treePath
return []*api.ContentsResponse{
{
- Name: filepath.Base(treePath),
- Path: treePath,
- SHA: sha,
- LastCommitSHA: lastCommitSHA,
- Type: "file",
- Size: 30,
- URL: &selfURL,
- HTMLURL: &htmlURL,
- GitURL: &gitURL,
- DownloadURL: &downloadURL,
+ Name: path.Base(treePath),
+ Path: treePath,
+ SHA: sha,
+ LastCommitSHA: util.ToPointer(lastCommitSHA),
+ LastCommitterDate: util.ToPointer(time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400))),
+ LastAuthorDate: util.ToPointer(time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400))),
+ Type: "file",
+ Size: 30,
+ URL: &selfURL,
+ HTMLURL: &htmlURL,
+ GitURL: &gitURL,
+ DownloadURL: &downloadURL,
Links: &api.FileLinksResponse{
Self: &selfURL,
GitURL: &gitURL,
@@ -62,7 +66,6 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // public repo
repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) // private repo
- treePath := "" // root dir
// Get user2's token
session := loginUser(t, user2.Name)
@@ -91,7 +94,7 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
// ref is default ref
ref := repo1.DefaultBranch
refType := "branch"
- req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
+ req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents?ref=%s", user2.Name, repo1.Name, ref)
resp := MakeRequest(t, req, http.StatusOK)
var contentsListResponse []*api.ContentsResponse
DecodeJSON(t, resp, &contentsListResponse)
@@ -99,22 +102,22 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
lastCommit, err := gitRepo.GetCommitByPath("README.md")
assert.NoError(t, err)
expectedContentsListResponse := getExpectedContentsListResponseForContents(ref, refType, lastCommit.ID.String())
- assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
+ assert.Equal(t, expectedContentsListResponse, contentsListResponse)
// No ref
refType = "branch"
- req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s", user2.Name, repo1.Name, treePath)
+ req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/", user2.Name, repo1.Name)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &contentsListResponse)
assert.NotNil(t, contentsListResponse)
expectedContentsListResponse = getExpectedContentsListResponseForContents(repo1.DefaultBranch, refType, lastCommit.ID.String())
- assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
+ assert.Equal(t, expectedContentsListResponse, contentsListResponse)
// ref is the branch we created above in setup
ref = newBranch
refType = "branch"
- req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
+ req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents?ref=%s", user2.Name, repo1.Name, ref)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &contentsListResponse)
assert.NotNil(t, contentsListResponse)
@@ -123,12 +126,12 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
lastCommit, err = branchCommit.GetCommitByPath("README.md")
assert.NoError(t, err)
expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType, lastCommit.ID.String())
- assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
+ assert.Equal(t, expectedContentsListResponse, contentsListResponse)
// ref is the new tag we created above in setup
ref = newTag
refType = "tag"
- req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
+ req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/?ref=%s", user2.Name, repo1.Name, ref)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &contentsListResponse)
assert.NotNil(t, contentsListResponse)
@@ -137,35 +140,35 @@ func testAPIGetContentsList(t *testing.T, u *url.URL) {
lastCommit, err = tagCommit.GetCommitByPath("README.md")
assert.NoError(t, err)
expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType, lastCommit.ID.String())
- assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
+ assert.Equal(t, expectedContentsListResponse, contentsListResponse)
// ref is a commit
ref = commitID
refType = "commit"
- req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
+ req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/?ref=%s", user2.Name, repo1.Name, ref)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &contentsListResponse)
assert.NotNil(t, contentsListResponse)
expectedContentsListResponse = getExpectedContentsListResponseForContents(ref, refType, commitID)
- assert.EqualValues(t, expectedContentsListResponse, contentsListResponse)
+ assert.Equal(t, expectedContentsListResponse, contentsListResponse)
// Test file contents a file with a bad ref
ref = "badref"
- req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
+ req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/?ref=%s", user2.Name, repo1.Name, ref)
MakeRequest(t, req, http.StatusNotFound)
// Test accessing private ref with user token that does not have access - should fail
- req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s", user2.Name, repo16.Name, treePath).
+ req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/", user2.Name, repo16.Name).
AddTokenAuth(token4)
MakeRequest(t, req, http.StatusNotFound)
// Test access private ref of owner of token
- req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/readme.md", user2.Name, repo16.Name).
+ req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/", user2.Name, repo16.Name).
AddTokenAuth(token2)
MakeRequest(t, req, http.StatusOK)
// Test access of org org3 private repo file by owner user2
- req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s", org3.Name, repo3.Name, treePath).
+ req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/", org3.Name, repo3.Name).
AddTokenAuth(token2)
MakeRequest(t, req, http.StatusOK)
}
diff --git a/tests/integration/api_repo_get_contents_test.go b/tests/integration/api_repo_get_contents_test.go
index 68a8608117..33df74f6ee 100644
--- a/tests/integration/api_repo_get_contents_test.go
+++ b/tests/integration/api_repo_get_contents_test.go
@@ -7,7 +7,9 @@ import (
"io"
"net/http"
"net/url"
+ "slices"
"testing"
+ "time"
auth_model "code.gitea.io/gitea/models/auth"
repo_model "code.gitea.io/gitea/models/repo"
@@ -17,33 +19,33 @@ import (
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/util"
repo_service "code.gitea.io/gitea/services/repository"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func getExpectedContentsResponseForContents(ref, refType, lastCommitSHA string) *api.ContentsResponse {
treePath := "README.md"
- sha := "4b4851ad51df6a7d9f25c979345979eaeb5b349f"
- encoding := "base64"
- content := "IyByZXBvMQoKRGVzY3JpcHRpb24gZm9yIHJlcG8x"
selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + treePath + "?ref=" + ref
htmlURL := setting.AppURL + "user2/repo1/src/" + refType + "/" + ref + "/" + treePath
- gitURL := setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/" + sha
- downloadURL := setting.AppURL + "user2/repo1/raw/" + refType + "/" + ref + "/" + treePath
+ gitURL := setting.AppURL + "api/v1/repos/user2/repo1/git/blobs/4b4851ad51df6a7d9f25c979345979eaeb5b349f"
return &api.ContentsResponse{
- Name: treePath,
- Path: treePath,
- SHA: sha,
- LastCommitSHA: lastCommitSHA,
- Type: "file",
- Size: 30,
- Encoding: &encoding,
- Content: &content,
- URL: &selfURL,
- HTMLURL: &htmlURL,
- GitURL: &gitURL,
- DownloadURL: &downloadURL,
+ Name: treePath,
+ Path: treePath,
+ SHA: "4b4851ad51df6a7d9f25c979345979eaeb5b349f",
+ LastCommitSHA: util.ToPointer(lastCommitSHA),
+ LastCommitterDate: util.ToPointer(time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400))),
+ LastAuthorDate: util.ToPointer(time.Date(2017, time.March, 19, 16, 47, 59, 0, time.FixedZone("", -14400))),
+ Type: "file",
+ Size: 30,
+ Encoding: util.ToPointer("base64"),
+ Content: util.ToPointer("IyByZXBvMQoKRGVzY3JpcHRpb24gZm9yIHJlcG8x"),
+ URL: &selfURL,
+ HTMLURL: &htmlURL,
+ GitURL: &gitURL,
+ DownloadURL: util.ToPointer(setting.AppURL + "user2/repo1/raw/" + refType + "/" + ref + "/" + treePath),
Links: &api.FileLinksResponse{
Self: &selfURL,
GitURL: &gitURL,
@@ -53,7 +55,11 @@ func getExpectedContentsResponseForContents(ref, refType, lastCommitSHA string)
}
func TestAPIGetContents(t *testing.T) {
- onGiteaRun(t, testAPIGetContents)
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ testAPIGetContentsRefFormats(t)
+ testAPIGetContents(t, u)
+ testAPIGetContentsExt(t)
+ })
}
func testAPIGetContents(t *testing.T, u *url.URL) {
@@ -75,54 +81,56 @@ func testAPIGetContents(t *testing.T, u *url.URL) {
// Get the commit ID of the default branch
gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo1)
- assert.NoError(t, err)
+ require.NoError(t, err)
defer gitRepo.Close()
// Make a new branch in repo1
newBranch := "test_branch"
err = repo_service.CreateNewBranch(git.DefaultContext, user2, repo1, gitRepo, repo1.DefaultBranch, newBranch)
- assert.NoError(t, err)
+ require.NoError(t, err)
commitID, err := gitRepo.GetBranchCommitID(repo1.DefaultBranch)
- assert.NoError(t, err)
+ require.NoError(t, err)
// Make a new tag in repo1
newTag := "test_tag"
err = gitRepo.CreateTag(newTag, commitID)
- assert.NoError(t, err)
+ require.NoError(t, err)
/*** END SETUP ***/
+ // not found
+ req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/no-such/file.md", user2.Name, repo1.Name)
+ resp := MakeRequest(t, req, http.StatusNotFound)
+ assert.Contains(t, resp.Body.String(), "object does not exist [id: , rel_path: no-such]")
+
// ref is default ref
ref := repo1.DefaultBranch
refType := "branch"
- req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
- resp := MakeRequest(t, req, http.StatusOK)
+ req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
+ resp = MakeRequest(t, req, http.StatusOK)
var contentsResponse api.ContentsResponse
DecodeJSON(t, resp, &contentsResponse)
- assert.NotNil(t, contentsResponse)
lastCommit, _ := gitRepo.GetCommitByPath("README.md")
expectedContentsResponse := getExpectedContentsResponseForContents(ref, refType, lastCommit.ID.String())
- assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
+ assert.Equal(t, *expectedContentsResponse, contentsResponse)
// No ref
refType = "branch"
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s", user2.Name, repo1.Name, treePath)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &contentsResponse)
- assert.NotNil(t, contentsResponse)
expectedContentsResponse = getExpectedContentsResponseForContents(repo1.DefaultBranch, refType, lastCommit.ID.String())
- assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
+ assert.Equal(t, *expectedContentsResponse, contentsResponse)
- // ref is the branch we created above in setup
+ // ref is the branch we created above in setup
ref = newBranch
refType = "branch"
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &contentsResponse)
- assert.NotNil(t, contentsResponse)
branchCommit, _ := gitRepo.GetBranchCommit(ref)
lastCommit, _ = branchCommit.GetCommitByPath("README.md")
expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType, lastCommit.ID.String())
- assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
+ assert.Equal(t, *expectedContentsResponse, contentsResponse)
// ref is the new tag we created above in setup
ref = newTag
@@ -130,11 +138,10 @@ func testAPIGetContents(t *testing.T, u *url.URL) {
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &contentsResponse)
- assert.NotNil(t, contentsResponse)
tagCommit, _ := gitRepo.GetTagCommit(ref)
lastCommit, _ = tagCommit.GetCommitByPath("README.md")
expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType, lastCommit.ID.String())
- assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
+ assert.Equal(t, *expectedContentsResponse, contentsResponse)
// ref is a commit
ref = commitID
@@ -142,9 +149,8 @@ func testAPIGetContents(t *testing.T, u *url.URL) {
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/contents/%s?ref=%s", user2.Name, repo1.Name, treePath, ref)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &contentsResponse)
- assert.NotNil(t, contentsResponse)
expectedContentsResponse = getExpectedContentsResponseForContents(ref, refType, commitID)
- assert.EqualValues(t, *expectedContentsResponse, contentsResponse)
+ assert.Equal(t, *expectedContentsResponse, contentsResponse)
// Test file contents a file with a bad ref
ref = "badref"
@@ -167,29 +173,131 @@ func testAPIGetContents(t *testing.T, u *url.URL) {
MakeRequest(t, req, http.StatusOK)
}
-func TestAPIGetContentsRefFormats(t *testing.T) {
- onGiteaRun(t, func(t *testing.T, u *url.URL) {
- file := "README.md"
- sha := "65f1bf27bc3bf70f64657658635e66094edbcb4d"
- content := "# repo1\n\nDescription for repo1"
-
- noRef := setting.AppURL + "api/v1/repos/user2/repo1/raw/" + file
- refInPath := setting.AppURL + "api/v1/repos/user2/repo1/raw/" + sha + "/" + file
- refInQuery := setting.AppURL + "api/v1/repos/user2/repo1/raw/" + file + "?ref=" + sha
-
- resp := MakeRequest(t, NewRequest(t, http.MethodGet, noRef), http.StatusOK)
- raw, err := io.ReadAll(resp.Body)
- assert.NoError(t, err)
- assert.EqualValues(t, content, string(raw))
-
- resp = MakeRequest(t, NewRequest(t, http.MethodGet, refInPath), http.StatusOK)
- raw, err = io.ReadAll(resp.Body)
- assert.NoError(t, err)
- assert.EqualValues(t, content, string(raw))
-
- resp = MakeRequest(t, NewRequest(t, http.MethodGet, refInQuery), http.StatusOK)
- raw, err = io.ReadAll(resp.Body)
- assert.NoError(t, err)
- assert.EqualValues(t, content, string(raw))
+func testAPIGetContentsRefFormats(t *testing.T) {
+ file := "README.md"
+ sha := "65f1bf27bc3bf70f64657658635e66094edbcb4d"
+ content := "# repo1\n\nDescription for repo1"
+
+ resp := MakeRequest(t, NewRequest(t, http.MethodGet, "/api/v1/repos/user2/repo1/raw/"+file), http.StatusOK)
+ raw, err := io.ReadAll(resp.Body)
+ assert.NoError(t, err)
+ assert.Equal(t, content, string(raw))
+
+ resp = MakeRequest(t, NewRequest(t, http.MethodGet, "/api/v1/repos/user2/repo1/raw/"+sha+"/"+file), http.StatusOK)
+ raw, err = io.ReadAll(resp.Body)
+ assert.NoError(t, err)
+ assert.Equal(t, content, string(raw))
+
+ resp = MakeRequest(t, NewRequest(t, http.MethodGet, "/api/v1/repos/user2/repo1/raw/"+file+"?ref="+sha), http.StatusOK)
+ raw, err = io.ReadAll(resp.Body)
+ assert.NoError(t, err)
+ assert.Equal(t, content, string(raw))
+
+ resp = MakeRequest(t, NewRequest(t, http.MethodGet, "/api/v1/repos/user2/repo1/raw/"+file+"?ref=master"), http.StatusOK)
+ raw, err = io.ReadAll(resp.Body)
+ assert.NoError(t, err)
+ assert.Equal(t, content, string(raw))
+
+ _ = MakeRequest(t, NewRequest(t, http.MethodGet, "/api/v1/repos/user2/repo1/raw/docs/README.md?ref=main"), http.StatusNotFound)
+ _ = MakeRequest(t, NewRequest(t, http.MethodGet, "/api/v1/repos/user2/repo1/raw/README.md?ref=main"), http.StatusOK)
+ _ = MakeRequest(t, NewRequest(t, http.MethodGet, "/api/v1/repos/user2/repo1/raw/docs/README.md?ref=sub-home-md-img-check"), http.StatusOK)
+ _ = MakeRequest(t, NewRequest(t, http.MethodGet, "/api/v1/repos/user2/repo1/raw/README.md?ref=sub-home-md-img-check"), http.StatusNotFound)
+
+ // FIXME: this is an incorrect behavior, non-existing branch falls back to default branch
+ _ = MakeRequest(t, NewRequest(t, http.MethodGet, "/api/v1/repos/user2/repo1/raw/README.md?ref=no-such"), http.StatusOK)
+}
+
+func testAPIGetContentsExt(t *testing.T) {
+ session := loginUser(t, "user2")
+ token2 := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+ t.Run("DirContents", func(t *testing.T) {
+ req := NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/contents-ext?ref=sub-home-md-img-check")
+ resp := MakeRequest(t, req, http.StatusOK)
+ var contentsResponse api.ContentsExtResponse
+ DecodeJSON(t, resp, &contentsResponse)
+ assert.Nil(t, contentsResponse.FileContents)
+ assert.NotNil(t, contentsResponse.DirContents)
+
+ req = NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/contents-ext/.?ref=sub-home-md-img-check")
+ resp = MakeRequest(t, req, http.StatusOK)
+ contentsResponse = api.ContentsExtResponse{}
+ DecodeJSON(t, resp, &contentsResponse)
+ assert.Nil(t, contentsResponse.FileContents)
+ assert.NotNil(t, contentsResponse.DirContents)
+
+ req = NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/contents-ext/docs?ref=sub-home-md-img-check")
+ resp = MakeRequest(t, req, http.StatusOK)
+ contentsResponse = api.ContentsExtResponse{}
+ DecodeJSON(t, resp, &contentsResponse)
+ assert.Nil(t, contentsResponse.FileContents)
+ assert.Equal(t, "README.md", contentsResponse.DirContents[0].Name)
+ assert.Nil(t, contentsResponse.DirContents[0].Encoding)
+ assert.Nil(t, contentsResponse.DirContents[0].Content)
+ assert.Nil(t, contentsResponse.DirContents[0].LastCommitSHA)
+ assert.Nil(t, contentsResponse.DirContents[0].LastCommitMessage)
+
+ // "includes=file_content" shouldn't affect directory listing
+ req = NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/contents-ext/docs?ref=sub-home-md-img-check&includes=file_content")
+ resp = MakeRequest(t, req, http.StatusOK)
+ contentsResponse = api.ContentsExtResponse{}
+ DecodeJSON(t, resp, &contentsResponse)
+ assert.Nil(t, contentsResponse.FileContents)
+ assert.Equal(t, "README.md", contentsResponse.DirContents[0].Name)
+ assert.Nil(t, contentsResponse.DirContents[0].Encoding)
+ assert.Nil(t, contentsResponse.DirContents[0].Content)
+
+ req = NewRequestf(t, "GET", "/api/v1/repos/user2/lfs/contents-ext?includes=file_content,lfs_metadata").AddTokenAuth(token2)
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ contentsResponse = api.ContentsExtResponse{}
+ DecodeJSON(t, resp, &contentsResponse)
+ assert.Nil(t, contentsResponse.FileContents)
+ respFileIdx := slices.IndexFunc(contentsResponse.DirContents, func(response *api.ContentsResponse) bool { return response.Name == "jpeg.jpg" })
+ require.NotEqual(t, -1, respFileIdx)
+ respFile := contentsResponse.DirContents[respFileIdx]
+ assert.Equal(t, "jpeg.jpg", respFile.Name)
+ assert.Nil(t, respFile.Encoding)
+ assert.Nil(t, respFile.Content)
+ assert.Equal(t, util.ToPointer(int64(107)), respFile.LfsSize)
+ assert.Equal(t, util.ToPointer("0b8d8b5f15046343fd32f451df93acc2bdd9e6373be478b968e4cad6b6647351"), respFile.LfsOid)
+ })
+ t.Run("FileContents", func(t *testing.T) {
+ // by default, no file content or commit info is returned
+ req := NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/contents-ext/docs/README.md?ref=sub-home-md-img-check")
+ resp := MakeRequest(t, req, http.StatusOK)
+ var contentsResponse api.ContentsExtResponse
+ DecodeJSON(t, resp, &contentsResponse)
+ assert.Nil(t, contentsResponse.DirContents)
+ assert.Equal(t, "README.md", contentsResponse.FileContents.Name)
+ assert.Nil(t, contentsResponse.FileContents.Encoding)
+ assert.Nil(t, contentsResponse.FileContents.Content)
+ assert.Nil(t, contentsResponse.FileContents.LastCommitSHA)
+ assert.Nil(t, contentsResponse.FileContents.LastCommitMessage)
+
+ // file content is only returned when `includes=file_content`
+ req = NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/contents-ext/docs/README.md?ref=sub-home-md-img-check&includes=file_content,commit_metadata,commit_message")
+ resp = MakeRequest(t, req, http.StatusOK)
+ contentsResponse = api.ContentsExtResponse{}
+ DecodeJSON(t, resp, &contentsResponse)
+ assert.Nil(t, contentsResponse.DirContents)
+ assert.Equal(t, "README.md", contentsResponse.FileContents.Name)
+ assert.NotNil(t, contentsResponse.FileContents.Encoding)
+ assert.NotNil(t, contentsResponse.FileContents.Content)
+ assert.Equal(t, "4649299398e4d39a5c09eb4f534df6f1e1eb87cc", *contentsResponse.FileContents.LastCommitSHA)
+ assert.Equal(t, "Test how READMEs render images when found in a subfolder\n", *contentsResponse.FileContents.LastCommitMessage)
+
+ req = NewRequestf(t, "GET", "/api/v1/repos/user2/lfs/contents-ext/jpeg.jpg?includes=file_content").AddTokenAuth(token2)
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ contentsResponse = api.ContentsExtResponse{}
+ DecodeJSON(t, resp, &contentsResponse)
+ assert.Nil(t, contentsResponse.DirContents)
+ assert.NotNil(t, contentsResponse.FileContents)
+ respFile := contentsResponse.FileContents
+ assert.Equal(t, "jpeg.jpg", respFile.Name)
+ assert.NotNil(t, respFile.Encoding)
+ assert.NotNil(t, respFile.Content)
+ assert.Nil(t, contentsResponse.FileContents.LastCommitSHA)
+ assert.Nil(t, contentsResponse.FileContents.LastCommitMessage)
+ assert.Equal(t, util.ToPointer(int64(107)), respFile.LfsSize)
+ assert.Equal(t, util.ToPointer("0b8d8b5f15046343fd32f451df93acc2bdd9e6373be478b968e4cad6b6647351"), respFile.LfsOid)
})
}
diff --git a/tests/integration/api_repo_git_blobs_test.go b/tests/integration/api_repo_git_blobs_test.go
index 184362e7e3..d4274bdb40 100644
--- a/tests/integration/api_repo_git_blobs_test.go
+++ b/tests/integration/api_repo_git_blobs_test.go
@@ -41,7 +41,7 @@ func TestAPIReposGitBlobs(t *testing.T) {
DecodeJSON(t, resp, &gitBlobResponse)
assert.NotNil(t, gitBlobResponse)
expectedContent := "dHJlZSAyYTJmMWQ0NjcwNzI4YTJlMTAwNDllMzQ1YmQ3YTI3NjQ2OGJlYWI2CmF1dGhvciB1c2VyMSA8YWRkcmVzczFAZXhhbXBsZS5jb20+IDE0ODk5NTY0NzkgLTA0MDAKY29tbWl0dGVyIEV0aGFuIEtvZW5pZyA8ZXRoYW50a29lbmlnQGdtYWlsLmNvbT4gMTQ4OTk1NjQ3OSAtMDQwMAoKSW5pdGlhbCBjb21taXQK"
- assert.Equal(t, expectedContent, gitBlobResponse.Content)
+ assert.Equal(t, expectedContent, *gitBlobResponse.Content)
// Tests a private repo with no token so will fail
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/blobs/%s", user2.Name, repo16.Name, repo16ReadmeSHA)
@@ -72,7 +72,7 @@ func TestAPIReposGitBlobs(t *testing.T) {
// Login as User4.
session = loginUser(t, user4.Name)
- token4 := getTokenForLoggedInUser(t, session)
+ token4 := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll)
// Test using org repo "org3/repo3" where user4 is a NOT collaborator
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/blobs/d56a3073c1dbb7b15963110a049d50cdb5db99fc?access=%s", org3.Name, repo3.Name, token4)
diff --git a/tests/integration/api_repo_git_commits_test.go b/tests/integration/api_repo_git_commits_test.go
index c4c626eb49..a1584d4629 100644
--- a/tests/integration/api_repo_git_commits_test.go
+++ b/tests/integration/api_repo_git_commits_test.go
@@ -72,12 +72,12 @@ func TestAPIReposGitCommitList(t *testing.T) {
DecodeJSON(t, resp, &apiData)
assert.Len(t, apiData, 2)
- assert.EqualValues(t, "cfe3b3c1fd36fba04f9183287b106497e1afe986", apiData[0].CommitMeta.SHA)
+ assert.Equal(t, "cfe3b3c1fd36fba04f9183287b106497e1afe986", apiData[0].CommitMeta.SHA)
compareCommitFiles(t, []string{"link_hi", "test.csv"}, apiData[0].Files)
- assert.EqualValues(t, "c8e31bc7688741a5287fcde4fbb8fc129ca07027", apiData[1].CommitMeta.SHA)
+ assert.Equal(t, "c8e31bc7688741a5287fcde4fbb8fc129ca07027", apiData[1].CommitMeta.SHA)
compareCommitFiles(t, []string{"test.csv"}, apiData[1].Files)
- assert.EqualValues(t, "2", resp.Header().Get("X-Total"))
+ assert.Equal(t, "2", resp.Header().Get("X-Total"))
}
func TestAPIReposGitCommitListNotMaster(t *testing.T) {
@@ -96,14 +96,14 @@ func TestAPIReposGitCommitListNotMaster(t *testing.T) {
DecodeJSON(t, resp, &apiData)
assert.Len(t, apiData, 3)
- assert.EqualValues(t, "69554a64c1e6030f051e5c3f94bfbd773cd6a324", apiData[0].CommitMeta.SHA)
+ assert.Equal(t, "69554a64c1e6030f051e5c3f94bfbd773cd6a324", apiData[0].CommitMeta.SHA)
compareCommitFiles(t, []string{"readme.md"}, apiData[0].Files)
- assert.EqualValues(t, "27566bd5738fc8b4e3fef3c5e72cce608537bd95", apiData[1].CommitMeta.SHA)
+ assert.Equal(t, "27566bd5738fc8b4e3fef3c5e72cce608537bd95", apiData[1].CommitMeta.SHA)
compareCommitFiles(t, []string{"readme.md"}, apiData[1].Files)
- assert.EqualValues(t, "5099b81332712fe655e34e8dd63574f503f61811", apiData[2].CommitMeta.SHA)
+ assert.Equal(t, "5099b81332712fe655e34e8dd63574f503f61811", apiData[2].CommitMeta.SHA)
compareCommitFiles(t, []string{"readme.md"}, apiData[2].Files)
- assert.EqualValues(t, "3", resp.Header().Get("X-Total"))
+ assert.Equal(t, "3", resp.Header().Get("X-Total"))
}
func TestAPIReposGitCommitListPage2Empty(t *testing.T) {
@@ -177,7 +177,7 @@ func TestDownloadCommitDiffOrPatch(t *testing.T) {
reqDiff := NewRequestf(t, "GET", "/api/v1/repos/%s/repo16/git/commits/f27c2b2b03dcab38beaf89b0ab4ff61f6de63441.diff", user.Name).
AddTokenAuth(token)
resp := MakeRequest(t, reqDiff, http.StatusOK)
- assert.EqualValues(t,
+ assert.Equal(t,
"commit f27c2b2b03dcab38beaf89b0ab4ff61f6de63441\nAuthor: User2 <user2@example.com>\nDate: Sun Aug 6 19:55:01 2017 +0200\n\n good signed commit\n\ndiff --git a/readme.md b/readme.md\nnew file mode 100644\nindex 0000000..458121c\n--- /dev/null\n+++ b/readme.md\n@@ -0,0 +1 @@\n+good sign\n",
resp.Body.String())
@@ -185,7 +185,7 @@ func TestDownloadCommitDiffOrPatch(t *testing.T) {
reqPatch := NewRequestf(t, "GET", "/api/v1/repos/%s/repo16/git/commits/f27c2b2b03dcab38beaf89b0ab4ff61f6de63441.patch", user.Name).
AddTokenAuth(token)
resp = MakeRequest(t, reqPatch, http.StatusOK)
- assert.EqualValues(t,
+ assert.Equal(t,
"From f27c2b2b03dcab38beaf89b0ab4ff61f6de63441 Mon Sep 17 00:00:00 2001\nFrom: User2 <user2@example.com>\nDate: Sun, 6 Aug 2017 19:55:01 +0200\nSubject: [PATCH] good signed commit\n\n---\n readme.md | 1 +\n 1 file changed, 1 insertion(+)\n create mode 100644 readme.md\n\ndiff --git a/readme.md b/readme.md\nnew file mode 100644\nindex 0000000..458121c\n--- /dev/null\n+++ b/readme.md\n@@ -0,0 +1 @@\n+good sign\n",
resp.Body.String())
}
@@ -208,7 +208,7 @@ func TestGetFileHistory(t *testing.T) {
assert.Equal(t, "f27c2b2b03dcab38beaf89b0ab4ff61f6de63441", apiData[0].CommitMeta.SHA)
compareCommitFiles(t, []string{"readme.md"}, apiData[0].Files)
- assert.EqualValues(t, "1", resp.Header().Get("X-Total"))
+ assert.Equal(t, "1", resp.Header().Get("X-Total"))
}
func TestGetFileHistoryNotOnMaster(t *testing.T) {
@@ -229,5 +229,5 @@ func TestGetFileHistoryNotOnMaster(t *testing.T) {
assert.Equal(t, "c8e31bc7688741a5287fcde4fbb8fc129ca07027", apiData[0].CommitMeta.SHA)
compareCommitFiles(t, []string{"test.csv"}, apiData[0].Files)
- assert.EqualValues(t, "1", resp.Header().Get("X-Total"))
+ assert.Equal(t, "1", resp.Header().Get("X-Total"))
}
diff --git a/tests/integration/api_repo_git_hook_test.go b/tests/integration/api_repo_git_hook_test.go
index 9917b41790..c28c4336e2 100644
--- a/tests/integration/api_repo_git_hook_test.go
+++ b/tests/integration/api_repo_git_hook_test.go
@@ -12,185 +12,190 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
)
-const testHookContent = `#!/bin/bash
+func TestAPIGitHooks(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+ defer test.MockVariableValue(&setting.DisableGitHooks, false)()
-echo Hello, World!
+ const testHookContent = `#!/bin/bash
+echo "TestGitHookScript"
`
-func TestAPIListGitHooks(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
-
- repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 37})
- owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
-
- // user1 is an admin user
- session := loginUser(t, "user1")
- token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository)
- req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git", owner.Name, repo.Name).
- AddTokenAuth(token)
- resp := MakeRequest(t, req, http.StatusOK)
- var apiGitHooks []*api.GitHook
- DecodeJSON(t, resp, &apiGitHooks)
- assert.Len(t, apiGitHooks, 3)
- for _, apiGitHook := range apiGitHooks {
- if apiGitHook.Name == "pre-receive" {
- assert.True(t, apiGitHook.IsActive)
- assert.Equal(t, testHookContent, apiGitHook.Content)
- } else {
+ t.Run("ListGitHooks", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 37})
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+
+ // user1 is an admin user
+ session := loginUser(t, "user1")
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository)
+ req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git", owner.Name, repo.Name).
+ AddTokenAuth(token)
+ resp := MakeRequest(t, req, http.StatusOK)
+ var apiGitHooks []*api.GitHook
+ DecodeJSON(t, resp, &apiGitHooks)
+ assert.Len(t, apiGitHooks, 3)
+ for _, apiGitHook := range apiGitHooks {
+ if apiGitHook.Name == "pre-receive" {
+ assert.True(t, apiGitHook.IsActive)
+ assert.Equal(t, testHookContent, apiGitHook.Content)
+ } else {
+ assert.False(t, apiGitHook.IsActive)
+ assert.Empty(t, apiGitHook.Content)
+ }
+ }
+ })
+
+ t.Run("NoGitHooks", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+
+ // user1 is an admin user
+ session := loginUser(t, "user1")
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository)
+ req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git", owner.Name, repo.Name).
+ AddTokenAuth(token)
+ resp := MakeRequest(t, req, http.StatusOK)
+ var apiGitHooks []*api.GitHook
+ DecodeJSON(t, resp, &apiGitHooks)
+ assert.Len(t, apiGitHooks, 3)
+ for _, apiGitHook := range apiGitHooks {
assert.False(t, apiGitHook.IsActive)
assert.Empty(t, apiGitHook.Content)
}
- }
-}
-
-func TestAPIListGitHooksNoHooks(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
-
- repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
- owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
-
- // user1 is an admin user
- session := loginUser(t, "user1")
- token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository)
- req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git", owner.Name, repo.Name).
- AddTokenAuth(token)
- resp := MakeRequest(t, req, http.StatusOK)
- var apiGitHooks []*api.GitHook
- DecodeJSON(t, resp, &apiGitHooks)
- assert.Len(t, apiGitHooks, 3)
- for _, apiGitHook := range apiGitHooks {
- assert.False(t, apiGitHook.IsActive)
- assert.Empty(t, apiGitHook.Content)
- }
-}
-
-func TestAPIListGitHooksNoAccess(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
-
- repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
- owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
-
- session := loginUser(t, owner.Name)
- token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository)
- req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git", owner.Name, repo.Name).
- AddTokenAuth(token)
- MakeRequest(t, req, http.StatusForbidden)
-}
-
-func TestAPIGetGitHook(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
-
- repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 37})
- owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
-
- // user1 is an admin user
- session := loginUser(t, "user1")
- token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository)
- req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git/pre-receive", owner.Name, repo.Name).
- AddTokenAuth(token)
- resp := MakeRequest(t, req, http.StatusOK)
- var apiGitHook *api.GitHook
- DecodeJSON(t, resp, &apiGitHook)
- assert.True(t, apiGitHook.IsActive)
- assert.Equal(t, testHookContent, apiGitHook.Content)
-}
-
-func TestAPIGetGitHookNoAccess(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
-
- repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
- owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
-
- session := loginUser(t, owner.Name)
- token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository)
- req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git/pre-receive", owner.Name, repo.Name).
- AddTokenAuth(token)
- MakeRequest(t, req, http.StatusForbidden)
-}
-
-func TestAPIEditGitHook(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
-
- repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
- owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
-
- // user1 is an admin user
- session := loginUser(t, "user1")
- token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
-
- urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/hooks/git/pre-receive",
- owner.Name, repo.Name)
- req := NewRequestWithJSON(t, "PATCH", urlStr, &api.EditGitHookOption{
- Content: testHookContent,
- }).AddTokenAuth(token)
- resp := MakeRequest(t, req, http.StatusOK)
- var apiGitHook *api.GitHook
- DecodeJSON(t, resp, &apiGitHook)
- assert.True(t, apiGitHook.IsActive)
- assert.Equal(t, testHookContent, apiGitHook.Content)
-
- req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git/pre-receive", owner.Name, repo.Name).
- AddTokenAuth(token)
- resp = MakeRequest(t, req, http.StatusOK)
- var apiGitHook2 *api.GitHook
- DecodeJSON(t, resp, &apiGitHook2)
- assert.True(t, apiGitHook2.IsActive)
- assert.Equal(t, testHookContent, apiGitHook2.Content)
-}
-
-func TestAPIEditGitHookNoAccess(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
-
- repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
- owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
-
- session := loginUser(t, owner.Name)
- token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
- urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/hooks/git/pre-receive", owner.Name, repo.Name)
- req := NewRequestWithJSON(t, "PATCH", urlStr, &api.EditGitHookOption{
- Content: testHookContent,
- }).AddTokenAuth(token)
- MakeRequest(t, req, http.StatusForbidden)
-}
-
-func TestAPIDeleteGitHook(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
-
- repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 37})
- owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
-
- // user1 is an admin user
- session := loginUser(t, "user1")
- token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
-
- req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/hooks/git/pre-receive", owner.Name, repo.Name).
- AddTokenAuth(token)
- MakeRequest(t, req, http.StatusNoContent)
-
- req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git/pre-receive", owner.Name, repo.Name).
- AddTokenAuth(token)
- resp := MakeRequest(t, req, http.StatusOK)
- var apiGitHook2 *api.GitHook
- DecodeJSON(t, resp, &apiGitHook2)
- assert.False(t, apiGitHook2.IsActive)
- assert.Empty(t, apiGitHook2.Content)
-}
-
-func TestAPIDeleteGitHookNoAccess(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
-
- repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
- owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
-
- session := loginUser(t, owner.Name)
- token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
- req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/hooks/git/pre-receive", owner.Name, repo.Name).
- AddTokenAuth(token)
- MakeRequest(t, req, http.StatusForbidden)
+ })
+
+ t.Run("ListGitHooksNoAccess", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+
+ session := loginUser(t, owner.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository)
+ req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git", owner.Name, repo.Name).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusForbidden)
+ })
+
+ t.Run("GetGitHook", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 37})
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+
+ // user1 is an admin user
+ session := loginUser(t, "user1")
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository)
+ req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git/pre-receive", owner.Name, repo.Name).
+ AddTokenAuth(token)
+ resp := MakeRequest(t, req, http.StatusOK)
+ var apiGitHook *api.GitHook
+ DecodeJSON(t, resp, &apiGitHook)
+ assert.True(t, apiGitHook.IsActive)
+ assert.Equal(t, testHookContent, apiGitHook.Content)
+ })
+ t.Run("GetGitHookNoAccess", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+
+ session := loginUser(t, owner.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository)
+ req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git/pre-receive", owner.Name, repo.Name).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusForbidden)
+ })
+
+ t.Run("EditGitHook", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+
+ // user1 is an admin user
+ session := loginUser(t, "user1")
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/hooks/git/pre-receive",
+ owner.Name, repo.Name)
+ req := NewRequestWithJSON(t, "PATCH", urlStr, &api.EditGitHookOption{
+ Content: testHookContent,
+ }).AddTokenAuth(token)
+ resp := MakeRequest(t, req, http.StatusOK)
+ var apiGitHook *api.GitHook
+ DecodeJSON(t, resp, &apiGitHook)
+ assert.True(t, apiGitHook.IsActive)
+ assert.Equal(t, testHookContent, apiGitHook.Content)
+
+ req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git/pre-receive", owner.Name, repo.Name).
+ AddTokenAuth(token)
+ resp = MakeRequest(t, req, http.StatusOK)
+ var apiGitHook2 *api.GitHook
+ DecodeJSON(t, resp, &apiGitHook2)
+ assert.True(t, apiGitHook2.IsActive)
+ assert.Equal(t, testHookContent, apiGitHook2.Content)
+ })
+
+ t.Run("EditGitHookNoAccess", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+
+ session := loginUser(t, owner.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+ urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/hooks/git/pre-receive", owner.Name, repo.Name)
+ req := NewRequestWithJSON(t, "PATCH", urlStr, &api.EditGitHookOption{
+ Content: testHookContent,
+ }).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusForbidden)
+ })
+
+ t.Run("DeleteGitHook", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 37})
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+
+ // user1 is an admin user
+ session := loginUser(t, "user1")
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/hooks/git/pre-receive", owner.Name, repo.Name).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNoContent)
+
+ req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/hooks/git/pre-receive", owner.Name, repo.Name).
+ AddTokenAuth(token)
+ resp := MakeRequest(t, req, http.StatusOK)
+ var apiGitHook2 *api.GitHook
+ DecodeJSON(t, resp, &apiGitHook2)
+ assert.False(t, apiGitHook2.IsActive)
+ assert.Empty(t, apiGitHook2.Content)
+ })
+
+ t.Run("DeleteGitHookNoAccess", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+
+ session := loginUser(t, owner.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+ req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/hooks/git/pre-receive", owner.Name, repo.Name).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusForbidden)
+ })
}
diff --git a/tests/integration/api_repo_git_tags_test.go b/tests/integration/api_repo_git_tags_test.go
index c5883a8058..5a66337589 100644
--- a/tests/integration/api_repo_git_tags_test.go
+++ b/tests/integration/api_repo_git_tags_test.go
@@ -30,8 +30,8 @@ func TestAPIGitTags(t *testing.T) {
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository)
// Set up git config for the tagger
- _ = git.NewCommand(git.DefaultContext, "config", "user.name").AddDynamicArguments(user.Name).Run(&git.RunOpts{Dir: repo.RepoPath()})
- _ = git.NewCommand(git.DefaultContext, "config", "user.email").AddDynamicArguments(user.Email).Run(&git.RunOpts{Dir: repo.RepoPath()})
+ _ = git.NewCommand("config", "user.name").AddDynamicArguments(user.Name).Run(git.DefaultContext, &git.RunOpts{Dir: repo.RepoPath()})
+ _ = git.NewCommand("config", "user.email").AddDynamicArguments(user.Email).Run(git.DefaultContext, &git.RunOpts{Dir: repo.RepoPath()})
gitRepo, _ := gitrepo.OpenRepository(git.DefaultContext, repo)
defer gitRepo.Close()
diff --git a/tests/integration/api_repo_git_trees_test.go b/tests/integration/api_repo_git_trees_test.go
index 8eec6d8d22..ea7630f414 100644
--- a/tests/integration/api_repo_git_trees_test.go
+++ b/tests/integration/api_repo_git_trees_test.go
@@ -11,7 +11,11 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
+ api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/tests"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func TestAPIReposGitTrees(t *testing.T) {
@@ -32,13 +36,21 @@ func TestAPIReposGitTrees(t *testing.T) {
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository)
// Test a public repo that anyone can GET the tree of
- for _, ref := range [...]string{
- "master", // Branch
- repo1TreeSHA, // Tree SHA
- } {
- req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/trees/%s", user2.Name, repo1.Name, ref)
- MakeRequest(t, req, http.StatusOK)
- }
+ _ = MakeRequest(t, NewRequest(t, "GET", "/api/v1/repos/user2/repo1/git/trees/master"), http.StatusOK)
+
+ resp := MakeRequest(t, NewRequest(t, "GET", "/api/v1/repos/user2/repo1/git/trees/62fb502a7172d4453f0322a2cc85bddffa57f07a?per_page=1"), http.StatusOK)
+ var respGitTree api.GitTreeResponse
+ DecodeJSON(t, resp, &respGitTree)
+ assert.True(t, respGitTree.Truncated)
+ require.Len(t, respGitTree.Entries, 1)
+ assert.Equal(t, "File-WoW", respGitTree.Entries[0].Path)
+
+ resp = MakeRequest(t, NewRequest(t, "GET", "/api/v1/repos/user2/repo1/git/trees/62fb502a7172d4453f0322a2cc85bddffa57f07a?page=2&per_page=1"), http.StatusOK)
+ respGitTree = api.GitTreeResponse{}
+ DecodeJSON(t, resp, &respGitTree)
+ assert.False(t, respGitTree.Truncated)
+ require.Len(t, respGitTree.Entries, 1)
+ assert.Equal(t, "README.md", respGitTree.Entries[0].Path)
// Tests a private repo with no token so will fail
for _, ref := range [...]string{
@@ -69,7 +81,7 @@ func TestAPIReposGitTrees(t *testing.T) {
// Login as User4.
session = loginUser(t, user4.Name)
- token4 := getTokenForLoggedInUser(t, session)
+ token4 := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll)
// Test using org repo "org3/repo3" where user4 is a NOT collaborator
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/git/trees/d56a3073c1dbb7b15963110a049d50cdb5db99fc?access=%s", org3.Name, repo3.Name, token4)
diff --git a/tests/integration/api_repo_languages_test.go b/tests/integration/api_repo_languages_test.go
index 1045aef57d..6347a43b4e 100644
--- a/tests/integration/api_repo_languages_test.go
+++ b/tests/integration/api_repo_languages_test.go
@@ -9,6 +9,8 @@ import (
"testing"
"time"
+ "code.gitea.io/gitea/modules/test"
+
"github.com/stretchr/testify/assert"
)
@@ -32,7 +34,8 @@ func TestRepoLanguages(t *testing.T) {
"content": "package main",
"commit_choice": "direct",
})
- session.MakeRequest(t, req, http.StatusSeeOther)
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ assert.NotEmpty(t, test.RedirectURL(resp))
// let gitea calculate language stats
time.Sleep(time.Second)
diff --git a/tests/integration/api_repo_lfs_locks_test.go b/tests/integration/api_repo_lfs_locks_test.go
index 4ba01e6d9b..161fa45dc6 100644
--- a/tests/integration/api_repo_lfs_locks_test.go
+++ b/tests/integration/api_repo_lfs_locks_test.go
@@ -112,7 +112,7 @@ func TestAPILFSLocksLogged(t *testing.T) {
var lfsLock api.LFSLockResponse
DecodeJSON(t, resp, &lfsLock)
assert.Equal(t, test.user.Name, lfsLock.Lock.Owner.Name)
- assert.EqualValues(t, lfsLock.Lock.LockedAt.Format(time.RFC3339), lfsLock.Lock.LockedAt.Format(time.RFC3339Nano)) // locked at should be rounded to second
+ assert.Equal(t, lfsLock.Lock.LockedAt.Format(time.RFC3339), lfsLock.Lock.LockedAt.Format(time.RFC3339Nano)) // locked at should be rounded to second
for _, id := range test.addTime {
resultsTests[id].locksTimes = append(resultsTests[id].locksTimes, time.Now())
}
@@ -129,9 +129,9 @@ func TestAPILFSLocksLogged(t *testing.T) {
DecodeJSON(t, resp, &lfsLocks)
assert.Len(t, lfsLocks.Locks, test.totalCount)
for i, lock := range lfsLocks.Locks {
- assert.EqualValues(t, test.locksOwners[i].Name, lock.Owner.Name)
+ assert.Equal(t, test.locksOwners[i].Name, lock.Owner.Name)
assert.WithinDuration(t, test.locksTimes[i], lock.LockedAt, 10*time.Second)
- assert.EqualValues(t, lock.LockedAt.Format(time.RFC3339), lock.LockedAt.Format(time.RFC3339Nano)) // locked at should be rounded to second
+ assert.Equal(t, lock.LockedAt.Format(time.RFC3339), lock.LockedAt.Format(time.RFC3339Nano)) // locked at should be rounded to second
}
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/%s.git/info/lfs/locks/verify", test.repo.FullName()), map[string]string{})
@@ -143,7 +143,7 @@ func TestAPILFSLocksLogged(t *testing.T) {
assert.Len(t, lfsLocksVerify.Ours, test.oursCount)
assert.Len(t, lfsLocksVerify.Theirs, test.theirsCount)
for _, lock := range lfsLocksVerify.Ours {
- assert.EqualValues(t, test.user.Name, lock.Owner.Name)
+ assert.Equal(t, test.user.Name, lock.Owner.Name)
deleteTests = append(deleteTests, struct {
user *user_model.User
repo *repo_model.Repository
diff --git a/tests/integration/api_repo_lfs_migrate_test.go b/tests/integration/api_repo_lfs_migrate_test.go
index 8b4d79db02..6ca6f9afab 100644
--- a/tests/integration/api_repo_lfs_migrate_test.go
+++ b/tests/integration/api_repo_lfs_migrate_test.go
@@ -40,7 +40,7 @@ func TestAPIRepoLFSMigrateLocal(t *testing.T) {
LFS: true,
}).AddTokenAuth(token)
resp := MakeRequest(t, req, NoExpectedStatus)
- assert.EqualValues(t, http.StatusCreated, resp.Code)
+ assert.Equal(t, http.StatusCreated, resp.Code)
store := lfs.NewContentStore()
ok, _ := store.Verify(lfs.Pointer{Oid: "fb8f7d8435968c4f82a726a92395be4d16f2f63116caf36c8ad35c60831ab041", Size: 6})
diff --git a/tests/integration/api_repo_lfs_test.go b/tests/integration/api_repo_lfs_test.go
index 6b42b83bc5..ec6a3a3b57 100644
--- a/tests/integration/api_repo_lfs_test.go
+++ b/tests/integration/api_repo_lfs_test.go
@@ -20,6 +20,7 @@ import (
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
@@ -226,9 +227,7 @@ func TestAPILFSBatch(t *testing.T) {
t.Run("FileTooBig", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
-
- oldMaxFileSize := setting.LFS.MaxFileSize
- setting.LFS.MaxFileSize = 2
+ defer test.MockVariableValue(&setting.LFS.MaxFileSize, 2)()
req := newRequest(t, &lfs.BatchRequest{
Operation: "upload",
@@ -243,8 +242,6 @@ func TestAPILFSBatch(t *testing.T) {
assert.NotNil(t, br.Objects[0].Error)
assert.Equal(t, http.StatusUnprocessableEntity, br.Objects[0].Error.Code)
assert.Equal(t, "Size must be less than or equal to 2", br.Objects[0].Error.Message)
-
- setting.LFS.MaxFileSize = oldMaxFileSize
})
t.Run("AddMeta", func(t *testing.T) {
diff --git a/tests/integration/api_repo_license_test.go b/tests/integration/api_repo_license_test.go
index 52d3085694..fb4450a2bd 100644
--- a/tests/integration/api_repo_license_test.go
+++ b/tests/integration/api_repo_license_test.go
@@ -12,12 +12,13 @@ import (
auth_model "code.gitea.io/gitea/models/auth"
api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/test"
"github.com/stretchr/testify/assert"
)
var testLicenseContent = `
-Copyright (c) 2024 Gitea
+Copyright (c) 2024 Gitea
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
@@ -48,7 +49,8 @@ func TestAPIRepoLicense(t *testing.T) {
"content": testLicenseContent,
"commit_choice": "direct",
})
- session.MakeRequest(t, req, http.StatusSeeOther)
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ assert.NotEmpty(t, test.RedirectURL(resp))
// let gitea update repo license
time.Sleep(time.Second)
diff --git a/tests/integration/api_repo_raw_test.go b/tests/integration/api_repo_raw_test.go
index e5f83d1c80..e9d741925f 100644
--- a/tests/integration/api_repo_raw_test.go
+++ b/tests/integration/api_repo_raw_test.go
@@ -30,11 +30,11 @@ func TestAPIReposRaw(t *testing.T) {
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/%s/README.md", user.Name, ref).
AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
- assert.EqualValues(t, "file", resp.Header().Get("x-gitea-object-type"))
+ assert.Equal(t, "file", resp.Header().Get("x-gitea-object-type"))
}
// Test default branch
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/README.md", user.Name).
AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
- assert.EqualValues(t, "file", resp.Header().Get("x-gitea-object-type"))
+ assert.Equal(t, "file", resp.Header().Get("x-gitea-object-type"))
}
diff --git a/tests/integration/api_repo_secrets_test.go b/tests/integration/api_repo_secrets_test.go
index c3074d9ece..2059aff484 100644
--- a/tests/integration/api_repo_secrets_test.go
+++ b/tests/integration/api_repo_secrets_test.go
@@ -73,6 +73,33 @@ func TestAPIRepoSecrets(t *testing.T) {
}
})
+ t.Run("CreateWithDescription", func(t *testing.T) {
+ cases := []struct {
+ Name string
+ Description string
+ ExpectedStatus int
+ }{
+ {
+ Name: "no_description",
+ Description: "",
+ ExpectedStatus: http.StatusCreated,
+ },
+ {
+ Name: "description",
+ Description: "some description",
+ ExpectedStatus: http.StatusCreated,
+ },
+ }
+
+ for _, c := range cases {
+ req := NewRequestWithJSON(t, "PUT", fmt.Sprintf("/api/v1/repos/%s/actions/secrets/%s", repo.FullName(), c.Name), api.CreateOrUpdateSecretOption{
+ Data: "data",
+ Description: c.Description,
+ }).AddTokenAuth(token)
+ MakeRequest(t, req, c.ExpectedStatus)
+ }
+ })
+
t.Run("Update", func(t *testing.T) {
name := "update_secret"
url := fmt.Sprintf("/api/v1/repos/%s/actions/secrets/%s", repo.FullName(), name)
diff --git a/tests/integration/api_repo_tags_test.go b/tests/integration/api_repo_tags_test.go
index a7f021ca4f..3932a8ba2b 100644
--- a/tests/integration/api_repo_tags_test.go
+++ b/tests/integration/api_repo_tags_test.go
@@ -48,10 +48,10 @@ func TestAPIRepoTags(t *testing.T) {
assert.Len(t, tags, 2)
for _, tag := range tags {
if tag.Name != "v1.1" {
- assert.EqualValues(t, newTag.Name, tag.Name)
- assert.EqualValues(t, newTag.Message, tag.Message)
- assert.EqualValues(t, "nice!\nand some text", tag.Message)
- assert.EqualValues(t, newTag.Commit.SHA, tag.Commit.SHA)
+ assert.Equal(t, newTag.Name, tag.Name)
+ assert.Equal(t, newTag.Message, tag.Message)
+ assert.Equal(t, "nice!\nand some text", tag.Message)
+ assert.Equal(t, newTag.Commit.SHA, tag.Commit.SHA)
}
}
@@ -61,7 +61,7 @@ func TestAPIRepoTags(t *testing.T) {
resp = MakeRequest(t, req, http.StatusOK)
var tag *api.Tag
DecodeJSON(t, resp, &tag)
- assert.EqualValues(t, newTag, tag)
+ assert.Equal(t, newTag, tag)
// delete tag
delReq := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/tags/%s", user.Name, repoName, newTag.Name).
diff --git a/tests/integration/api_repo_teams_test.go b/tests/integration/api_repo_teams_test.go
index 07d065b02b..143e3dd29f 100644
--- a/tests/integration/api_repo_teams_test.go
+++ b/tests/integration/api_repo_teams_test.go
@@ -37,15 +37,15 @@ func TestAPIRepoTeams(t *testing.T) {
var teams []*api.Team
DecodeJSON(t, res, &teams)
if assert.Len(t, teams, 2) {
- assert.EqualValues(t, "Owners", teams[0].Name)
+ assert.Equal(t, "Owners", teams[0].Name)
assert.True(t, teams[0].CanCreateOrgRepo)
assert.True(t, util.SliceSortedEqual(unit.AllUnitKeyNames(), teams[0].Units), "%v == %v", unit.AllUnitKeyNames(), teams[0].Units)
- assert.EqualValues(t, "owner", teams[0].Permission)
+ assert.Equal(t, "owner", teams[0].Permission)
- assert.EqualValues(t, "test_team", teams[1].Name)
+ assert.Equal(t, "test_team", teams[1].Name)
assert.False(t, teams[1].CanCreateOrgRepo)
- assert.EqualValues(t, []string{"repo.issues"}, teams[1].Units)
- assert.EqualValues(t, "write", teams[1].Permission)
+ assert.Equal(t, []string{"repo.issues"}, teams[1].Units)
+ assert.Equal(t, "write", teams[1].Permission)
}
// IsTeam
@@ -54,7 +54,7 @@ func TestAPIRepoTeams(t *testing.T) {
res = MakeRequest(t, req, http.StatusOK)
var team *api.Team
DecodeJSON(t, res, &team)
- assert.EqualValues(t, teams[1], team)
+ assert.Equal(t, teams[1], team)
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/teams/%s", publicOrgRepo.FullName(), "NonExistingTeam")).
AddTokenAuth(token)
diff --git a/tests/integration/api_repo_test.go b/tests/integration/api_repo_test.go
index 122afbfa08..a2c3a467c6 100644
--- a/tests/integration/api_repo_test.go
+++ b/tests/integration/api_repo_test.go
@@ -37,7 +37,7 @@ func TestAPIUserReposNotLogin(t *testing.T) {
unittest.Cond("is_private = ?", false))
assert.Len(t, apiRepos, expectedLen)
for _, repo := range apiRepos {
- assert.EqualValues(t, user.ID, repo.Owner.ID)
+ assert.Equal(t, user.ID, repo.Owner.ID)
assert.False(t, repo.Private)
}
}
@@ -45,7 +45,7 @@ func TestAPIUserReposNotLogin(t *testing.T) {
func TestAPIUserReposWithWrongToken(t *testing.T) {
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
- wrongToken := fmt.Sprintf("Bearer %s", "wrong_token")
+ wrongToken := "Bearer " + "wrong_token"
req := NewRequestf(t, "GET", "/api/v1/users/%s/repos", user.Name).
AddTokenAuth(wrongToken)
resp := MakeRequest(t, req, http.StatusUnauthorized)
@@ -266,25 +266,25 @@ func TestAPIViewRepo(t *testing.T) {
resp := MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &repo)
assert.EqualValues(t, 1, repo.ID)
- assert.EqualValues(t, "repo1", repo.Name)
- assert.EqualValues(t, 2, repo.Releases)
- assert.EqualValues(t, 1, repo.OpenIssues)
- assert.EqualValues(t, 3, repo.OpenPulls)
+ assert.Equal(t, "repo1", repo.Name)
+ assert.Equal(t, 2, repo.Releases)
+ assert.Equal(t, 1, repo.OpenIssues)
+ assert.Equal(t, 3, repo.OpenPulls)
req = NewRequest(t, "GET", "/api/v1/repos/user12/repo10")
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &repo)
assert.EqualValues(t, 10, repo.ID)
- assert.EqualValues(t, "repo10", repo.Name)
- assert.EqualValues(t, 1, repo.OpenPulls)
- assert.EqualValues(t, 1, repo.Forks)
+ assert.Equal(t, "repo10", repo.Name)
+ assert.Equal(t, 1, repo.OpenPulls)
+ assert.Equal(t, 1, repo.Forks)
req = NewRequest(t, "GET", "/api/v1/repos/user5/repo4")
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &repo)
assert.EqualValues(t, 4, repo.ID)
- assert.EqualValues(t, "repo4", repo.Name)
- assert.EqualValues(t, 1, repo.Stars)
+ assert.Equal(t, "repo4", repo.Name)
+ assert.Equal(t, 1, repo.Stars)
}
func TestAPIOrgRepos(t *testing.T) {
@@ -337,9 +337,9 @@ func TestAPIOrgReposWithCodeUnitDisabled(t *testing.T) {
var units []unit_model.Type
units = append(units, unit_model.TypeCode)
- if err := repo_service.UpdateRepositoryUnits(db.DefaultContext, repo21, nil, units); err != nil {
- assert.Fail(t, "should have been able to delete code repository unit; failed to %v", err)
- }
+ err := repo_service.UpdateRepositoryUnits(db.DefaultContext, repo21, nil, units)
+ assert.NoError(t, err, "should have been able to delete code repository unit")
+
assert.False(t, repo21.UnitEnabled(db.DefaultContext, unit_model.TypeCode))
session := loginUser(t, "user2")
@@ -403,12 +403,12 @@ func TestAPIRepoMigrate(t *testing.T) {
case "Remote visit addressed rate limitation.":
t.Log("test hit github rate limitation")
case "You can not import from disallowed hosts.":
- assert.EqualValues(t, "private-ip", testCase.repoName)
+ assert.Equal(t, "private-ip", testCase.repoName)
default:
- assert.FailNow(t, "unexpected error '%v' on url '%s'", respJSON["message"], testCase.cloneURL)
+ assert.FailNow(t, "unexpected error", "unexpected error '%v' on url '%s'", respJSON["message"], testCase.cloneURL)
}
} else {
- assert.EqualValues(t, testCase.expectedStatus, resp.Code)
+ assert.Equal(t, testCase.expectedStatus, resp.Code)
}
}
}
@@ -471,6 +471,15 @@ func TestAPIMirrorSyncNonMirrorRepo(t *testing.T) {
assert.Equal(t, "Repository is not a mirror", errRespJSON["message"])
}
+func testAPIOrgCreateRepo(t *testing.T, session *TestSession, orgName, repoName string, status int) {
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization, auth_model.AccessTokenScopeWriteRepository)
+
+ req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/org/%s/repos", orgName), &api.CreateRepoOption{
+ Name: repoName,
+ }).AddTokenAuth(token)
+ MakeRequest(t, req, status)
+}
+
func TestAPIOrgRepoCreate(t *testing.T) {
testCases := []struct {
ctxUserID int64
@@ -488,11 +497,7 @@ func TestAPIOrgRepoCreate(t *testing.T) {
for _, testCase := range testCases {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: testCase.ctxUserID})
session := loginUser(t, user.Name)
- token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization, auth_model.AccessTokenScopeWriteRepository)
- req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/org/%s/repos", testCase.orgName), &api.CreateRepoOption{
- Name: testCase.repoName,
- }).AddTokenAuth(token)
- MakeRequest(t, req, testCase.expectedStatus)
+ testAPIOrgCreateRepo(t, session, testCase.orgName, testCase.repoName, testCase.expectedStatus)
}
}
@@ -581,7 +586,7 @@ func TestAPIRepoTransfer(t *testing.T) {
// cleanup
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiRepo.ID})
- _ = repo_service.DeleteRepositoryDirectly(db.DefaultContext, user, repo.ID)
+ _ = repo_service.DeleteRepositoryDirectly(db.DefaultContext, repo.ID)
}
func transfer(t *testing.T) *repo_model.Repository {
@@ -735,5 +740,5 @@ func TestAPIRepoGetAssignees(t *testing.T) {
resp := MakeRequest(t, req, http.StatusOK)
var assignees []*api.User
DecodeJSON(t, resp, &assignees)
- assert.Len(t, assignees, 1)
+ assert.Len(t, assignees, 2)
}
diff --git a/tests/integration/api_repo_topic_test.go b/tests/integration/api_repo_topic_test.go
index a10e159b78..82d0c54ca8 100644
--- a/tests/integration/api_repo_topic_test.go
+++ b/tests/integration/api_repo_topic_test.go
@@ -30,7 +30,7 @@ func TestAPITopicSearch(t *testing.T) {
res := MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK)
DecodeJSON(t, res, &topics)
assert.Len(t, topics.TopicNames, 6)
- assert.EqualValues(t, "6", res.Header().Get("x-total-count"))
+ assert.Equal(t, "6", res.Header().Get("x-total-count"))
// pagination search topics first page
topics.TopicNames = nil
@@ -40,7 +40,7 @@ func TestAPITopicSearch(t *testing.T) {
res = MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK)
DecodeJSON(t, res, &topics)
assert.Len(t, topics.TopicNames, 4)
- assert.EqualValues(t, "6", res.Header().Get("x-total-count"))
+ assert.Equal(t, "6", res.Header().Get("x-total-count"))
// pagination search topics second page
topics.TopicNames = nil
@@ -50,7 +50,7 @@ func TestAPITopicSearch(t *testing.T) {
res = MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK)
DecodeJSON(t, res, &topics)
assert.Len(t, topics.TopicNames, 2)
- assert.EqualValues(t, "6", res.Header().Get("x-total-count"))
+ assert.Equal(t, "6", res.Header().Get("x-total-count"))
// add keyword search
query = url.Values{"page": []string{"1"}, "limit": []string{"4"}}
@@ -66,8 +66,8 @@ func TestAPITopicSearch(t *testing.T) {
DecodeJSON(t, res, &topics)
if assert.Len(t, topics.TopicNames, 1) {
assert.EqualValues(t, 2, topics.TopicNames[0].ID)
- assert.EqualValues(t, "database", topics.TopicNames[0].Name)
- assert.EqualValues(t, 1, topics.TopicNames[0].RepoCount)
+ assert.Equal(t, "database", topics.TopicNames[0].Name)
+ assert.Equal(t, 1, topics.TopicNames[0].RepoCount)
}
}
diff --git a/tests/integration/api_repo_variables_test.go b/tests/integration/api_repo_variables_test.go
index 7847962b07..b5c88af279 100644
--- a/tests/integration/api_repo_variables_test.go
+++ b/tests/integration/api_repo_variables_test.go
@@ -35,11 +35,11 @@ func TestAPIRepoVariables(t *testing.T) {
},
{
Name: "_",
- ExpectedStatus: http.StatusNoContent,
+ ExpectedStatus: http.StatusCreated,
},
{
Name: "TEST_VAR",
- ExpectedStatus: http.StatusNoContent,
+ ExpectedStatus: http.StatusCreated,
},
{
Name: "test_var",
@@ -81,7 +81,7 @@ func TestAPIRepoVariables(t *testing.T) {
req := NewRequestWithJSON(t, "POST", url, api.CreateVariableOption{
Value: "initial_val",
}).AddTokenAuth(token)
- MakeRequest(t, req, http.StatusNoContent)
+ MakeRequest(t, req, http.StatusCreated)
cases := []struct {
Name string
@@ -138,7 +138,7 @@ func TestAPIRepoVariables(t *testing.T) {
req := NewRequestWithJSON(t, "POST", url, api.CreateVariableOption{
Value: "initial_val",
}).AddTokenAuth(token)
- MakeRequest(t, req, http.StatusNoContent)
+ MakeRequest(t, req, http.StatusCreated)
req = NewRequest(t, "DELETE", url).AddTokenAuth(token)
MakeRequest(t, req, http.StatusNoContent)
diff --git a/tests/integration/api_settings_test.go b/tests/integration/api_settings_test.go
index 9881578fba..743dbb0481 100644
--- a/tests/integration/api_settings_test.go
+++ b/tests/integration/api_settings_test.go
@@ -30,11 +30,12 @@ func TestAPIExposedSettings(t *testing.T) {
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiSettings)
- assert.EqualValues(t, &api.GeneralAPISettings{
+ assert.Equal(t, &api.GeneralAPISettings{
MaxResponseItems: setting.API.MaxResponseItems,
DefaultPagingNum: setting.API.DefaultPagingNum,
DefaultGitTreesPerPage: setting.API.DefaultGitTreesPerPage,
DefaultMaxBlobSize: setting.API.DefaultMaxBlobSize,
+ DefaultMaxResponseSize: setting.API.DefaultMaxResponseSize,
}, apiSettings)
repo := new(api.GeneralRepoSettings)
@@ -42,7 +43,7 @@ func TestAPIExposedSettings(t *testing.T) {
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &repo)
- assert.EqualValues(t, &api.GeneralRepoSettings{
+ assert.Equal(t, &api.GeneralRepoSettings{
MirrorsDisabled: !setting.Mirror.Enabled,
HTTPGitDisabled: setting.Repository.DisableHTTPGit,
MigrationsDisabled: setting.Repository.DisableMigrations,
@@ -55,7 +56,7 @@ func TestAPIExposedSettings(t *testing.T) {
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &attachment)
- assert.EqualValues(t, &api.GeneralAttachmentSettings{
+ assert.Equal(t, &api.GeneralAttachmentSettings{
Enabled: setting.Attachment.Enabled,
AllowedTypes: setting.Attachment.AllowedTypes,
MaxFiles: setting.Attachment.MaxFiles,
diff --git a/tests/integration/api_team_test.go b/tests/integration/api_team_test.go
index d14c66ff2c..e54203ed50 100644
--- a/tests/integration/api_team_test.go
+++ b/tests/integration/api_team_test.go
@@ -40,9 +40,9 @@ func TestAPITeam(t *testing.T) {
var apiTeam api.Team
DecodeJSON(t, resp, &apiTeam)
- assert.EqualValues(t, team.ID, apiTeam.ID)
+ assert.Equal(t, team.ID, apiTeam.ID)
assert.Equal(t, team.Name, apiTeam.Name)
- assert.EqualValues(t, convert.ToOrganization(db.DefaultContext, org), apiTeam.Organization)
+ assert.Equal(t, convert.ToOrganization(db.DefaultContext, org), apiTeam.Organization)
// non team member user will not access the teams details
teamUser2 := unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{ID: 3})
@@ -78,9 +78,9 @@ func TestAPITeam(t *testing.T) {
apiTeam = api.Team{}
DecodeJSON(t, resp, &apiTeam)
checkTeamResponse(t, "CreateTeam1", &apiTeam, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
- teamToCreate.Permission, teamToCreate.Units, nil)
+ "none", teamToCreate.Units, nil)
checkTeamBean(t, apiTeam.ID, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
- teamToCreate.Permission, teamToCreate.Units, nil)
+ "none", teamToCreate.Units, nil)
teamID := apiTeam.ID
// Edit team.
@@ -149,9 +149,9 @@ func TestAPITeam(t *testing.T) {
apiTeam = api.Team{}
DecodeJSON(t, resp, &apiTeam)
checkTeamResponse(t, "CreateTeam2", &apiTeam, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
- "read", nil, teamToCreate.UnitsMap)
+ "none", nil, teamToCreate.UnitsMap)
checkTeamBean(t, apiTeam.ID, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
- "read", nil, teamToCreate.UnitsMap)
+ "none", nil, teamToCreate.UnitsMap)
teamID = apiTeam.ID
// Edit team.
@@ -171,9 +171,9 @@ func TestAPITeam(t *testing.T) {
apiTeam = api.Team{}
DecodeJSON(t, resp, &apiTeam)
checkTeamResponse(t, "EditTeam2", &apiTeam, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories,
- "read", nil, teamToEdit.UnitsMap)
+ "none", nil, teamToEdit.UnitsMap)
checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories,
- "read", nil, teamToEdit.UnitsMap)
+ "none", nil, teamToEdit.UnitsMap)
// Edit team Description only
editDescription = "second team"
@@ -184,9 +184,9 @@ func TestAPITeam(t *testing.T) {
apiTeam = api.Team{}
DecodeJSON(t, resp, &apiTeam)
checkTeamResponse(t, "EditTeam2_DescOnly", &apiTeam, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories,
- "read", nil, teamToEdit.UnitsMap)
+ "none", nil, teamToEdit.UnitsMap)
checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories,
- "read", nil, teamToEdit.UnitsMap)
+ "none", nil, teamToEdit.UnitsMap)
// Read team.
teamRead = unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID})
@@ -247,10 +247,10 @@ func checkTeamResponse(t *testing.T, testName string, apiTeam *api.Team, name, d
if units != nil {
sort.StringSlice(units).Sort()
sort.StringSlice(apiTeam.Units).Sort()
- assert.EqualValues(t, units, apiTeam.Units, "units")
+ assert.Equal(t, units, apiTeam.Units, "units")
}
if unitsMap != nil {
- assert.EqualValues(t, unitsMap, apiTeam.UnitsMap, "unitsMap")
+ assert.Equal(t, unitsMap, apiTeam.UnitsMap, "unitsMap")
}
})
}
diff --git a/tests/integration/api_team_user_test.go b/tests/integration/api_team_user_test.go
index 6c80bc9f80..cbbbe00a9e 100644
--- a/tests/integration/api_team_user_test.go
+++ b/tests/integration/api_team_user_test.go
@@ -21,29 +21,31 @@ import (
func TestAPITeamUser(t *testing.T) {
defer tests.PrepareTestEnv(t)()
-
- normalUsername := "user2"
- session := loginUser(t, normalUsername)
- token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadOrganization)
- req := NewRequest(t, "GET", "/api/v1/teams/1/members/user1").
- AddTokenAuth(token)
- MakeRequest(t, req, http.StatusNotFound)
-
- req = NewRequest(t, "GET", "/api/v1/teams/1/members/user2").
- AddTokenAuth(token)
- resp := MakeRequest(t, req, http.StatusOK)
- var user2 *api.User
- DecodeJSON(t, resp, &user2)
- user2.Created = user2.Created.In(time.Local)
- user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user2"})
-
- expectedUser := convert.ToUser(db.DefaultContext, user, user)
-
- // test time via unix timestamp
- assert.EqualValues(t, expectedUser.LastLogin.Unix(), user2.LastLogin.Unix())
- assert.EqualValues(t, expectedUser.Created.Unix(), user2.Created.Unix())
- expectedUser.LastLogin = user2.LastLogin
- expectedUser.Created = user2.Created
-
- assert.Equal(t, expectedUser, user2)
+ user2Session := loginUser(t, "user2")
+ user2Token := getTokenForLoggedInUser(t, user2Session, auth_model.AccessTokenScopeWriteOrganization)
+
+ t.Run("User2ReadUser1", func(t *testing.T) {
+ req := NewRequest(t, "GET", "/api/v1/teams/1/members/user1").AddTokenAuth(user2Token)
+ MakeRequest(t, req, http.StatusNotFound)
+ })
+
+ t.Run("User2ReadSelf", func(t *testing.T) {
+ // read self user
+ req := NewRequest(t, "GET", "/api/v1/teams/1/members/user2").AddTokenAuth(user2Token)
+ resp := MakeRequest(t, req, http.StatusOK)
+ var user2 *api.User
+ DecodeJSON(t, resp, &user2)
+ user2.Created = user2.Created.In(time.Local)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user2"})
+
+ expectedUser := convert.ToUser(db.DefaultContext, user, user)
+
+ // test time via unix timestamp
+ assert.Equal(t, expectedUser.LastLogin.Unix(), user2.LastLogin.Unix())
+ assert.Equal(t, expectedUser.Created.Unix(), user2.Created.Unix())
+ expectedUser.LastLogin = user2.LastLogin
+ expectedUser.Created = user2.Created
+
+ assert.Equal(t, expectedUser, user2)
+ })
}
diff --git a/tests/integration/api_token_test.go b/tests/integration/api_token_test.go
index 01d18ef6f1..1770358d21 100644
--- a/tests/integration/api_token_test.go
+++ b/tests/integration/api_token_test.go
@@ -507,7 +507,7 @@ func runTestCase(t *testing.T, testCase *requiredScopeTestCase, user *user_model
} else if minRequiredLevel == auth_model.Write {
unauthorizedLevel = auth_model.Read
} else {
- assert.FailNow(t, "Invalid test case: Unknown access token scope level: %v", minRequiredLevel)
+ assert.FailNow(t, "Invalid test case", "Unknown access token scope level: %v", minRequiredLevel)
}
}
diff --git a/tests/integration/api_twofa_test.go b/tests/integration/api_twofa_test.go
index 18e6fa91b7..938feba61a 100644
--- a/tests/integration/api_twofa_test.go
+++ b/tests/integration/api_twofa_test.go
@@ -94,7 +94,7 @@ func TestBasicAuthWithWebAuthn(t *testing.T) {
}
var userParsed userResponse
DecodeJSON(t, resp, &userParsed)
- assert.EqualValues(t, "Basic authorization is not allowed while webAuthn enrolled", userParsed.Message)
+ assert.Equal(t, "basic authorization is not allowed while WebAuthn enrolled", userParsed.Message)
// user32 has webauthn enrolled, he can't request git protocol with basic auth
req = NewRequest(t, "GET", "/user2/repo1/info/refs")
diff --git a/tests/integration/api_user_block_test.go b/tests/integration/api_user_block_test.go
index ae6b9eb849..6f73b089df 100644
--- a/tests/integration/api_user_block_test.go
+++ b/tests/integration/api_user_block_test.go
@@ -76,7 +76,7 @@ func TestBlockUser(t *testing.T) {
blockeeName := "user10"
t.Run("Block", func(t *testing.T) {
- req := NewRequest(t, "PUT", fmt.Sprintf("/api/v1/user/blocks/%s", blockeeName))
+ req := NewRequest(t, "PUT", "/api/v1/user/blocks/"+blockeeName)
MakeRequest(t, req, http.StatusUnauthorized)
assert.EqualValues(t, 1, countStars(t, blockerID, blockeeID))
@@ -84,7 +84,7 @@ func TestBlockUser(t *testing.T) {
assert.EqualValues(t, 1, countRepositoryTransfers(t, blockerID, blockeeID))
assert.EqualValues(t, 1, countCollaborations(t, blockerID, blockeeID))
- req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/user/blocks/%s", blockeeName)).
+ req = NewRequest(t, "GET", "/api/v1/user/blocks/"+blockeeName).
AddTokenAuth(blockerToken)
MakeRequest(t, req, http.StatusNotFound)
@@ -97,15 +97,15 @@ func TestBlockUser(t *testing.T) {
assert.EqualValues(t, 0, countRepositoryTransfers(t, blockerID, blockeeID))
assert.EqualValues(t, 0, countCollaborations(t, blockerID, blockeeID))
- req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/user/blocks/%s", blockeeName)).
+ req = NewRequest(t, "GET", "/api/v1/user/blocks/"+blockeeName).
AddTokenAuth(blockerToken)
MakeRequest(t, req, http.StatusNoContent)
- req = NewRequest(t, "PUT", fmt.Sprintf("/api/v1/user/blocks/%s", blockeeName)).
+ req = NewRequest(t, "PUT", "/api/v1/user/blocks/"+blockeeName).
AddTokenAuth(blockerToken)
MakeRequest(t, req, http.StatusBadRequest) // can't block blocked user
- req = NewRequest(t, "PUT", fmt.Sprintf("/api/v1/user/blocks/%s", "org3")).
+ req = NewRequest(t, "PUT", "/api/v1/user/blocks/"+"org3").
AddTokenAuth(blockerToken)
MakeRequest(t, req, http.StatusBadRequest) // can't block organization
@@ -124,18 +124,18 @@ func TestBlockUser(t *testing.T) {
})
t.Run("Unblock", func(t *testing.T) {
- req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/user/blocks/%s", blockeeName))
+ req := NewRequest(t, "DELETE", "/api/v1/user/blocks/"+blockeeName)
MakeRequest(t, req, http.StatusUnauthorized)
- req = NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/user/blocks/%s", blockeeName)).
+ req = NewRequest(t, "DELETE", "/api/v1/user/blocks/"+blockeeName).
AddTokenAuth(blockerToken)
MakeRequest(t, req, http.StatusNoContent)
- req = NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/user/blocks/%s", blockeeName)).
+ req = NewRequest(t, "DELETE", "/api/v1/user/blocks/"+blockeeName).
AddTokenAuth(blockerToken)
MakeRequest(t, req, http.StatusBadRequest)
- req = NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/user/blocks/%s", "org3")).
+ req = NewRequest(t, "DELETE", "/api/v1/user/blocks/"+"org3").
AddTokenAuth(blockerToken)
MakeRequest(t, req, http.StatusBadRequest)
diff --git a/tests/integration/api_user_email_test.go b/tests/integration/api_user_email_test.go
index 6441e2ed8e..5b6f0708ea 100644
--- a/tests/integration/api_user_email_test.go
+++ b/tests/integration/api_user_email_test.go
@@ -28,7 +28,7 @@ func TestAPIListEmails(t *testing.T) {
var emails []*api.Email
DecodeJSON(t, resp, &emails)
- assert.EqualValues(t, []*api.Email{
+ assert.Equal(t, []*api.Email{
{
Email: "user2@example.com",
Verified: true,
@@ -66,7 +66,7 @@ func TestAPIAddEmail(t *testing.T) {
var emails []*api.Email
DecodeJSON(t, resp, &emails)
- assert.EqualValues(t, []*api.Email{
+ assert.Equal(t, []*api.Email{
{
Email: "user2@example.com",
Verified: true,
@@ -119,7 +119,7 @@ func TestAPIDeleteEmail(t *testing.T) {
var emails []*api.Email
DecodeJSON(t, resp, &emails)
- assert.EqualValues(t, []*api.Email{
+ assert.Equal(t, []*api.Email{
{
Email: "user2@example.com",
Verified: true,
diff --git a/tests/integration/api_user_follow_test.go b/tests/integration/api_user_follow_test.go
index fe20af6769..6cb31a6802 100644
--- a/tests/integration/api_user_follow_test.go
+++ b/tests/integration/api_user_follow_test.go
@@ -32,7 +32,7 @@ func TestAPIFollow(t *testing.T) {
t.Run("Follow", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "PUT", fmt.Sprintf("/api/v1/user/following/%s", user1)).
+ req := NewRequest(t, "PUT", "/api/v1/user/following/"+user1).
AddTokenAuth(token2)
MakeRequest(t, req, http.StatusNoContent)
@@ -110,11 +110,11 @@ func TestAPIFollow(t *testing.T) {
t.Run("CheckMyFollowing", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/user/following/%s", user1)).
+ req := NewRequest(t, "GET", "/api/v1/user/following/"+user1).
AddTokenAuth(token2)
MakeRequest(t, req, http.StatusNoContent)
- req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/user/following/%s", user2)).
+ req = NewRequest(t, "GET", "/api/v1/user/following/"+user2).
AddTokenAuth(token1)
MakeRequest(t, req, http.StatusNotFound)
})
@@ -122,7 +122,7 @@ func TestAPIFollow(t *testing.T) {
t.Run("Unfollow", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/user/following/%s", user1)).
+ req := NewRequest(t, "DELETE", "/api/v1/user/following/"+user1).
AddTokenAuth(token2)
MakeRequest(t, req, http.StatusNoContent)
})
diff --git a/tests/integration/api_user_info_test.go b/tests/integration/api_user_info_test.go
index 89f7266859..06353eabe0 100644
--- a/tests/integration/api_user_info_test.go
+++ b/tests/integration/api_user_info_test.go
@@ -4,7 +4,6 @@
package integration
import (
- "fmt"
"net/http"
"testing"
@@ -31,7 +30,7 @@ func TestAPIUserInfo(t *testing.T) {
t.Run("GetInfo", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/users/%s", user2)).
+ req := NewRequest(t, "GET", "/api/v1/users/"+user2).
AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
@@ -39,17 +38,17 @@ func TestAPIUserInfo(t *testing.T) {
DecodeJSON(t, resp, &u)
assert.Equal(t, user2, u.UserName)
- req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/users/%s", user2))
+ req = NewRequest(t, "GET", "/api/v1/users/"+user2)
MakeRequest(t, req, http.StatusNotFound)
// test if the placaholder Mail is returned if a User is not logged in
- req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/users/%s", org3.Name))
+ req = NewRequest(t, "GET", "/api/v1/users/"+org3.Name)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &u)
assert.Equal(t, org3.GetPlaceholderEmail(), u.Email)
// Test if the correct Mail is returned if a User is logged in
- req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/users/%s", org3.Name)).
+ req = NewRequest(t, "GET", "/api/v1/users/"+org3.Name).
AddTokenAuth(token)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &u)
diff --git a/tests/integration/api_user_search_test.go b/tests/integration/api_user_search_test.go
index 5604a14259..97264969eb 100644
--- a/tests/integration/api_user_search_test.go
+++ b/tests/integration/api_user_search_test.go
@@ -66,7 +66,7 @@ func TestAPIUserSearchNotLoggedIn(t *testing.T) {
for _, user := range results.Data {
assert.Contains(t, user.UserName, query)
modelUser = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: user.ID})
- assert.EqualValues(t, modelUser.GetPlaceholderEmail(), user.Email)
+ assert.Equal(t, modelUser.GetPlaceholderEmail(), user.Email)
}
}
@@ -85,8 +85,8 @@ func TestAPIUserSearchSystemUsers(t *testing.T) {
assert.NotEmpty(t, results.Data)
if assert.Len(t, results.Data, 1) {
user := results.Data[0]
- assert.EqualValues(t, user.UserName, systemUser.Name)
- assert.EqualValues(t, user.ID, systemUser.ID)
+ assert.Equal(t, user.UserName, systemUser.Name)
+ assert.Equal(t, user.ID, systemUser.ID)
}
})
}
@@ -108,7 +108,7 @@ func TestAPIUserSearchAdminLoggedInUserHidden(t *testing.T) {
for _, user := range results.Data {
assert.Contains(t, user.UserName, query)
assert.NotEmpty(t, user.Email)
- assert.EqualValues(t, "private", user.Visibility)
+ assert.Equal(t, "private", user.Visibility)
}
}
diff --git a/tests/integration/api_user_secrets_test.go b/tests/integration/api_user_secrets_test.go
index 56bf30e804..10024ac090 100644
--- a/tests/integration/api_user_secrets_test.go
+++ b/tests/integration/api_user_secrets_test.go
@@ -4,7 +4,6 @@
package integration
import (
- "fmt"
"net/http"
"testing"
@@ -55,7 +54,7 @@ func TestAPIUserSecrets(t *testing.T) {
}
for _, c := range cases {
- req := NewRequestWithJSON(t, "PUT", fmt.Sprintf("/api/v1/user/actions/secrets/%s", c.Name), api.CreateOrUpdateSecretOption{
+ req := NewRequestWithJSON(t, "PUT", "/api/v1/user/actions/secrets/"+c.Name, api.CreateOrUpdateSecretOption{
Data: "data",
}).AddTokenAuth(token)
MakeRequest(t, req, c.ExpectedStatus)
@@ -64,7 +63,7 @@ func TestAPIUserSecrets(t *testing.T) {
t.Run("Update", func(t *testing.T) {
name := "update_secret"
- url := fmt.Sprintf("/api/v1/user/actions/secrets/%s", name)
+ url := "/api/v1/user/actions/secrets/" + name
req := NewRequestWithJSON(t, "PUT", url, api.CreateOrUpdateSecretOption{
Data: "initial",
@@ -79,7 +78,7 @@ func TestAPIUserSecrets(t *testing.T) {
t.Run("Delete", func(t *testing.T) {
name := "delete_secret"
- url := fmt.Sprintf("/api/v1/user/actions/secrets/%s", name)
+ url := "/api/v1/user/actions/secrets/" + name
req := NewRequestWithJSON(t, "PUT", url, api.CreateOrUpdateSecretOption{
Data: "initial",
diff --git a/tests/integration/api_user_star_test.go b/tests/integration/api_user_star_test.go
index 0062889a92..989e7ab1d1 100644
--- a/tests/integration/api_user_star_test.go
+++ b/tests/integration/api_user_star_test.go
@@ -11,7 +11,9 @@ import (
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
@@ -30,13 +32,13 @@ func TestAPIStar(t *testing.T) {
t.Run("Star", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "PUT", fmt.Sprintf("/api/v1/user/starred/%s", repo)).
+ req := NewRequest(t, "PUT", "/api/v1/user/starred/"+repo).
AddTokenAuth(tokenWithUserScope)
MakeRequest(t, req, http.StatusNoContent)
// blocked user can't star a repo
user34 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 34})
- req = NewRequest(t, "PUT", fmt.Sprintf("/api/v1/user/starred/%s", repo)).
+ req = NewRequest(t, "PUT", "/api/v1/user/starred/"+repo).
AddTokenAuth(getUserToken(t, user34.Name, auth_model.AccessTokenScopeWriteRepository))
MakeRequest(t, req, http.StatusForbidden)
})
@@ -74,11 +76,11 @@ func TestAPIStar(t *testing.T) {
t.Run("IsStarring", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/user/starred/%s", repo)).
+ req := NewRequest(t, "GET", "/api/v1/user/starred/"+repo).
AddTokenAuth(tokenWithUserScope)
MakeRequest(t, req, http.StatusNoContent)
- req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/user/starred/%s", repo+"notexisting")).
+ req = NewRequest(t, "GET", "/api/v1/user/starred/"+repo+"notexisting").
AddTokenAuth(tokenWithUserScope)
MakeRequest(t, req, http.StatusNotFound)
})
@@ -86,8 +88,70 @@ func TestAPIStar(t *testing.T) {
t.Run("Unstar", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
- req := NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/user/starred/%s", repo)).
+ req := NewRequest(t, "DELETE", "/api/v1/user/starred/"+repo).
AddTokenAuth(tokenWithUserScope)
MakeRequest(t, req, http.StatusNoContent)
})
}
+
+func TestAPIStarDisabled(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+
+ user := "user1"
+ repo := "user2/repo1"
+
+ session := loginUser(t, user)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadUser)
+ tokenWithUserScope := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteUser, auth_model.AccessTokenScopeWriteRepository)
+
+ defer test.MockVariableValue(&setting.Repository.DisableStars, true)()
+
+ t.Run("Star", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ req := NewRequest(t, "PUT", "/api/v1/user/starred/"+repo).
+ AddTokenAuth(tokenWithUserScope)
+ MakeRequest(t, req, http.StatusForbidden)
+
+ user34 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 34})
+ req = NewRequest(t, "PUT", "/api/v1/user/starred/"+repo).
+ AddTokenAuth(getUserToken(t, user34.Name, auth_model.AccessTokenScopeWriteRepository))
+ MakeRequest(t, req, http.StatusForbidden)
+ })
+
+ t.Run("GetStarredRepos", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/users/%s/starred", user)).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusForbidden)
+ })
+
+ t.Run("GetMyStarredRepos", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ req := NewRequest(t, "GET", "/api/v1/user/starred").
+ AddTokenAuth(tokenWithUserScope)
+ MakeRequest(t, req, http.StatusForbidden)
+ })
+
+ t.Run("IsStarring", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ req := NewRequest(t, "GET", "/api/v1/user/starred/"+repo).
+ AddTokenAuth(tokenWithUserScope)
+ MakeRequest(t, req, http.StatusForbidden)
+
+ req = NewRequest(t, "GET", "/api/v1/user/starred/"+repo+"notexisting").
+ AddTokenAuth(tokenWithUserScope)
+ MakeRequest(t, req, http.StatusForbidden)
+ })
+
+ t.Run("Unstar", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ req := NewRequest(t, "DELETE", "/api/v1/user/starred/"+repo).
+ AddTokenAuth(tokenWithUserScope)
+ MakeRequest(t, req, http.StatusForbidden)
+ })
+}
diff --git a/tests/integration/api_user_variables_test.go b/tests/integration/api_user_variables_test.go
index 9fd84ddf81..d430c9e21d 100644
--- a/tests/integration/api_user_variables_test.go
+++ b/tests/integration/api_user_variables_test.go
@@ -4,7 +4,6 @@
package integration
import (
- "fmt"
"net/http"
"testing"
@@ -30,11 +29,11 @@ func TestAPIUserVariables(t *testing.T) {
},
{
Name: "_",
- ExpectedStatus: http.StatusNoContent,
+ ExpectedStatus: http.StatusCreated,
},
{
Name: "TEST_VAR",
- ExpectedStatus: http.StatusNoContent,
+ ExpectedStatus: http.StatusCreated,
},
{
Name: "test_var",
@@ -63,7 +62,7 @@ func TestAPIUserVariables(t *testing.T) {
}
for _, c := range cases {
- req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/user/actions/variables/%s", c.Name), api.CreateVariableOption{
+ req := NewRequestWithJSON(t, "POST", "/api/v1/user/actions/variables/"+c.Name, api.CreateVariableOption{
Value: "value",
}).AddTokenAuth(token)
MakeRequest(t, req, c.ExpectedStatus)
@@ -72,11 +71,11 @@ func TestAPIUserVariables(t *testing.T) {
t.Run("UpdateUserVariable", func(t *testing.T) {
variableName := "test_update_var"
- url := fmt.Sprintf("/api/v1/user/actions/variables/%s", variableName)
+ url := "/api/v1/user/actions/variables/" + variableName
req := NewRequestWithJSON(t, "POST", url, api.CreateVariableOption{
Value: "initial_val",
}).AddTokenAuth(token)
- MakeRequest(t, req, http.StatusNoContent)
+ MakeRequest(t, req, http.StatusCreated)
cases := []struct {
Name string
@@ -118,7 +117,7 @@ func TestAPIUserVariables(t *testing.T) {
}
for _, c := range cases {
- req := NewRequestWithJSON(t, "PUT", fmt.Sprintf("/api/v1/user/actions/variables/%s", c.Name), api.UpdateVariableOption{
+ req := NewRequestWithJSON(t, "PUT", "/api/v1/user/actions/variables/"+c.Name, api.UpdateVariableOption{
Name: c.UpdateName,
Value: "updated_val",
}).AddTokenAuth(token)
@@ -128,12 +127,12 @@ func TestAPIUserVariables(t *testing.T) {
t.Run("DeleteRepoVariable", func(t *testing.T) {
variableName := "test_delete_var"
- url := fmt.Sprintf("/api/v1/user/actions/variables/%s", variableName)
+ url := "/api/v1/user/actions/variables/" + variableName
req := NewRequestWithJSON(t, "POST", url, api.CreateVariableOption{
Value: "initial_val",
}).AddTokenAuth(token)
- MakeRequest(t, req, http.StatusNoContent)
+ MakeRequest(t, req, http.StatusCreated)
req = NewRequest(t, "DELETE", url).AddTokenAuth(token)
MakeRequest(t, req, http.StatusNoContent)
diff --git a/tests/integration/api_wiki_test.go b/tests/integration/api_wiki_test.go
index 05d90fc4e3..8e5f67e282 100644
--- a/tests/integration/api_wiki_test.go
+++ b/tests/integration/api_wiki_test.go
@@ -172,6 +172,19 @@ func TestAPIListWikiPages(t *testing.T) {
assert.Equal(t, dummymeta, meta)
}
+func testAPICreateWikiPage(t *testing.T, session *TestSession, userName, repoName, title string, status int) {
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/new", userName, repoName)
+
+ req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateWikiPageOptions{
+ Title: title,
+ ContentBase64: base64.StdEncoding.EncodeToString([]byte("Wiki page content for API unit tests")),
+ Message: "",
+ }).AddTokenAuth(token)
+ MakeRequest(t, req, status)
+}
+
func TestAPINewWikiPage(t *testing.T) {
for _, title := range []string{
"New page",
@@ -180,16 +193,7 @@ func TestAPINewWikiPage(t *testing.T) {
defer tests.PrepareTestEnv(t)()
username := "user2"
session := loginUser(t, username)
- token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
-
- urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/new", username, "repo1")
-
- req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateWikiPageOptions{
- Title: title,
- ContentBase64: base64.StdEncoding.EncodeToString([]byte("Wiki page content for API unit tests")),
- Message: "",
- }).AddTokenAuth(token)
- MakeRequest(t, req, http.StatusCreated)
+ testAPICreateWikiPage(t, session, username, "repo1", title, http.StatusCreated)
}
}
diff --git a/tests/integration/auth_ldap_test.go b/tests/integration/auth_ldap_test.go
index 5d37244331..24f0c03bed 100644
--- a/tests/integration/auth_ldap_test.go
+++ b/tests/integration/auth_ldap_test.go
@@ -4,7 +4,6 @@
package integration
import (
- "context"
"net/http"
"os"
"strings"
@@ -16,6 +15,7 @@ import (
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/optional"
+ "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/translation"
"code.gitea.io/gitea/modules/util"
@@ -238,7 +238,7 @@ func TestLDAPUserSync(t *testing.T) {
defer tests.PrepareTestEnv(t)()
te.addAuthSource(t)
- err := auth.SyncExternalUsers(context.Background(), true)
+ err := auth.SyncExternalUsers(t.Context(), true)
assert.NoError(t, err)
// Check if users exists
@@ -279,7 +279,7 @@ func TestLDAPUserSyncWithEmptyUsernameAttribute(t *testing.T) {
htmlDoc := NewHTMLParser(t, resp.Body)
- tr := htmlDoc.doc.Find("table.table tbody tr")
+ tr := htmlDoc.doc.Find("table.table tbody tr:not(.no-results-row)")
assert.Equal(t, 0, tr.Length())
}
@@ -292,7 +292,7 @@ func TestLDAPUserSyncWithEmptyUsernameAttribute(t *testing.T) {
MakeRequest(t, req, http.StatusSeeOther)
}
- require.NoError(t, auth.SyncExternalUsers(context.Background(), true))
+ require.NoError(t, auth.SyncExternalUsers(t.Context(), true))
authSource := unittest.AssertExistsAndLoadBean(t, &auth_model.Source{
Name: payload["name"],
@@ -328,11 +328,11 @@ func TestLDAPUserSyncWithGroupFilter(t *testing.T) {
u := te.otherLDAPUsers[0]
testLoginFailed(t, u.UserName, u.Password, translation.NewLocale("en-US").TrString("form.username_password_incorrect"))
- require.NoError(t, auth.SyncExternalUsers(context.Background(), true))
+ require.NoError(t, auth.SyncExternalUsers(t.Context(), true))
// Assert members of LDAP group "cn=git" are added
for _, gitLDAPUser := range te.gitLDAPUsers {
- unittest.BeanExists(t, &user_model.User{
+ unittest.AssertExistsAndLoadBean(t, &user_model.User{
Name: gitLDAPUser.UserName,
})
}
@@ -351,7 +351,7 @@ func TestLDAPUserSyncWithGroupFilter(t *testing.T) {
ldapConfig.GroupFilter = "(cn=ship_crew)"
require.NoError(t, auth_model.UpdateSource(db.DefaultContext, ldapSource))
- require.NoError(t, auth.SyncExternalUsers(context.Background(), true))
+ require.NoError(t, auth.SyncExternalUsers(t.Context(), true))
for _, gitLDAPUser := range te.gitLDAPUsers {
if gitLDAPUser.UserName == "fry" || gitLDAPUser.UserName == "leela" || gitLDAPUser.UserName == "bender" {
@@ -392,7 +392,7 @@ func TestLDAPUserSSHKeySync(t *testing.T) {
defer tests.PrepareTestEnv(t)()
te.addAuthSource(t, ldapAuthOptions{attributeSSHPublicKey: "sshPublicKey"})
- require.NoError(t, auth.SyncExternalUsers(context.Background(), true))
+ require.NoError(t, auth.SyncExternalUsers(t.Context(), true))
// Check if users has SSH keys synced
for _, u := range te.gitLDAPUsers {
@@ -432,14 +432,14 @@ func TestLDAPGroupTeamSyncAddMember(t *testing.T) {
assert.NoError(t, err)
team, err := organization.GetTeam(db.DefaultContext, org.ID, "team11")
assert.NoError(t, err)
- require.NoError(t, auth.SyncExternalUsers(context.Background(), true))
+ require.NoError(t, auth.SyncExternalUsers(t.Context(), true))
for _, gitLDAPUser := range te.gitLDAPUsers {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{
Name: gitLDAPUser.UserName,
})
usersOrgs, err := db.Find[organization.Organization](db.DefaultContext, organization.FindOrgOptions{
- UserID: user.ID,
- IncludePrivate: true,
+ UserID: user.ID,
+ IncludeVisibility: structs.VisibleTypePrivate,
})
assert.NoError(t, err)
allOrgTeams, err := organization.GetUserOrgTeams(db.DefaultContext, org.ID, user.ID)
diff --git a/tests/integration/benchmarks_test.go b/tests/integration/benchmarks_test.go
deleted file mode 100644
index 62da761d2d..0000000000
--- a/tests/integration/benchmarks_test.go
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2017 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package integration
-
-import (
- "math/rand/v2"
- "net/http"
- "net/url"
- "testing"
-
- repo_model "code.gitea.io/gitea/models/repo"
- "code.gitea.io/gitea/models/unittest"
- api "code.gitea.io/gitea/modules/structs"
-)
-
-// StringWithCharset random string (from https://www.calhoun.io/creating-random-strings-in-go/)
-func StringWithCharset(length int, charset string) string {
- b := make([]byte, length)
- for i := range b {
- b[i] = charset[rand.IntN(len(charset))]
- }
- return string(b)
-}
-
-func BenchmarkRepoBranchCommit(b *testing.B) {
- onGiteaRun(b, func(b *testing.B, u *url.URL) {
- samples := []int64{1, 2, 3}
- b.ResetTimer()
-
- for _, repoID := range samples {
- b.StopTimer()
- repo := unittest.AssertExistsAndLoadBean(b, &repo_model.Repository{ID: repoID})
- b.StartTimer()
- b.Run(repo.Name, func(b *testing.B) {
- session := loginUser(b, "user2")
- b.ResetTimer()
- b.Run("CreateBranch", func(b *testing.B) {
- b.StopTimer()
- branchName := StringWithCharset(5+rand.IntN(10), "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- b.Run("new_"+branchName, func(b *testing.B) {
- b.Skip("benchmark broken") // TODO fix
- testAPICreateBranch(b, session, repo.OwnerName, repo.Name, repo.DefaultBranch, "new_"+branchName, http.StatusCreated)
- })
- }
- })
- b.Run("GetBranches", func(b *testing.B) {
- req := NewRequestf(b, "GET", "/api/v1/repos/%s/branches", repo.FullName())
- session.MakeRequest(b, req, http.StatusOK)
- })
- b.Run("AccessCommits", func(b *testing.B) {
- var branches []*api.Branch
- req := NewRequestf(b, "GET", "/api/v1/repos/%s/branches", repo.FullName())
- resp := session.MakeRequest(b, req, http.StatusOK)
- DecodeJSON(b, resp, &branches)
- b.ResetTimer() // We measure from here
- if len(branches) != 0 {
- for i := 0; i < b.N; i++ {
- req := NewRequestf(b, "GET", "/api/v1/repos/%s/commits?sha=%s", repo.FullName(), branches[i%len(branches)].Name)
- session.MakeRequest(b, req, http.StatusOK)
- }
- }
- })
- })
- }
- })
-}
diff --git a/tests/integration/change_default_branch_test.go b/tests/integration/change_default_branch_test.go
index 729eb1e4ce..9b61cff9fd 100644
--- a/tests/integration/change_default_branch_test.go
+++ b/tests/integration/change_default_branch_test.go
@@ -6,12 +6,16 @@ package integration
import (
"fmt"
"net/http"
+ "strconv"
"testing"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/tests"
+
+ "github.com/stretchr/testify/assert"
)
func TestChangeDefaultBranch(t *testing.T) {
@@ -38,3 +42,96 @@ func TestChangeDefaultBranch(t *testing.T) {
})
session.MakeRequest(t, req, http.StatusNotFound)
}
+
+func checkDivergence(t *testing.T, session *TestSession, branchesURL, expectedDefaultBranch string, expectedBranchToDivergence map[string]git.DivergeObject) {
+ req := NewRequest(t, "GET", branchesURL)
+ resp := session.MakeRequest(t, req, http.StatusOK)
+
+ htmlDoc := NewHTMLParser(t, resp.Body)
+
+ branchNodes := htmlDoc.doc.Find(".branch-name").Nodes
+ branchNames := []string{}
+ for _, node := range branchNodes {
+ branchNames = append(branchNames, node.FirstChild.Data)
+ }
+
+ expectBranchCount := len(expectedBranchToDivergence)
+
+ assert.Len(t, branchNames, expectBranchCount+1)
+ assert.Equal(t, expectedDefaultBranch, branchNames[0])
+
+ allCountBehindNodes := htmlDoc.doc.Find(".count-behind").Nodes
+ allCountAheadNodes := htmlDoc.doc.Find(".count-ahead").Nodes
+
+ assert.Len(t, allCountAheadNodes, expectBranchCount)
+ assert.Len(t, allCountBehindNodes, expectBranchCount)
+
+ for i := range expectBranchCount {
+ branchName := branchNames[i+1]
+ assert.Contains(t, expectedBranchToDivergence, branchName)
+
+ expectedCountAhead := expectedBranchToDivergence[branchName].Ahead
+ expectedCountBehind := expectedBranchToDivergence[branchName].Behind
+ countAhead, err := strconv.Atoi(allCountAheadNodes[i].FirstChild.Data)
+ assert.NoError(t, err)
+ countBehind, err := strconv.Atoi(allCountBehindNodes[i].FirstChild.Data)
+ assert.NoError(t, err)
+
+ assert.Equal(t, expectedCountAhead, countAhead)
+ assert.Equal(t, expectedCountBehind, countBehind)
+ }
+}
+
+func TestChangeDefaultBranchDivergence(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16})
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
+
+ session := loginUser(t, owner.Name)
+ branchesURL := fmt.Sprintf("/%s/%s/branches", owner.Name, repo.Name)
+ settingsBranchesURL := fmt.Sprintf("/%s/%s/settings/branches", owner.Name, repo.Name)
+
+ // check branch divergence before switching default branch
+ expectedBranchToDivergenceBefore := map[string]git.DivergeObject{
+ "not-signed": {
+ Ahead: 0,
+ Behind: 0,
+ },
+ "good-sign-not-yet-validated": {
+ Ahead: 0,
+ Behind: 1,
+ },
+ "good-sign": {
+ Ahead: 1,
+ Behind: 3,
+ },
+ }
+ checkDivergence(t, session, branchesURL, "master", expectedBranchToDivergenceBefore)
+
+ // switch default branch
+ newDefaultBranch := "good-sign-not-yet-validated"
+ csrf := GetUserCSRFToken(t, session)
+ req := NewRequestWithValues(t, "POST", settingsBranchesURL, map[string]string{
+ "_csrf": csrf,
+ "action": "default_branch",
+ "branch": newDefaultBranch,
+ })
+ session.MakeRequest(t, req, http.StatusSeeOther)
+
+ // check branch divergence after switching default branch
+ expectedBranchToDivergenceAfter := map[string]git.DivergeObject{
+ "master": {
+ Ahead: 1,
+ Behind: 0,
+ },
+ "not-signed": {
+ Ahead: 1,
+ Behind: 0,
+ },
+ "good-sign": {
+ Ahead: 1,
+ Behind: 2,
+ },
+ }
+ checkDivergence(t, session, branchesURL, newDefaultBranch, expectedBranchToDivergenceAfter)
+}
diff --git a/tests/integration/cmd_keys_test.go b/tests/integration/cmd_keys_test.go
index 61f11c58b0..3878302ef0 100644
--- a/tests/integration/cmd_keys_test.go
+++ b/tests/integration/cmd_keys_test.go
@@ -13,7 +13,7 @@ import (
"code.gitea.io/gitea/modules/util"
"github.com/stretchr/testify/assert"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
)
func Test_CmdKeys(t *testing.T) {
@@ -36,18 +36,21 @@ func Test_CmdKeys(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- out := new(bytes.Buffer)
- app := cli.NewApp()
- app.Writer = out
- app.Commands = []*cli.Command{cmd.CmdKeys}
+ var stdout, stderr bytes.Buffer
+ app := &cli.Command{
+ Writer: &stdout,
+ ErrWriter: &stderr,
+ Commands: []*cli.Command{cmd.CmdKeys},
+ }
cmd.CmdKeys.HideHelp = true
- err := app.Run(append([]string{"prog"}, tt.args...))
+ err := app.Run(t.Context(), append([]string{"prog"}, tt.args...))
if tt.wantErr {
assert.Error(t, err)
+ assert.Equal(t, tt.expectedOutput, stderr.String())
} else {
assert.NoError(t, err)
+ assert.Equal(t, tt.expectedOutput, stdout.String())
}
- assert.Equal(t, tt.expectedOutput, out.String())
})
}
})
diff --git a/tests/integration/compare_test.go b/tests/integration/compare_test.go
index d960416b3a..0648777fed 100644
--- a/tests/integration/compare_test.go
+++ b/tests/integration/compare_test.go
@@ -27,7 +27,7 @@ func TestCompareTag(t *testing.T) {
req := NewRequest(t, "GET", "/user2/repo1/compare/v1.1...master")
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
- selection := htmlDoc.doc.Find(".choose.branch .filter.dropdown")
+ selection := htmlDoc.doc.Find(".ui.dropdown.select-branch")
// A dropdown for both base and head.
assert.Lenf(t, selection.Nodes, 2, "The template has changed")
@@ -44,7 +44,7 @@ func TestCompareDefault(t *testing.T) {
req := NewRequest(t, "GET", "/user2/repo1/compare/v1.1")
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
- selection := htmlDoc.doc.Find(".choose.branch .filter.dropdown")
+ selection := htmlDoc.doc.Find(".ui.dropdown.select-branch")
assert.Lenf(t, selection.Nodes, 2, "The template has changed")
}
@@ -133,7 +133,7 @@ func TestCompareCodeExpand(t *testing.T) {
Readme: "Default",
AutoInit: true,
DefaultBranch: "main",
- })
+ }, true)
assert.NoError(t, err)
session := loginUser(t, user1.Name)
diff --git a/tests/integration/db_collation_test.go b/tests/integration/db_collation_test.go
index acec4aa5d1..339bfce71c 100644
--- a/tests/integration/db_collation_test.go
+++ b/tests/integration/db_collation_test.go
@@ -75,7 +75,7 @@ func TestDatabaseCollation(t *testing.T) {
defer test.MockVariableValue(&setting.Database.CharsetCollation, "utf8mb4_bin")()
r, err := db.CheckCollations(x)
assert.NoError(t, err)
- assert.EqualValues(t, "utf8mb4_bin", r.ExpectedCollation)
+ assert.Equal(t, "utf8mb4_bin", r.ExpectedCollation)
assert.NoError(t, db.ConvertDatabaseTable())
r, err = db.CheckCollations(x)
assert.NoError(t, err)
diff --git a/tests/integration/delete_user_test.go b/tests/integration/delete_user_test.go
index ad3c882882..4b02c4725a 100644
--- a/tests/integration/delete_user_test.go
+++ b/tests/integration/delete_user_test.go
@@ -4,7 +4,6 @@
package integration
import (
- "fmt"
"net/http"
"testing"
@@ -34,7 +33,7 @@ func TestUserDeleteAccount(t *testing.T) {
session := loginUser(t, "user8")
csrf := GetUserCSRFToken(t, session)
- urlStr := fmt.Sprintf("/user/settings/account/delete?password=%s", userPassword)
+ urlStr := "/user/settings/account/delete?password=" + userPassword
req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
"_csrf": csrf,
})
@@ -49,7 +48,7 @@ func TestUserDeleteAccountStillOwnRepos(t *testing.T) {
session := loginUser(t, "user2")
csrf := GetUserCSRFToken(t, session)
- urlStr := fmt.Sprintf("/user/settings/account/delete?password=%s", userPassword)
+ urlStr := "/user/settings/account/delete?password=" + userPassword
req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
"_csrf": csrf,
})
diff --git a/tests/integration/dump_restore_test.go b/tests/integration/dump_restore_test.go
index 47bb6f76e9..d2d43075c3 100644
--- a/tests/integration/dump_restore_test.go
+++ b/tests/integration/dump_restore_test.go
@@ -4,7 +4,6 @@
package integration
import (
- "context"
"errors"
"fmt"
"net/url"
@@ -21,7 +20,6 @@ import (
base "code.gitea.io/gitea/modules/migration"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
- "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/migrations"
"github.com/stretchr/testify/assert"
@@ -44,10 +42,7 @@ func TestDumpRestore(t *testing.T) {
reponame := "repo1"
- basePath, err := os.MkdirTemp("", reponame)
- assert.NoError(t, err)
- defer util.RemoveAll(basePath)
-
+ basePath := t.TempDir()
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame})
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
session := loginUser(t, repoOwner.Name)
@@ -57,7 +52,7 @@ func TestDumpRestore(t *testing.T) {
// Phase 1: dump repo1 from the Gitea instance to the filesystem
//
- ctx := context.Background()
+ ctx := t.Context()
opts := migrations.MigrateOptions{
GitServiceType: structs.GiteaService,
Issues: true,
@@ -66,10 +61,10 @@ func TestDumpRestore(t *testing.T) {
Milestones: true,
Comments: true,
AuthToken: token,
- CloneAddr: repo.CloneLink().HTTPS,
+ CloneAddr: repo.CloneLinkGeneral(t.Context()).HTTPS,
RepoName: reponame,
}
- err = migrations.DumpRepository(ctx, basePath, repoOwner.Name, opts)
+ err := migrations.DumpRepository(ctx, basePath, repoOwner.Name, opts)
assert.NoError(t, err)
//
@@ -96,7 +91,7 @@ func TestDumpRestore(t *testing.T) {
// Phase 3: dump restored from the Gitea instance to the filesystem
//
opts.RepoName = newreponame
- opts.CloneAddr = newrepo.CloneLink().HTTPS
+ opts.CloneAddr = newrepo.CloneLinkGeneral(t.Context()).HTTPS
err = migrations.DumpRepository(ctx, basePath, repoOwner.Name, opts)
assert.NoError(t, err)
@@ -183,7 +178,7 @@ func (c *compareDump) assertEquals(repoBefore, repoAfter *repo_model.Repository)
}).([]*base.Comment)
assert.True(c.t, ok)
for _, comment := range comments {
- assert.EqualValues(c.t, issue.Number, comment.IssueIndex)
+ assert.Equal(c.t, issue.Number, comment.IssueIndex)
}
}
@@ -210,7 +205,7 @@ func (c *compareDump) assertEquals(repoBefore, repoAfter *repo_model.Repository)
comments, ok := c.assertEqual(filename, []base.Comment{}, compareFields{}).([]*base.Comment)
assert.True(c.t, ok)
for _, comment := range comments {
- assert.EqualValues(c.t, pr.Number, comment.IssueIndex)
+ assert.Equal(c.t, pr.Number, comment.IssueIndex)
}
}
}
@@ -218,7 +213,7 @@ func (c *compareDump) assertEquals(repoBefore, repoAfter *repo_model.Repository)
func (c *compareDump) assertLoadYAMLFiles(beforeFilename, afterFilename string, before, after any) {
_, beforeErr := os.Stat(beforeFilename)
_, afterErr := os.Stat(afterFilename)
- assert.EqualValues(c.t, errors.Is(beforeErr, os.ErrNotExist), errors.Is(afterErr, os.ErrNotExist))
+ assert.Equal(c.t, errors.Is(beforeErr, os.ErrNotExist), errors.Is(afterErr, os.ErrNotExist))
if errors.Is(beforeErr, os.ErrNotExist) {
return
}
@@ -270,7 +265,7 @@ func (c *compareDump) assertEqual(filename string, kind any, fields compareField
}
func (c *compareDump) assertEqualSlices(before, after reflect.Value, fields compareFields) any {
- assert.EqualValues(c.t, before.Len(), after.Len())
+ assert.Equal(c.t, before.Len(), after.Len())
if before.Len() == after.Len() {
for i := 0; i < before.Len(); i++ {
_ = c.assertEqualValues(
@@ -303,15 +298,15 @@ func (c *compareDump) assertEqualValues(before, after reflect.Value, fields comp
assert.True(c.t, ok)
as, ok := ai.(string)
assert.True(c.t, ok)
- assert.EqualValues(c.t, compare.transform(bs), compare.transform(as))
+ assert.Equal(c.t, compare.transform(bs), compare.transform(as))
continue
}
if compare.before != nil && compare.after != nil {
//
// The fields are expected to have different values
//
- assert.EqualValues(c.t, compare.before, bi)
- assert.EqualValues(c.t, compare.after, ai)
+ assert.Equal(c.t, compare.before, bi)
+ assert.Equal(c.t, compare.after, ai)
continue
}
if compare.nested != nil {
@@ -322,7 +317,7 @@ func (c *compareDump) assertEqualValues(before, after reflect.Value, fields comp
continue
}
}
- assert.EqualValues(c.t, bi, ai)
+ assert.Equal(c.t, bi, ai)
}
return after.Interface()
}
diff --git a/tests/integration/editor_test.go b/tests/integration/editor_test.go
index f0f71b80d1..8c45d8881c 100644
--- a/tests/integration/editor_test.go
+++ b/tests/integration/editor_test.go
@@ -4,175 +4,457 @@
package integration
import (
+ "bytes"
"fmt"
+ "io"
+ "maps"
+ "mime/multipart"
"net/http"
"net/http/httptest"
"net/url"
"path"
+ "strings"
"testing"
- "code.gitea.io/gitea/modules/json"
- gitea_context "code.gitea.io/gitea/services/context"
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/test"
+ "code.gitea.io/gitea/modules/translation"
+ "code.gitea.io/gitea/modules/util"
+ "code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
-func TestCreateFile(t *testing.T) {
+func TestEditor(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) {
- session := loginUser(t, "user2")
- testCreateFile(t, session, "user2", "repo1", "master", "test.txt", "Content")
+ sessionUser2 := loginUser(t, "user2")
+ t.Run("EditFileNotAllowed", testEditFileNotAllowed)
+ t.Run("DiffPreview", testEditorDiffPreview)
+ t.Run("CreateFile", testEditorCreateFile)
+ t.Run("EditFile", func(t *testing.T) {
+ testEditFile(t, sessionUser2, "user2", "repo1", "master", "README.md", "Hello, World (direct)\n")
+ testEditFileToNewBranch(t, sessionUser2, "user2", "repo1", "master", "feature/test", "README.md", "Hello, World (commit-to-new-branch)\n")
+ })
+ t.Run("PatchFile", testEditorPatchFile)
+ t.Run("DeleteFile", func(t *testing.T) {
+ viewLink := "/user2/repo1/src/branch/branch2/README.md"
+ sessionUser2.MakeRequest(t, NewRequest(t, "GET", viewLink), http.StatusOK)
+ testEditorActionPostRequest(t, sessionUser2, "/user2/repo1/_delete/branch2/README.md", map[string]string{"commit_choice": "direct"})
+ sessionUser2.MakeRequest(t, NewRequest(t, "GET", viewLink), http.StatusNotFound)
+ })
+ t.Run("ForkToEditFile", func(t *testing.T) {
+ testForkToEditFile(t, loginUser(t, "user4"), "user4", "user2", "repo1", "master", "README.md")
+ })
+ t.Run("WebGitCommitEmail", testEditorWebGitCommitEmail)
+ t.Run("ProtectedBranch", testEditorProtectedBranch)
+ })
+}
+
+func testEditorCreateFile(t *testing.T) {
+ session := loginUser(t, "user2")
+ testCreateFile(t, session, "user2", "repo1", "master", "", "test.txt", "Content")
+ testEditorActionPostRequestError(t, session, "/user2/repo1/_new/master/", map[string]string{
+ "tree_path": "test.txt",
+ "commit_choice": "direct",
+ "new_branch_name": "master",
+ }, `A file named "test.txt" already exists in this repository.`)
+ testEditorActionPostRequestError(t, session, "/user2/repo1/_new/master/", map[string]string{
+ "tree_path": "test.txt",
+ "commit_choice": "commit-to-new-branch",
+ "new_branch_name": "master",
+ }, `Branch "master" already exists in this repository.`)
+}
+
+func testCreateFile(t *testing.T, session *TestSession, user, repo, baseBranchName, newBranchName, filePath, content string) {
+ commitChoice := "direct"
+ if newBranchName != "" && newBranchName != baseBranchName {
+ commitChoice = "commit-to-new-branch"
+ }
+ testEditorActionEdit(t, session, user, repo, "_new", baseBranchName, "", map[string]string{
+ "tree_path": filePath,
+ "content": content,
+ "commit_choice": commitChoice,
+ "new_branch_name": newBranchName,
+ })
+}
+
+func testEditorProtectedBranch(t *testing.T) {
+ session := loginUser(t, "user2")
+ // Change the "master" branch to "protected"
+ req := NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/edit", map[string]string{
+ "_csrf": GetUserCSRFToken(t, session),
+ "rule_name": "master",
+ "enable_push": "true",
})
+ session.MakeRequest(t, req, http.StatusSeeOther)
+ flashMsg := session.GetCookieFlashMessage()
+ assert.Equal(t, `Branch protection for rule "master" has been updated.`, flashMsg.SuccessMsg)
+
+ // Try to commit a file to the "master" branch and it should fail
+ resp := testEditorActionPostRequest(t, session, "/user2/repo1/_new/master/", map[string]string{"tree_path": "test-protected-branch.txt", "commit_choice": "direct"})
+ assert.Equal(t, http.StatusBadRequest, resp.Code)
+ assert.Equal(t, `Cannot commit to protected branch "master".`, test.ParseJSONError(resp.Body.Bytes()).ErrorMessage)
}
-func testCreateFile(t *testing.T, session *TestSession, user, repo, branch, filePath, content string) *httptest.ResponseRecorder {
- // Request editor page
- newURL := fmt.Sprintf("/%s/%s/_new/%s/", user, repo, branch)
- req := NewRequest(t, "GET", newURL)
+func testEditorActionPostRequest(t *testing.T, session *TestSession, requestPath string, params map[string]string) *httptest.ResponseRecorder {
+ req := NewRequest(t, "GET", requestPath)
resp := session.MakeRequest(t, req, http.StatusOK)
+ htmlDoc := NewHTMLParser(t, resp.Body)
+ form := map[string]string{
+ "_csrf": htmlDoc.GetCSRF(),
+ "last_commit": htmlDoc.GetInputValueByName("last_commit"),
+ }
+ maps.Copy(form, params)
+ req = NewRequestWithValues(t, "POST", requestPath, form)
+ return session.MakeRequest(t, req, NoExpectedStatus)
+}
- doc := NewHTMLParser(t, resp.Body)
- lastCommit := doc.GetInputValueByName("last_commit")
- assert.NotEmpty(t, lastCommit)
+func testEditorActionPostRequestError(t *testing.T, session *TestSession, requestPath string, params map[string]string, errorMessage string) {
+ resp := testEditorActionPostRequest(t, session, requestPath, params)
+ assert.Equal(t, http.StatusBadRequest, resp.Code)
+ assert.Equal(t, errorMessage, test.ParseJSONError(resp.Body.Bytes()).ErrorMessage)
+}
- // Save new file to master branch
- req = NewRequestWithValues(t, "POST", newURL, map[string]string{
- "_csrf": doc.GetCSRF(),
- "last_commit": lastCommit,
- "tree_path": filePath,
- "content": content,
+func testEditorActionEdit(t *testing.T, session *TestSession, user, repo, editorAction, branch, filePath string, params map[string]string) *httptest.ResponseRecorder {
+ params["tree_path"] = util.IfZero(params["tree_path"], filePath)
+ newBranchName := util.Iif(params["commit_choice"] == "direct", branch, params["new_branch_name"])
+ resp := testEditorActionPostRequest(t, session, fmt.Sprintf("/%s/%s/%s/%s/%s", user, repo, editorAction, branch, filePath), params)
+ assert.Equal(t, http.StatusOK, resp.Code)
+ assert.NotEmpty(t, test.RedirectURL(resp))
+ req := NewRequest(t, "GET", path.Join(user, repo, "raw/branch", newBranchName, params["tree_path"]))
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ assert.Equal(t, params["content"], resp.Body.String())
+ return resp
+}
+
+func testEditFile(t *testing.T, session *TestSession, user, repo, branch, filePath, newContent string) {
+ testEditorActionEdit(t, session, user, repo, "_edit", branch, filePath, map[string]string{
+ "content": newContent,
"commit_choice": "direct",
})
- return session.MakeRequest(t, req, http.StatusSeeOther)
}
-func TestCreateFileOnProtectedBranch(t *testing.T) {
- onGiteaRun(t, func(t *testing.T, u *url.URL) {
- session := loginUser(t, "user2")
-
- csrf := GetUserCSRFToken(t, session)
- // Change master branch to protected
- req := NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/edit", map[string]string{
- "_csrf": csrf,
- "rule_name": "master",
- "enable_push": "true",
- })
- session.MakeRequest(t, req, http.StatusSeeOther)
- // Check if master branch has been locked successfully
- flashCookie := session.GetCookie(gitea_context.CookieNameFlash)
- assert.NotNil(t, flashCookie)
- assert.EqualValues(t, "success%3DBranch%2Bprotection%2Bfor%2Brule%2B%2522master%2522%2Bhas%2Bbeen%2Bupdated.", flashCookie.Value)
+func testEditFileToNewBranch(t *testing.T, session *TestSession, user, repo, branch, targetBranch, filePath, newContent string) {
+ testEditorActionEdit(t, session, user, repo, "_edit", branch, filePath, map[string]string{
+ "content": newContent,
+ "commit_choice": "commit-to-new-branch",
+ "new_branch_name": targetBranch,
+ })
+}
- // Request editor page
- req = NewRequest(t, "GET", "/user2/repo1/_new/master/")
- resp := session.MakeRequest(t, req, http.StatusOK)
+func testEditorDiffPreview(t *testing.T) {
+ session := loginUser(t, "user2")
+ req := NewRequestWithValues(t, "POST", "/user2/repo1/_preview/master/README.md", map[string]string{
+ "_csrf": GetUserCSRFToken(t, session),
+ "content": "Hello, World (Edited)\n",
+ })
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ assert.Contains(t, resp.Body.String(), `<span class="added-code">Hello, World (Edited)</span>`)
+}
- doc := NewHTMLParser(t, resp.Body)
- lastCommit := doc.GetInputValueByName("last_commit")
- assert.NotEmpty(t, lastCommit)
+func testEditorPatchFile(t *testing.T) {
+ session := loginUser(t, "user2")
+ pathContentCommon := `diff --git a/patch-file-1.txt b/patch-file-1.txt
+new file mode 100644
+index 0000000000..aaaaaaaaaa
+--- /dev/null
++++ b/patch-file-1.txt
+@@ -0,0 +1 @@
++`
+ testEditorActionPostRequest(t, session, "/user2/repo1/_diffpatch/master/", map[string]string{
+ "content": pathContentCommon + "patched content\n",
+ "commit_choice": "commit-to-new-branch",
+ "new_branch_name": "patched-branch",
+ })
+ resp := MakeRequest(t, NewRequest(t, "GET", "/user2/repo1/raw/branch/patched-branch/patch-file-1.txt"), http.StatusOK)
+ assert.Equal(t, "patched content\n", resp.Body.String())
- // Save new file to master branch
- req = NewRequestWithValues(t, "POST", "/user2/repo1/_new/master/", map[string]string{
- "_csrf": doc.GetCSRF(),
- "last_commit": lastCommit,
- "tree_path": "test.txt",
- "content": "Content",
- "commit_choice": "direct",
- })
+ // patch again, it should fail
+ resp = testEditorActionPostRequest(t, session, "/user2/repo1/_diffpatch/patched-branch/", map[string]string{
+ "content": pathContentCommon + "another patched content\n",
+ "commit_choice": "commit-to-new-branch",
+ "new_branch_name": "patched-branch-1",
+ })
+ assert.Equal(t, "Unable to apply patch", test.ParseJSONError(resp.Body.Bytes()).ErrorMessage)
+}
- resp = session.MakeRequest(t, req, http.StatusOK)
- // Check body for error message
- assert.Contains(t, resp.Body.String(), "Cannot commit to protected branch &#34;master&#34;.")
+func testEditorWebGitCommitEmail(t *testing.T) {
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ require.True(t, user.KeepEmailPrivate)
+
+ repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+ gitRepo, _ := git.OpenRepository(git.DefaultContext, repo1.RepoPath())
+ defer gitRepo.Close()
+ getLastCommit := func(t *testing.T) *git.Commit {
+ c, err := gitRepo.GetBranchCommit("master")
+ require.NoError(t, err)
+ return c
+ }
- // remove the protected branch
- csrf = GetUserCSRFToken(t, session)
+ session := loginUser(t, user.Name)
- // Change master branch to protected
- req = NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/1/delete", map[string]string{
- "_csrf": csrf,
+ makeReq := func(t *testing.T, link string, params map[string]string, expectedUserName, expectedEmail string) *httptest.ResponseRecorder {
+ lastCommit := getLastCommit(t)
+ params["_csrf"] = GetUserCSRFToken(t, session)
+ params["last_commit"] = lastCommit.ID.String()
+ params["commit_choice"] = "direct"
+ req := NewRequestWithValues(t, "POST", link, params)
+ resp := session.MakeRequest(t, req, NoExpectedStatus)
+ newCommit := getLastCommit(t)
+ if expectedUserName == "" {
+ require.Equal(t, lastCommit.ID.String(), newCommit.ID.String())
+ respErr := test.ParseJSONError(resp.Body.Bytes())
+ assert.Equal(t, translation.NewLocale("en-US").TrString("repo.editor.invalid_commit_email"), respErr.ErrorMessage)
+ } else {
+ require.NotEqual(t, lastCommit.ID.String(), newCommit.ID.String())
+ assert.Equal(t, expectedUserName, newCommit.Author.Name)
+ assert.Equal(t, expectedEmail, newCommit.Author.Email)
+ assert.Equal(t, expectedUserName, newCommit.Committer.Name)
+ assert.Equal(t, expectedEmail, newCommit.Committer.Email)
+ }
+ return resp
+ }
+
+ uploadFile := func(t *testing.T, name, content string) string {
+ body := &bytes.Buffer{}
+ uploadForm := multipart.NewWriter(body)
+ file, _ := uploadForm.CreateFormFile("file", name)
+ _, _ = io.Copy(file, strings.NewReader(content))
+ _ = uploadForm.WriteField("_csrf", GetUserCSRFToken(t, session))
+ _ = uploadForm.Close()
+
+ req := NewRequestWithBody(t, "POST", "/user2/repo1/upload-file", body)
+ req.Header.Add("Content-Type", uploadForm.FormDataContentType())
+ resp := session.MakeRequest(t, req, http.StatusOK)
+
+ respMap := map[string]string{}
+ DecodeJSON(t, resp, &respMap)
+ return respMap["uuid"]
+ }
+
+ t.Run("EmailInactive", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+ email := unittest.AssertExistsAndLoadBean(t, &user_model.EmailAddress{ID: 35, UID: user.ID})
+ require.False(t, email.IsActivated)
+ makeReq(t, "/user2/repo1/_edit/master/README.md", map[string]string{
+ "tree_path": "README.md",
+ "content": "test content",
+ "commit_email": email.Email,
+ }, "", "")
+ })
+
+ t.Run("EmailInvalid", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+ email := unittest.AssertExistsAndLoadBean(t, &user_model.EmailAddress{ID: 1, IsActivated: true})
+ require.NotEqual(t, email.UID, user.ID)
+ makeReq(t, "/user2/repo1/_edit/master/README.md", map[string]string{
+ "tree_path": "README.md",
+ "content": "test content",
+ "commit_email": email.Email,
+ }, "", "")
+ })
+
+ testWebGit := func(t *testing.T, linkForKeepPrivate string, paramsForKeepPrivate map[string]string, linkForChosenEmail string, paramsForChosenEmail map[string]string) (resp1, resp2 *httptest.ResponseRecorder) {
+ t.Run("DefaultEmailKeepPrivate", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+ paramsForKeepPrivate["commit_email"] = ""
+ resp1 = makeReq(t, linkForKeepPrivate, paramsForKeepPrivate, "User Two", "user2@noreply.example.org")
+ })
+ t.Run("ChooseEmail", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+ paramsForChosenEmail["commit_email"] = "user2@example.com"
+ resp2 = makeReq(t, linkForChosenEmail, paramsForChosenEmail, "User Two", "user2@example.com")
})
+ return resp1, resp2
+ }
- resp = session.MakeRequest(t, req, http.StatusOK)
+ t.Run("Edit", func(t *testing.T) {
+ testWebGit(t,
+ "/user2/repo1/_edit/master/README.md", map[string]string{"tree_path": "README.md", "content": "for keep private"},
+ "/user2/repo1/_edit/master/README.md", map[string]string{"tree_path": "README.md", "content": "for chosen email"},
+ )
+ })
+
+ t.Run("UploadDelete", func(t *testing.T) {
+ file1UUID := uploadFile(t, "file1", "File 1")
+ file2UUID := uploadFile(t, "file2", "File 2")
+ testWebGit(t,
+ "/user2/repo1/_upload/master", map[string]string{"files": file1UUID},
+ "/user2/repo1/_upload/master", map[string]string{"files": file2UUID},
+ )
+ testWebGit(t,
+ "/user2/repo1/_delete/master/file1", map[string]string{},
+ "/user2/repo1/_delete/master/file2", map[string]string{},
+ )
+ })
- res := make(map[string]string)
- assert.NoError(t, json.NewDecoder(resp.Body).Decode(&res))
- assert.EqualValues(t, "/user2/repo1/settings/branches", res["redirect"])
+ t.Run("ApplyPatchCherryPick", func(t *testing.T) {
+ testWebGit(t,
+ "/user2/repo1/_diffpatch/master", map[string]string{
+ "tree_path": "__dummy__",
+ "content": `diff --git a/patch-file-1.txt b/patch-file-1.txt
+new file mode 100644
+index 0000000000..aaaaaaaaaa
+--- /dev/null
++++ b/patch-file-1.txt
+@@ -0,0 +1 @@
++File 1
+`,
+ },
+ "/user2/repo1/_diffpatch/master", map[string]string{
+ "tree_path": "__dummy__",
+ "content": `diff --git a/patch-file-2.txt b/patch-file-2.txt
+new file mode 100644
+index 0000000000..bbbbbbbbbb
+--- /dev/null
++++ b/patch-file-2.txt
+@@ -0,0 +1 @@
++File 2
+`,
+ },
+ )
- // Check if master branch has been locked successfully
- flashCookie = session.GetCookie(gitea_context.CookieNameFlash)
- assert.NotNil(t, flashCookie)
- assert.EqualValues(t, "error%3DRemoving%2Bbranch%2Bprotection%2Brule%2B%25221%2522%2Bfailed.", flashCookie.Value)
+ commit1, err := gitRepo.GetCommitByPath("patch-file-1.txt")
+ require.NoError(t, err)
+ commit2, err := gitRepo.GetCommitByPath("patch-file-2.txt")
+ require.NoError(t, err)
+ resp1, _ := testWebGit(t,
+ "/user2/repo1/_cherrypick/"+commit1.ID.String()+"/master", map[string]string{"revert": "true"},
+ "/user2/repo1/_cherrypick/"+commit2.ID.String()+"/master", map[string]string{"revert": "true"},
+ )
+
+ // By the way, test the "cherrypick" page: a successful revert redirects to the main branch
+ assert.Equal(t, "/user2/repo1/src/branch/master", test.RedirectURL(resp1))
})
}
-func testEditFile(t *testing.T, session *TestSession, user, repo, branch, filePath, newContent string) *httptest.ResponseRecorder {
- // Get to the 'edit this file' page
- req := NewRequest(t, "GET", path.Join(user, repo, "_edit", branch, filePath))
- resp := session.MakeRequest(t, req, http.StatusOK)
+func testForkToEditFile(t *testing.T, session *TestSession, user, owner, repo, branch, filePath string) {
+ forkToEdit := func(t *testing.T, session *TestSession, owner, repo, operation, branch, filePath string) {
+ // visit the base repo, see the "Add File" button
+ req := NewRequest(t, "GET", path.Join(owner, repo))
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ htmlDoc := NewHTMLParser(t, resp.Body)
+ AssertHTMLElement(t, htmlDoc, ".repo-add-file", 1)
- htmlDoc := NewHTMLParser(t, resp.Body)
- lastCommit := htmlDoc.GetInputValueByName("last_commit")
- assert.NotEmpty(t, lastCommit)
-
- // Submit the edits
- req = NewRequestWithValues(t, "POST", path.Join(user, repo, "_edit", branch, filePath),
- map[string]string{
- "_csrf": htmlDoc.GetCSRF(),
- "last_commit": lastCommit,
- "tree_path": filePath,
- "content": newContent,
- "commit_choice": "direct",
- },
- )
- session.MakeRequest(t, req, http.StatusSeeOther)
+ // attempt to edit a file, see the guideline page
+ req = NewRequest(t, "GET", path.Join(owner, repo, operation, branch, filePath))
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ assert.Contains(t, resp.Body.String(), "Fork Repository to Propose Changes")
- // Verify the change
- req = NewRequest(t, "GET", path.Join(user, repo, "raw/branch", branch, filePath))
- resp = session.MakeRequest(t, req, http.StatusOK)
- assert.EqualValues(t, newContent, resp.Body.String())
+ // fork the repository
+ req = NewRequestWithValues(t, "POST", path.Join(owner, repo, "_fork", branch), map[string]string{"_csrf": GetUserCSRFToken(t, session)})
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ assert.JSONEq(t, `{"redirect":""}`, resp.Body.String())
+ }
- return resp
-}
+ t.Run("ForkButArchived", func(t *testing.T) {
+ // Fork repository because we can't edit it
+ forkToEdit(t, session, owner, repo, "_edit", branch, filePath)
-func testEditFileToNewBranch(t *testing.T, session *TestSession, user, repo, branch, targetBranch, filePath, newContent string) *httptest.ResponseRecorder {
- // Get to the 'edit this file' page
- req := NewRequest(t, "GET", path.Join(user, repo, "_edit", branch, filePath))
- resp := session.MakeRequest(t, req, http.StatusOK)
+ // Archive the repository
+ req := NewRequestWithValues(t, "POST", path.Join(user, repo, "settings"),
+ map[string]string{
+ "_csrf": GetUserCSRFToken(t, session),
+ "repo_name": repo,
+ "action": "archive",
+ },
+ )
+ session.MakeRequest(t, req, http.StatusSeeOther)
- htmlDoc := NewHTMLParser(t, resp.Body)
- lastCommit := htmlDoc.GetInputValueByName("last_commit")
- assert.NotEmpty(t, lastCommit)
-
- // Submit the edits
- req = NewRequestWithValues(t, "POST", path.Join(user, repo, "_edit", branch, filePath),
- map[string]string{
- "_csrf": htmlDoc.GetCSRF(),
- "last_commit": lastCommit,
- "tree_path": filePath,
- "content": newContent,
- "commit_choice": "commit-to-new-branch",
- "new_branch_name": targetBranch,
- },
- )
- session.MakeRequest(t, req, http.StatusSeeOther)
+ // Check editing archived repository is disabled
+ req = NewRequest(t, "GET", path.Join(owner, repo, "_edit", branch, filePath)).SetHeader("Accept", "text/html")
+ resp := session.MakeRequest(t, req, http.StatusNotFound)
+ assert.Contains(t, resp.Body.String(), "You have forked this repository but your fork is not editable.")
- // Verify the change
- req = NewRequest(t, "GET", path.Join(user, repo, "raw/branch", targetBranch, filePath))
- resp = session.MakeRequest(t, req, http.StatusOK)
- assert.EqualValues(t, newContent, resp.Body.String())
+ // Unfork the repository
+ req = NewRequestWithValues(t, "POST", path.Join(user, repo, "settings"),
+ map[string]string{
+ "_csrf": GetUserCSRFToken(t, session),
+ "repo_name": repo,
+ "action": "convert_fork",
+ },
+ )
+ session.MakeRequest(t, req, http.StatusSeeOther)
+ })
- return resp
-}
+ // Fork repository again, and check the existence of the forked repo with unique name
+ forkToEdit(t, session, owner, repo, "_edit", branch, filePath)
+ session.MakeRequest(t, NewRequestf(t, "GET", "/%s/%s-1", user, repo), http.StatusOK)
-func TestEditFile(t *testing.T) {
- onGiteaRun(t, func(t *testing.T, u *url.URL) {
- session := loginUser(t, "user2")
- testEditFile(t, session, "user2", "repo1", "master", "README.md", "Hello, World (Edited)\n")
+ t.Run("CheckBaseRepoForm", func(t *testing.T) {
+ // the base repo's edit form should have the correct action and upload links (pointing to the forked repo)
+ req := NewRequest(t, "GET", path.Join(owner, repo, "_upload", branch, filePath)+"?foo=bar")
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ htmlDoc := NewHTMLParser(t, resp.Body)
+
+ uploadForm := htmlDoc.doc.Find(".form-fetch-action")
+ formAction := uploadForm.AttrOr("action", "")
+ assert.Equal(t, fmt.Sprintf("/%s/%s-1/_upload/%s/%s?from_base_branch=%s&foo=bar", user, repo, branch, filePath, branch), formAction)
+ uploadLink := uploadForm.Find(".dropzone").AttrOr("data-link-url", "")
+ assert.Equal(t, fmt.Sprintf("/%s/%s-1/upload-file", user, repo), uploadLink)
+ newBranchName := uploadForm.Find("input[name=new_branch_name]").AttrOr("value", "")
+ assert.Equal(t, user+"-patch-1", newBranchName)
+ commitChoice := uploadForm.Find("input[name=commit_choice][checked]").AttrOr("value", "")
+ assert.Equal(t, "commit-to-new-branch", commitChoice)
+ lastCommit := uploadForm.Find("input[name=last_commit]").AttrOr("value", "")
+ assert.NotEmpty(t, lastCommit)
})
-}
-func TestEditFileToNewBranch(t *testing.T) {
- onGiteaRun(t, func(t *testing.T, u *url.URL) {
- session := loginUser(t, "user2")
- testEditFileToNewBranch(t, session, "user2", "repo1", "master", "feature/test", "README.md", "Hello, World (Edited)\n")
+ t.Run("ViewBaseEditFormAndCommitToFork", func(t *testing.T) {
+ req := NewRequest(t, "GET", path.Join(owner, repo, "_edit", branch, filePath))
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ htmlDoc := NewHTMLParser(t, resp.Body)
+ editRequestForm := map[string]string{
+ "_csrf": GetUserCSRFToken(t, session),
+ "last_commit": htmlDoc.GetInputValueByName("last_commit"),
+ "tree_path": filePath,
+ "content": "new content in fork",
+ "commit_choice": "commit-to-new-branch",
+ }
+ // change a file in the forked repo with existing branch name (should fail)
+ editRequestForm["new_branch_name"] = "master"
+ req = NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s-1/_edit/%s/%s?from_base_branch=%s", user, repo, branch, filePath, branch), editRequestForm)
+ resp = session.MakeRequest(t, req, http.StatusBadRequest)
+ respJSON := test.ParseJSONError(resp.Body.Bytes())
+ assert.Equal(t, `Branch "master" already exists in your fork. Please choose a new branch name.`, respJSON.ErrorMessage)
+
+ // change a file in the forked repo (should succeed)
+ newBranchName := htmlDoc.GetInputValueByName("new_branch_name")
+ editRequestForm["new_branch_name"] = newBranchName
+ req = NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s-1/_edit/%s/%s?from_base_branch=%s", user, repo, branch, filePath, branch), editRequestForm)
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ assert.Equal(t, fmt.Sprintf("/%s/%s/compare/%s...%s/%s-1:%s", owner, repo, branch, user, repo, newBranchName), test.RedirectURL(resp))
+
+ // check the file in the fork's branch is changed
+ req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s-1/src/branch/%s/%s", user, repo, newBranchName, filePath))
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ assert.Contains(t, resp.Body.String(), "new content in fork")
})
}
+
+func testEditFileNotAllowed(t *testing.T) {
+ sessionUser1 := loginUser(t, "user1") // admin, all access
+ sessionUser4 := loginUser(t, "user4")
+ // "_cherrypick" has a different route pattern, so skip its test
+ operations := []string{"_new", "_edit", "_delete", "_upload", "_diffpatch"}
+ for _, operation := range operations {
+ t.Run(operation, func(t *testing.T) {
+ // Branch does not exist
+ targetLink := path.Join("user2", "repo1", operation, "missing", "README.md")
+ sessionUser1.MakeRequest(t, NewRequest(t, "GET", targetLink), http.StatusNotFound)
+
+ // Private repository
+ targetLink = path.Join("user2", "repo2", operation, "master", "Home.md")
+ sessionUser1.MakeRequest(t, NewRequest(t, "GET", targetLink), http.StatusOK)
+ sessionUser4.MakeRequest(t, NewRequest(t, "GET", targetLink), http.StatusNotFound)
+
+ // Empty repository
+ targetLink = path.Join("org41", "repo61", operation, "master", "README.md")
+ sessionUser1.MakeRequest(t, NewRequest(t, "GET", targetLink), http.StatusNotFound)
+ })
+ }
+}
diff --git a/tests/integration/empty_repo_test.go b/tests/integration/empty_repo_test.go
index 630a3c03af..127df5919d 100644
--- a/tests/integration/empty_repo_test.go
+++ b/tests/integration/empty_repo_test.go
@@ -10,10 +10,11 @@ import (
"io"
"mime/multipart"
"net/http"
- "net/http/httptest"
+ "strings"
"testing"
auth_model "code.gitea.io/gitea/models/auth"
+ "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
@@ -21,12 +22,14 @@ import (
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/test"
+ "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
-func testAPINewFile(t *testing.T, session *TestSession, user, repo, branch, treePath, content string) *httptest.ResponseRecorder {
+func testAPINewFile(t *testing.T, session *TestSession, user, repo, branch, treePath, content string) {
url := fmt.Sprintf("/%s/%s/_new/%s", user, repo, branch)
req := NewRequestWithValues(t, "POST", url, map[string]string{
"_csrf": GetUserCSRFToken(t, session),
@@ -34,7 +37,8 @@ func testAPINewFile(t *testing.T, session *TestSession, user, repo, branch, tree
"tree_path": treePath,
"content": content,
})
- return session.MakeRequest(t, req, http.StatusSeeOther)
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ assert.NotEmpty(t, test.RedirectURL(resp))
}
func TestEmptyRepo(t *testing.T) {
@@ -58,8 +62,27 @@ func TestEmptyRepoAddFile(t *testing.T) {
defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user30")
- req := NewRequest(t, "GET", "/user30/empty/_new/"+setting.Repository.DefaultBranch)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository)
+
+ // test web page
+ req := NewRequest(t, "GET", "/user30/empty")
resp := session.MakeRequest(t, req, http.StatusOK)
+ bodyString := resp.Body.String()
+ assert.Contains(t, bodyString, "empty-repo-guide")
+ assert.True(t, test.IsNormalPageCompleted(bodyString))
+
+ // test api
+ req = NewRequest(t, "GET", "/api/v1/repos/user30/empty/raw/main/README.md").AddTokenAuth(token)
+ session.MakeRequest(t, req, http.StatusNotFound)
+
+ // test feed
+ req = NewRequest(t, "GET", "/user30/empty/rss/branch/main/README.md").AddTokenAuth(token).SetHeader("Accept", "application/rss+xml")
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ assert.Contains(t, resp.Body.String(), "</rss>")
+
+ // create a new file
+ req = NewRequest(t, "GET", "/user30/empty/_new/"+setting.Repository.DefaultBranch)
+ resp = session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body).Find(`input[name="commit_choice"]`)
assert.Empty(t, doc.AttrOr("checked", "_no_"))
req = NewRequestWithValues(t, "POST", "/user30/empty/_new/"+setting.Repository.DefaultBranch, map[string]string{
@@ -69,13 +92,43 @@ func TestEmptyRepoAddFile(t *testing.T) {
"content": "newly-added-test-file",
})
- resp = session.MakeRequest(t, req, http.StatusSeeOther)
+ resp = session.MakeRequest(t, req, http.StatusOK)
redirect := test.RedirectURL(resp)
assert.Equal(t, "/user30/empty/src/branch/"+setting.Repository.DefaultBranch+"/test-file.md", redirect)
req = NewRequest(t, "GET", redirect)
resp = session.MakeRequest(t, req, http.StatusOK)
assert.Contains(t, resp.Body.String(), "newly-added-test-file")
+
+ // the repo is not empty anymore
+ req = NewRequest(t, "GET", "/user30/empty")
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ assert.Contains(t, resp.Body.String(), "test-file.md")
+
+ // if the repo is in incorrect state, it should be able to self-heal (recover to correct state)
+ testEmptyOrBrokenRecover := func(t *testing.T, isEmpty, isBroken bool) {
+ user30EmptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: 30, Name: "empty"})
+ user30EmptyRepo.IsEmpty = isEmpty
+ user30EmptyRepo.Status = util.Iif(isBroken, repo_model.RepositoryBroken, repo_model.RepositoryReady)
+ user30EmptyRepo.DefaultBranch = "no-such"
+ _, err := db.GetEngine(db.DefaultContext).ID(user30EmptyRepo.ID).Cols("is_empty", "status", "default_branch").Update(user30EmptyRepo)
+ require.NoError(t, err)
+ user30EmptyRepo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: 30, Name: "empty"})
+ assert.Equal(t, isEmpty, user30EmptyRepo.IsEmpty)
+ assert.Equal(t, isBroken, user30EmptyRepo.Status == repo_model.RepositoryBroken)
+
+ req = NewRequest(t, "GET", "/user30/empty")
+ resp = session.MakeRequest(t, req, http.StatusSeeOther)
+ redirect = test.RedirectURL(resp)
+ assert.Equal(t, "/user30/empty", redirect)
+
+ req = NewRequest(t, "GET", "/user30/empty")
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ assert.Contains(t, resp.Body.String(), "test-file.md")
+ }
+ testEmptyOrBrokenRecover(t, true, false)
+ testEmptyOrBrokenRecover(t, false, true)
+ testEmptyOrBrokenRecover(t, true, true)
}
func TestEmptyRepoUploadFile(t *testing.T) {
@@ -91,7 +144,7 @@ func TestEmptyRepoUploadFile(t *testing.T) {
mpForm := multipart.NewWriter(body)
_ = mpForm.WriteField("_csrf", GetUserCSRFToken(t, session))
file, _ := mpForm.CreateFormFile("file", "uploaded-file.txt")
- _, _ = io.Copy(file, bytes.NewBufferString("newly-uploaded-test-file"))
+ _, _ = io.Copy(file, strings.NewReader("newly-uploaded-test-file"))
_ = mpForm.Close()
req = NewRequestWithBody(t, "POST", "/user30/empty/upload-file", body)
@@ -106,9 +159,9 @@ func TestEmptyRepoUploadFile(t *testing.T) {
"files": respMap["uuid"],
"tree_path": "",
})
- resp = session.MakeRequest(t, req, http.StatusSeeOther)
+ resp = session.MakeRequest(t, req, http.StatusOK)
redirect := test.RedirectURL(resp)
- assert.Equal(t, "/user30/empty/src/branch/"+setting.Repository.DefaultBranch+"/", redirect)
+ assert.Equal(t, "/user30/empty/src/branch/"+setting.Repository.DefaultBranch, redirect)
req = NewRequest(t, "GET", redirect)
resp = session.MakeRequest(t, req, http.StatusOK)
@@ -133,7 +186,7 @@ func TestEmptyRepoAddFileByAPI(t *testing.T) {
var fileResponse api.FileResponse
DecodeJSON(t, resp, &fileResponse)
expectedHTMLURL := setting.AppURL + "user30/empty/src/branch/new_branch/new-file.txt"
- assert.EqualValues(t, expectedHTMLURL, *fileResponse.Content.HTMLURL)
+ assert.Equal(t, expectedHTMLURL, *fileResponse.Content.HTMLURL)
req = NewRequest(t, "GET", "/user30/empty/src/branch/new_branch/new-file.txt")
resp = session.MakeRequest(t, req, http.StatusOK)
diff --git a/tests/integration/ephemeral_actions_runner_deletion_test.go b/tests/integration/ephemeral_actions_runner_deletion_test.go
new file mode 100644
index 0000000000..40f8c643a8
--- /dev/null
+++ b/tests/integration/ephemeral_actions_runner_deletion_test.go
@@ -0,0 +1,77 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package integration
+
+import (
+ "testing"
+
+ actions_model "code.gitea.io/gitea/models/actions"
+ "code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/util"
+ repo_service "code.gitea.io/gitea/services/repository"
+ user_service "code.gitea.io/gitea/services/user"
+ "code.gitea.io/gitea/tests"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestEphemeralActionsRunnerDeletion(t *testing.T) {
+ t.Run("ByTaskCompletion", testEphemeralActionsRunnerDeletionByTaskCompletion)
+ t.Run("ByRepository", testEphemeralActionsRunnerDeletionByRepository)
+ t.Run("ByUser", testEphemeralActionsRunnerDeletionByUser)
+}
+
+// Test that the ephemeral runner is deleted when the task is finished
+func testEphemeralActionsRunnerDeletionByTaskCompletion(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+
+ _, err := actions_model.GetRunnerByID(t.Context(), 34350)
+ assert.NoError(t, err)
+
+ task := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 52})
+ assert.Equal(t, actions_model.StatusRunning, task.Status)
+
+ task.Status = actions_model.StatusSuccess
+ err = actions_model.UpdateTask(t.Context(), task, "status")
+ assert.NoError(t, err)
+
+ _, err = actions_model.GetRunnerByID(t.Context(), 34350)
+ assert.ErrorIs(t, err, util.ErrNotExist)
+}
+
+func testEphemeralActionsRunnerDeletionByRepository(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+
+ _, err := actions_model.GetRunnerByID(t.Context(), 34350)
+ assert.NoError(t, err)
+
+ task := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 52})
+ assert.Equal(t, actions_model.StatusRunning, task.Status)
+
+ err = repo_service.DeleteRepositoryDirectly(t.Context(), task.RepoID, true)
+ assert.NoError(t, err)
+
+ _, err = actions_model.GetRunnerByID(t.Context(), 34350)
+ assert.ErrorIs(t, err, util.ErrNotExist)
+}
+
+// Test that the ephemeral runner is deleted when a user is deleted
+func testEphemeralActionsRunnerDeletionByUser(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+
+ _, err := actions_model.GetRunnerByID(t.Context(), 34350)
+ assert.NoError(t, err)
+
+ task := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 52})
+ assert.Equal(t, actions_model.StatusRunning, task.Status)
+
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+
+ err = user_service.DeleteUser(t.Context(), user, true)
+ assert.NoError(t, err)
+
+ _, err = actions_model.GetRunnerByID(t.Context(), 34350)
+ assert.ErrorIs(t, err, util.ErrNotExist)
+}
diff --git a/tests/integration/feed_repo_test.go b/tests/integration/feed_repo_test.go
new file mode 100644
index 0000000000..2915b9b3f4
--- /dev/null
+++ b/tests/integration/feed_repo_test.go
@@ -0,0 +1,35 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package integration
+
+import (
+ "encoding/xml"
+ "net/http"
+ "testing"
+
+ "code.gitea.io/gitea/tests"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestFeedRepo(t *testing.T) {
+ t.Run("RSS", func(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+
+ req := NewRequest(t, "GET", "/user2/repo1.rss")
+ resp := MakeRequest(t, req, http.StatusOK)
+
+ data := resp.Body.String()
+ assert.Contains(t, data, `<rss version="2.0"`)
+
+ var rss RSS
+ err := xml.Unmarshal(resp.Body.Bytes(), &rss)
+ assert.NoError(t, err)
+ assert.Contains(t, rss.Channel.Link, "/user2/repo1")
+ assert.NotEmpty(t, rss.Channel.PubDate)
+ assert.Len(t, rss.Channel.Items, 1)
+ assert.Equal(t, "issue5", rss.Channel.Items[0].Description)
+ assert.NotEmpty(t, rss.Channel.Items[0].PubDate)
+ })
+}
diff --git a/tests/integration/api_feed_user_test.go b/tests/integration/feed_user_test.go
index c44f9a1951..4315c67f48 100644
--- a/tests/integration/api_feed_user_test.go
+++ b/tests/integration/feed_user_test.go
@@ -4,6 +4,7 @@
package integration
import (
+ "encoding/xml"
"net/http"
"testing"
@@ -12,7 +13,23 @@ import (
"github.com/stretchr/testify/assert"
)
-func TestFeed(t *testing.T) {
+// RSS is a struct to unmarshal RSS feeds test only
+type RSS struct {
+ Channel struct {
+ Title string `xml:"title"`
+ Link string `xml:"link"`
+ Description string `xml:"description"`
+ PubDate string `xml:"pubDate"`
+ Items []struct {
+ Title string `xml:"title"`
+ Link string `xml:"link"`
+ Description string `xml:"description"`
+ PubDate string `xml:"pubDate"`
+ } `xml:"item"`
+ } `xml:"channel"`
+}
+
+func TestFeedUser(t *testing.T) {
t.Run("User", func(t *testing.T) {
t.Run("Atom", func(t *testing.T) {
defer tests.PrepareTestEnv(t)()
@@ -32,6 +49,12 @@ func TestFeed(t *testing.T) {
data := resp.Body.String()
assert.Contains(t, data, `<rss version="2.0"`)
+
+ var rss RSS
+ err := xml.Unmarshal(resp.Body.Bytes(), &rss)
+ assert.NoError(t, err)
+ assert.Contains(t, rss.Channel.Link, "/user2")
+ assert.NotEmpty(t, rss.Channel.PubDate)
})
})
}
diff --git a/tests/integration/git_general_test.go b/tests/integration/git_general_test.go
index a47cb75196..e72b7b4ff1 100644
--- a/tests/integration/git_general_test.go
+++ b/tests/integration/git_general_test.go
@@ -11,9 +11,12 @@ import (
"net/http"
"net/url"
"os"
+ "os/exec"
"path"
"path/filepath"
+ "slices"
"strconv"
+ "strings"
"testing"
"time"
@@ -24,14 +27,16 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/commitstatus"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
- gitea_context "code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/tests"
+ "github.com/kballard/go-shellquote"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
const (
@@ -80,6 +85,7 @@ func testGitGeneral(t *testing.T, u *url.URL) {
mediaTest(t, &httpContext, pushedFilesStandard[0], pushedFilesStandard[1], pushedFilesLFS[0], pushedFilesLFS[1])
t.Run("CreateAgitFlowPull", doCreateAgitFlowPull(dstPath, &httpContext, "test/head"))
+ t.Run("CreateProtectedBranch", doCreateProtectedBranch(&httpContext, dstPath))
t.Run("BranchProtectMerge", doBranchProtectPRMerge(&httpContext, dstPath))
t.Run("AutoMerge", doAutoPRMerge(&httpContext, dstPath))
t.Run("CreatePRAndSetManuallyMerged", doCreatePRAndSetManuallyMerged(httpContext, httpContext, dstPath, "master", "test-manually-merge"))
@@ -104,7 +110,12 @@ func testGitGeneral(t *testing.T, u *url.URL) {
// Setup key the user ssh key
withKeyFile(t, keyname, func(keyFile string) {
- t.Run("CreateUserKey", doAPICreateUserKey(sshContext, "test-key", keyFile))
+ var keyID int64
+ t.Run("CreateUserKey", doAPICreateUserKey(sshContext, "test-key", keyFile, func(t *testing.T, key api.PublicKey) {
+ keyID = key.ID
+ }))
+ assert.NotZero(t, keyID)
+ t.Run("LFSAccessTest", doSSHLFSAccessTest(sshContext, keyID))
// Setup remote link
// TODO: get url from api
@@ -121,6 +132,7 @@ func testGitGeneral(t *testing.T, u *url.URL) {
mediaTest(t, &sshContext, pushedFilesStandard[0], pushedFilesStandard[1], pushedFilesLFS[0], pushedFilesLFS[1])
t.Run("CreateAgitFlowPull", doCreateAgitFlowPull(dstPath, &sshContext, "test/head2"))
+ t.Run("CreateProtectedBranch", doCreateProtectedBranch(&sshContext, dstPath))
t.Run("BranchProtectMerge", doBranchProtectPRMerge(&sshContext, dstPath))
t.Run("MergeFork", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
@@ -134,6 +146,36 @@ func testGitGeneral(t *testing.T, u *url.URL) {
})
}
+func doSSHLFSAccessTest(_ APITestContext, keyID int64) func(*testing.T) {
+ return func(t *testing.T) {
+ sshCommand := os.Getenv("GIT_SSH_COMMAND") // it is set in withKeyFile
+ sshCmdParts, err := shellquote.Split(sshCommand) // and parse the ssh command to construct some mocked arguments
+ require.NoError(t, err)
+
+ t.Run("User2AccessOwned", func(t *testing.T) {
+ sshCmdUser2Self := append(slices.Clone(sshCmdParts),
+ "-p", strconv.Itoa(setting.SSH.ListenPort), "git@"+setting.SSH.ListenHost,
+ "git-lfs-authenticate", "user2/repo1.git", "upload", // accessible to own repo
+ )
+ cmd := exec.CommandContext(t.Context(), sshCmdUser2Self[0], sshCmdUser2Self[1:]...)
+ _, err := cmd.Output()
+ assert.NoError(t, err) // accessible, no error
+ })
+
+ t.Run("User2AccessOther", func(t *testing.T) {
+ sshCmdUser2Other := append(slices.Clone(sshCmdParts),
+ "-p", strconv.Itoa(setting.SSH.ListenPort), "git@"+setting.SSH.ListenHost,
+ "git-lfs-authenticate", "user5/repo4.git", "upload", // inaccessible to other's (user5/repo4)
+ )
+ cmd := exec.CommandContext(t.Context(), sshCmdUser2Other[0], sshCmdUser2Other[1:]...)
+ _, err := cmd.Output()
+ var errExit *exec.ExitError
+ require.ErrorAs(t, err, &errExit) // inaccessible, error
+ assert.Contains(t, string(errExit.Stderr), fmt.Sprintf("User: 2:user2 with Key: %d:test-key is not authorized to write to user5/repo4.", keyID))
+ })
+ }
+}
+
func ensureAnonymousClone(t *testing.T, u *url.URL) {
dstLocalPath := t.TempDir()
t.Run("CloneAnonymous", doGitClone(dstLocalPath, u))
@@ -151,9 +193,9 @@ func lfsCommitAndPushTest(t *testing.T, dstPath string, sizes ...int) (pushedFil
t.Run("CommitAndPushLFS", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
prefix := "lfs-data-file-"
- err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("install").Run(&git.RunOpts{Dir: dstPath})
+ err := git.NewCommand("lfs").AddArguments("install").Run(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
- _, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("track").AddDynamicArguments(prefix + "*").RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, err = git.NewCommand("lfs").AddArguments("track").AddDynamicArguments(prefix+"*").RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
err = git.AddChanges(dstPath, false, ".gitattributes")
assert.NoError(t, err)
@@ -269,20 +311,20 @@ func lockTest(t *testing.T, repoPath string) {
}
func lockFileTest(t *testing.T, filename, repoPath string) {
- _, _, err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("locks").RunStdString(&git.RunOpts{Dir: repoPath})
+ _, _, err := git.NewCommand("lfs").AddArguments("locks").RunStdString(git.DefaultContext, &git.RunOpts{Dir: repoPath})
assert.NoError(t, err)
- _, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("lock").AddDynamicArguments(filename).RunStdString(&git.RunOpts{Dir: repoPath})
+ _, _, err = git.NewCommand("lfs").AddArguments("lock").AddDynamicArguments(filename).RunStdString(git.DefaultContext, &git.RunOpts{Dir: repoPath})
assert.NoError(t, err)
- _, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("locks").RunStdString(&git.RunOpts{Dir: repoPath})
+ _, _, err = git.NewCommand("lfs").AddArguments("locks").RunStdString(git.DefaultContext, &git.RunOpts{Dir: repoPath})
assert.NoError(t, err)
- _, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("unlock").AddDynamicArguments(filename).RunStdString(&git.RunOpts{Dir: repoPath})
+ _, _, err = git.NewCommand("lfs").AddArguments("unlock").AddDynamicArguments(filename).RunStdString(git.DefaultContext, &git.RunOpts{Dir: repoPath})
assert.NoError(t, err)
}
func doCommitAndPush(t *testing.T, size int, repoPath, prefix string) string {
name, err := generateCommitWithNewData(size, repoPath, "user2@example.com", "User Two", prefix)
assert.NoError(t, err)
- _, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "master").RunStdString(&git.RunOpts{Dir: repoPath}) // Push
+ _, _, err = git.NewCommand("push", "origin", "master").RunStdString(git.DefaultContext, &git.RunOpts{Dir: repoPath}) // Push
assert.NoError(t, err)
return name
}
@@ -325,6 +367,34 @@ func generateCommitWithNewData(size int, repoPath, email, fullName, prefix strin
return filepath.Base(tmpFile.Name()), err
}
+func doCreateProtectedBranch(baseCtx *APITestContext, dstPath string) func(t *testing.T) {
+ return func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+ ctx := NewAPITestContext(t, baseCtx.Username, baseCtx.Reponame, auth_model.AccessTokenScopeWriteRepository)
+
+ t.Run("ProtectBranchWithFilePatterns", doProtectBranch(ctx, "release-*", baseCtx.Username, "", "", "config*"))
+
+ // push a new branch without any new commits
+ t.Run("CreateProtectedBranch-NoChanges", doGitCreateBranch(dstPath, "release-v1.0"))
+ t.Run("PushProtectedBranch-NoChanges", doGitPushTestRepository(dstPath, "origin", "release-v1.0"))
+ t.Run("CheckoutMaster-NoChanges", doGitCheckoutBranch(dstPath, "master"))
+
+ // push a new branch with a new unprotected file
+ t.Run("CreateProtectedBranch-UnprotectedFile", doGitCreateBranch(dstPath, "release-v2.0"))
+ _, err := generateCommitWithNewData(testFileSizeSmall, dstPath, "user2@example.com", "User Two", "abc.txt")
+ assert.NoError(t, err)
+ t.Run("PushProtectedBranch-UnprotectedFile", doGitPushTestRepository(dstPath, "origin", "release-v2.0"))
+ t.Run("CheckoutMaster-UnprotectedFile", doGitCheckoutBranch(dstPath, "master"))
+
+ // push a new branch with a new protected file
+ t.Run("CreateProtectedBranch-ProtectedFile", doGitCreateBranch(dstPath, "release-v3.0"))
+ _, err = generateCommitWithNewData(testFileSizeSmall, dstPath, "user2@example.com", "User Two", "config")
+ assert.NoError(t, err)
+ t.Run("PushProtectedBranch-ProtectedFile", doGitPushTestRepositoryFail(dstPath, "origin", "release-v3.0"))
+ t.Run("CheckoutMaster-ProtectedFile", doGitCheckoutBranch(dstPath, "master"))
+ }
+}
+
func doBranchProtectPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) {
return func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
@@ -334,60 +404,48 @@ func doBranchProtectPRMerge(baseCtx *APITestContext, dstPath string) func(t *tes
ctx := NewAPITestContext(t, baseCtx.Username, baseCtx.Reponame, auth_model.AccessTokenScopeWriteRepository)
// Protect branch without any whitelisting
- t.Run("ProtectBranchNoWhitelist", func(t *testing.T) {
- doProtectBranch(ctx, "protected", "", "", "")
- })
+ t.Run("ProtectBranchNoWhitelist", doProtectBranch(ctx, "protected", "", "", "", ""))
// Try to push without permissions, which should fail
t.Run("TryPushWithoutPermissions", func(t *testing.T) {
_, err := generateCommitWithNewData(testFileSizeSmall, dstPath, "user2@example.com", "User Two", "branch-data-file-")
assert.NoError(t, err)
- doGitPushTestRepositoryFail(dstPath, "origin", "protected")
+ doGitPushTestRepositoryFail(dstPath, "origin", "protected")(t)
})
// Set up permissions for normal push but not force push
- t.Run("SetupNormalPushPermissions", func(t *testing.T) {
- doProtectBranch(ctx, "protected", baseCtx.Username, "", "")
- })
+ t.Run("SetupNormalPushPermissions", doProtectBranch(ctx, "protected", baseCtx.Username, "", "", ""))
// Normal push should work
t.Run("NormalPushWithPermissions", func(t *testing.T) {
_, err := generateCommitWithNewData(testFileSizeSmall, dstPath, "user2@example.com", "User Two", "branch-data-file-")
assert.NoError(t, err)
- doGitPushTestRepository(dstPath, "origin", "protected")
+ doGitPushTestRepository(dstPath, "origin", "protected")(t)
})
// Try to force push without force push permissions, which should fail
t.Run("ForcePushWithoutForcePermissions", func(t *testing.T) {
t.Run("CreateDivergentHistory", func(t *testing.T) {
- git.NewCommand(git.DefaultContext, "reset", "--hard", "HEAD~1").Run(&git.RunOpts{Dir: dstPath})
+ git.NewCommand("reset", "--hard", "HEAD~1").Run(git.DefaultContext, &git.RunOpts{Dir: dstPath})
_, err := generateCommitWithNewData(testFileSizeSmall, dstPath, "user2@example.com", "User Two", "branch-data-file-new")
assert.NoError(t, err)
})
- doGitPushTestRepositoryFail(dstPath, "-f", "origin", "protected")
+ doGitPushTestRepositoryFail(dstPath, "-f", "origin", "protected")(t)
})
// Set up permissions for force push but not normal push
- t.Run("SetupForcePushPermissions", func(t *testing.T) {
- doProtectBranch(ctx, "protected", "", baseCtx.Username, "")
- })
+ t.Run("SetupForcePushPermissions", doProtectBranch(ctx, "protected", "", baseCtx.Username, "", ""))
// Try to force push without normal push permissions, which should fail
- t.Run("ForcePushWithoutNormalPermissions", func(t *testing.T) {
- doGitPushTestRepositoryFail(dstPath, "-f", "origin", "protected")
- })
+ t.Run("ForcePushWithoutNormalPermissions", doGitPushTestRepositoryFail(dstPath, "-f", "origin", "protected"))
// Set up permissions for normal and force push (both are required to force push)
- t.Run("SetupNormalAndForcePushPermissions", func(t *testing.T) {
- doProtectBranch(ctx, "protected", baseCtx.Username, baseCtx.Username, "")
- })
+ t.Run("SetupNormalAndForcePushPermissions", doProtectBranch(ctx, "protected", baseCtx.Username, baseCtx.Username, "", ""))
// Force push should now work
- t.Run("ForcePushWithPermissions", func(t *testing.T) {
- doGitPushTestRepository(dstPath, "-f", "origin", "protected")
- })
+ t.Run("ForcePushWithPermissions", doGitPushTestRepository(dstPath, "-f", "origin", "protected"))
- t.Run("ProtectProtectedBranchNoWhitelist", doProtectBranch(ctx, "protected", "", "", ""))
+ t.Run("ProtectProtectedBranchNoWhitelist", doProtectBranch(ctx, "protected", "", "", "", ""))
t.Run("PushToUnprotectedBranch", doGitPushTestRepository(dstPath, "origin", "protected:unprotected"))
var pr api.PullRequest
var err error
@@ -409,14 +467,14 @@ func doBranchProtectPRMerge(baseCtx *APITestContext, dstPath string) func(t *tes
t.Run("MergePR", doAPIMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index))
t.Run("PullProtected", doGitPull(dstPath, "origin", "protected"))
- t.Run("ProtectProtectedBranchUnprotectedFilePaths", doProtectBranch(ctx, "protected", "", "", "unprotected-file-*"))
+ t.Run("ProtectProtectedBranchUnprotectedFilePaths", doProtectBranch(ctx, "protected", "", "", "unprotected-file-*", ""))
t.Run("GenerateCommit", func(t *testing.T) {
_, err := generateCommitWithNewData(testFileSizeSmall, dstPath, "user2@example.com", "User Two", "unprotected-file-")
assert.NoError(t, err)
})
t.Run("PushUnprotectedFilesToProtectedBranch", doGitPushTestRepository(dstPath, "origin", "protected"))
- t.Run("ProtectProtectedBranchWhitelist", doProtectBranch(ctx, "protected", baseCtx.Username, "", ""))
+ t.Run("ProtectProtectedBranchWhitelist", doProtectBranch(ctx, "protected", baseCtx.Username, "", "", ""))
t.Run("CheckoutMaster", doGitCheckoutBranch(dstPath, "master"))
t.Run("CreateBranchForced", doGitCreateBranch(dstPath, "toforce"))
@@ -431,41 +489,61 @@ func doBranchProtectPRMerge(baseCtx *APITestContext, dstPath string) func(t *tes
}
}
-func doProtectBranch(ctx APITestContext, branch, userToWhitelistPush, userToWhitelistForcePush, unprotectedFilePatterns string) func(t *testing.T) {
+func doProtectBranch(ctx APITestContext, branch, userToWhitelistPush, userToWhitelistForcePush, unprotectedFilePatterns, protectedFilePatterns string) func(t *testing.T) {
+ return doProtectBranchExt(ctx, branch, doProtectBranchOptions{
+ UserToWhitelistPush: userToWhitelistPush,
+ UserToWhitelistForcePush: userToWhitelistForcePush,
+ UnprotectedFilePatterns: unprotectedFilePatterns,
+ ProtectedFilePatterns: protectedFilePatterns,
+ })
+}
+
+type doProtectBranchOptions struct {
+ UserToWhitelistPush, UserToWhitelistForcePush, UnprotectedFilePatterns, ProtectedFilePatterns string
+
+ StatusCheckPatterns []string
+}
+
+func doProtectBranchExt(ctx APITestContext, ruleName string, opts doProtectBranchOptions) func(t *testing.T) {
// We are going to just use the owner to set the protection.
return func(t *testing.T) {
csrf := GetUserCSRFToken(t, ctx.Session)
formData := map[string]string{
"_csrf": csrf,
- "rule_name": branch,
- "unprotected_file_patterns": unprotectedFilePatterns,
+ "rule_name": ruleName,
+ "unprotected_file_patterns": opts.UnprotectedFilePatterns,
+ "protected_file_patterns": opts.ProtectedFilePatterns,
}
- if userToWhitelistPush != "" {
- user, err := user_model.GetUserByName(db.DefaultContext, userToWhitelistPush)
+ if opts.UserToWhitelistPush != "" {
+ user, err := user_model.GetUserByName(db.DefaultContext, opts.UserToWhitelistPush)
assert.NoError(t, err)
formData["whitelist_users"] = strconv.FormatInt(user.ID, 10)
formData["enable_push"] = "whitelist"
formData["enable_whitelist"] = "on"
}
- if userToWhitelistForcePush != "" {
- user, err := user_model.GetUserByName(db.DefaultContext, userToWhitelistForcePush)
+ if opts.UserToWhitelistForcePush != "" {
+ user, err := user_model.GetUserByName(db.DefaultContext, opts.UserToWhitelistForcePush)
assert.NoError(t, err)
formData["force_push_allowlist_users"] = strconv.FormatInt(user.ID, 10)
formData["enable_force_push"] = "whitelist"
formData["enable_force_push_allowlist"] = "on"
}
+ if len(opts.StatusCheckPatterns) > 0 {
+ formData["enable_status_check"] = "on"
+ formData["status_check_contexts"] = strings.Join(opts.StatusCheckPatterns, "\n")
+ }
+
// Send the request to update branch protection settings
req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/settings/branches/edit", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame)), formData)
ctx.Session.MakeRequest(t, req, http.StatusSeeOther)
- // Check if master branch has been locked successfully
- flashCookie := ctx.Session.GetCookie(gitea_context.CookieNameFlash)
- assert.NotNil(t, flashCookie)
- assert.EqualValues(t, "success%3DBranch%2Bprotection%2Bfor%2Brule%2B%2522"+url.QueryEscape(branch)+"%2522%2Bhas%2Bbeen%2Bupdated.", flashCookie.Value)
+ // Check if the "master" branch has been locked successfully
+ flashMsg := ctx.Session.GetCookieFlashMessage()
+ assert.Equal(t, `Branch protection for rule "`+ruleName+`" has been updated.`, flashMsg.SuccessMsg)
}
}
@@ -574,7 +652,7 @@ func doPushCreate(ctx APITestContext, u *url.URL) func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
// create a context for a currently non-existent repository
- ctx.Reponame = fmt.Sprintf("repo-tmp-push-create-%s", u.Scheme)
+ ctx.Reponame = "repo-tmp-push-create-" + u.Scheme
u.Path = ctx.GitPath()
// Create a temporary directory
@@ -605,7 +683,7 @@ func doPushCreate(ctx APITestContext, u *url.URL) func(t *testing.T) {
// Now add a remote that is invalid to "Push To Create"
invalidCtx := ctx
- invalidCtx.Reponame = fmt.Sprintf("invalid/repo-tmp-push-create-%s", u.Scheme)
+ invalidCtx.Reponame = "invalid/repo-tmp-push-create-" + u.Scheme
u.Path = invalidCtx.GitPath()
t.Run("AddInvalidRemote", doGitAddRemote(tmpDir, "invalid", u))
@@ -631,6 +709,10 @@ func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) {
ctx := NewAPITestContext(t, baseCtx.Username, baseCtx.Reponame, auth_model.AccessTokenScopeWriteRepository)
+ // automerge will merge immediately if the PR is mergeable and there is no "status check" because no status check also means "all checks passed"
+ // so we must set up a status check to test the auto merge feature
+ doProtectBranchExt(ctx, "protected", doProtectBranchOptions{StatusCheckPatterns: []string{"*"}})(t)
+
t.Run("CheckoutProtected", doGitCheckoutBranch(dstPath, "protected"))
t.Run("PullProtected", doGitPull(dstPath, "origin", "protected"))
t.Run("GenerateCommit", func(t *testing.T) {
@@ -657,7 +739,7 @@ func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) {
commitID := path.Base(commitURL)
- addCommitStatus := func(status api.CommitStatusState) func(*testing.T) {
+ addCommitStatus := func(status commitstatus.CommitStatusState) func(*testing.T) {
return doAPICreateCommitStatus(ctx, commitID, api.CreateStatusOption{
State: status,
TargetURL: "http://test.ci/",
@@ -667,17 +749,17 @@ func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) {
}
// Call API to add Pending status for commit
- t.Run("CreateStatus", addCommitStatus(api.CommitStatusPending))
+ t.Run("CreateStatus", addCommitStatus(commitstatus.CommitStatusPending))
// Cancel not existing auto merge
ctx.ExpectedCode = http.StatusNotFound
- t.Run("CancelAutoMergePR", doAPICancelAutoMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index))
+ t.Run("CancelAutoMergePRNotExist", doAPICancelAutoMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index))
// Add auto merge request
ctx.ExpectedCode = http.StatusCreated
t.Run("AutoMergePR", doAPIAutoMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index))
- // Can not create schedule twice
+ // Cannot create schedule twice
ctx.ExpectedCode = http.StatusConflict
t.Run("AutoMergePRTwice", doAPIAutoMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index))
@@ -696,7 +778,7 @@ func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) {
assert.False(t, pr.HasMerged)
// Call API to add Failure status for commit
- t.Run("CreateStatus", addCommitStatus(api.CommitStatusFailure))
+ t.Run("CreateStatus", addCommitStatus(commitstatus.CommitStatusFailure))
// Check pr status
pr, err = doAPIGetPullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t)
@@ -704,7 +786,7 @@ func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) {
assert.False(t, pr.HasMerged)
// Call API to add Success status for commit
- t.Run("CreateStatus", addCommitStatus(api.CommitStatusSuccess))
+ t.Run("CreateStatus", addCommitStatus(commitstatus.CommitStatusSuccess))
// wait to let gitea merge stuff
time.Sleep(time.Second)
@@ -726,9 +808,8 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, headBranch string
}
gitRepo, err := git.OpenRepository(git.DefaultContext, dstPath)
- if !assert.NoError(t, err) {
- return
- }
+ require.NoError(t, err)
+
defer gitRepo.Close()
var (
@@ -736,9 +817,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, headBranch string
commit string
)
repo, err := repo_model.GetRepositoryByOwnerAndName(db.DefaultContext, ctx.Username, ctx.Reponame)
- if !assert.NoError(t, err) {
- return
- }
+ require.NoError(t, err)
pullNum := unittest.GetCount(t, &issues_model.PullRequest{})
@@ -746,9 +825,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, headBranch string
t.Run("AddCommit", func(t *testing.T) {
err := os.WriteFile(path.Join(dstPath, "test_file"), []byte("## test content"), 0o666)
- if !assert.NoError(t, err) {
- return
- }
+ require.NoError(t, err)
err = git.AddChanges(dstPath, true)
assert.NoError(t, err)
@@ -772,44 +849,38 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, headBranch string
})
t.Run("Push", func(t *testing.T) {
- err := git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master", "-o").AddDynamicArguments("topic=" + headBranch).Run(&git.RunOpts{Dir: dstPath})
- if !assert.NoError(t, err) {
- return
- }
+ err := git.NewCommand("push", "origin", "HEAD:refs/for/master", "-o").AddDynamicArguments("topic="+headBranch).Run(git.DefaultContext, &git.RunOpts{Dir: dstPath})
+ require.NoError(t, err)
+
unittest.AssertCount(t, &issues_model.PullRequest{}, pullNum+1)
pr1 = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
HeadRepoID: repo.ID,
Flow: issues_model.PullRequestFlowAGit,
})
- if !assert.NotEmpty(t, pr1) {
- return
- }
+ require.NotEmpty(t, pr1)
+
prMsg, err := doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr1.Index)(t)
- if !assert.NoError(t, err) {
- return
- }
+ require.NoError(t, err)
+
assert.Equal(t, "user2/"+headBranch, pr1.HeadBranch)
assert.False(t, prMsg.HasMerged)
assert.Contains(t, "Testing commit 1", prMsg.Body)
assert.Equal(t, commit, prMsg.Head.Sha)
- _, _, err = git.NewCommand(git.DefaultContext, "push", "origin").AddDynamicArguments("HEAD:refs/for/master/test/" + headBranch).RunStdString(&git.RunOpts{Dir: dstPath})
- if !assert.NoError(t, err) {
- return
- }
+ _, _, err = git.NewCommand("push", "origin").AddDynamicArguments("HEAD:refs/for/master/test/"+headBranch).RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
+ require.NoError(t, err)
+
unittest.AssertCount(t, &issues_model.PullRequest{}, pullNum+2)
pr2 = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
HeadRepoID: repo.ID,
Index: pr1.Index + 1,
Flow: issues_model.PullRequestFlowAGit,
})
- if !assert.NotEmpty(t, pr2) {
- return
- }
+ require.NotEmpty(t, pr2)
+
prMsg, err = doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr2.Index)(t)
- if !assert.NoError(t, err) {
- return
- }
+ require.NoError(t, err)
+
assert.Equal(t, "user2/test/"+headBranch, pr2.HeadBranch)
assert.False(t, prMsg.HasMerged)
})
@@ -820,9 +891,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, headBranch string
t.Run("AddCommit2", func(t *testing.T) {
err := os.WriteFile(path.Join(dstPath, "test_file"), []byte("## test content \n ## test content 2"), 0o666)
- if !assert.NoError(t, err) {
- return
- }
+ require.NoError(t, err)
err = git.AddChanges(dstPath, true)
assert.NoError(t, err)
@@ -846,27 +915,23 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, headBranch string
})
t.Run("Push2", func(t *testing.T) {
- err := git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master", "-o").AddDynamicArguments("topic=" + headBranch).Run(&git.RunOpts{Dir: dstPath})
- if !assert.NoError(t, err) {
- return
- }
+ err := git.NewCommand("push", "origin", "HEAD:refs/for/master", "-o").AddDynamicArguments("topic="+headBranch).Run(git.DefaultContext, &git.RunOpts{Dir: dstPath})
+ require.NoError(t, err)
+
unittest.AssertCount(t, &issues_model.PullRequest{}, pullNum+2)
prMsg, err := doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr1.Index)(t)
- if !assert.NoError(t, err) {
- return
- }
+ require.NoError(t, err)
+
assert.False(t, prMsg.HasMerged)
assert.Equal(t, commit, prMsg.Head.Sha)
- _, _, err = git.NewCommand(git.DefaultContext, "push", "origin").AddDynamicArguments("HEAD:refs/for/master/test/" + headBranch).RunStdString(&git.RunOpts{Dir: dstPath})
- if !assert.NoError(t, err) {
- return
- }
+ _, _, err = git.NewCommand("push", "origin").AddDynamicArguments("HEAD:refs/for/master/test/"+headBranch).RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
+ require.NoError(t, err)
+
unittest.AssertCount(t, &issues_model.PullRequest{}, pullNum+2)
prMsg, err = doAPIGetPullRequest(*ctx, ctx.Username, ctx.Reponame, pr2.Index)(t)
- if !assert.NoError(t, err) {
- return
- }
+ require.NoError(t, err)
+
assert.False(t, prMsg.HasMerged)
assert.Equal(t, commit, prMsg.Head.Sha)
})
diff --git a/tests/integration/git_helper_for_declarative_test.go b/tests/integration/git_helper_for_declarative_test.go
index 43b151e0b6..7d42508bfe 100644
--- a/tests/integration/git_helper_for_declarative_test.go
+++ b/tests/integration/git_helper_for_declarative_test.go
@@ -10,7 +10,6 @@ import (
"net/http"
"net/url"
"os"
- "path"
"path/filepath"
"strconv"
"testing"
@@ -35,12 +34,12 @@ func withKeyFile(t *testing.T, keyname string, callback func(string)) {
err = ssh.GenKeyPair(keyFile)
assert.NoError(t, err)
- err = os.WriteFile(path.Join(tmpDir, "ssh"), []byte("#!/bin/bash\n"+
+ err = os.WriteFile(filepath.Join(tmpDir, "ssh"), []byte("#!/bin/bash\n"+
"ssh -o \"UserKnownHostsFile=/dev/null\" -o \"StrictHostKeyChecking=no\" -o \"IdentitiesOnly=yes\" -i \""+keyFile+"\" \"$@\""), 0o700)
assert.NoError(t, err)
// Setup ssh wrapper
- t.Setenv("GIT_SSH", path.Join(tmpDir, "ssh"))
+ t.Setenv("GIT_SSH", filepath.Join(tmpDir, "ssh"))
t.Setenv("GIT_SSH_COMMAND",
"ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentitiesOnly=yes -i \""+keyFile+"\"")
t.Setenv("GIT_SSH_VARIANT", "ssh")
@@ -76,7 +75,7 @@ func onGiteaRun[T testing.TB](t T, callback func(T, *url.URL)) {
u.Host = listener.Addr().String()
defer func() {
- ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
+ ctx, cancel := context.WithTimeout(t.Context(), 2*time.Minute)
s.Shutdown(ctx)
cancel()
}()
@@ -89,7 +88,7 @@ func onGiteaRun[T testing.TB](t T, callback func(T, *url.URL)) {
func doGitClone(dstLocalPath string, u *url.URL) func(*testing.T) {
return func(t *testing.T) {
- assert.NoError(t, git.CloneWithArgs(context.Background(), git.AllowLFSFiltersArgs(), u.String(), dstLocalPath, git.CloneRepoOptions{}))
+ assert.NoError(t, git.CloneWithArgs(t.Context(), git.AllowLFSFiltersArgs(), u.String(), dstLocalPath, git.CloneRepoOptions{}))
exist, err := util.IsExist(filepath.Join(dstLocalPath, "README.md"))
assert.NoError(t, err)
assert.True(t, exist)
@@ -98,7 +97,7 @@ func doGitClone(dstLocalPath string, u *url.URL) func(*testing.T) {
func doPartialGitClone(dstLocalPath string, u *url.URL) func(*testing.T) {
return func(t *testing.T) {
- assert.NoError(t, git.CloneWithArgs(context.Background(), git.AllowLFSFiltersArgs(), u.String(), dstLocalPath, git.CloneRepoOptions{
+ assert.NoError(t, git.CloneWithArgs(t.Context(), git.AllowLFSFiltersArgs(), u.String(), dstLocalPath, git.CloneRepoOptions{
Filter: "blob:none",
}))
exist, err := util.IsExist(filepath.Join(dstLocalPath, "README.md"))
@@ -122,9 +121,9 @@ func doGitInitTestRepository(dstPath string) func(*testing.T) {
// Init repository in dstPath
assert.NoError(t, git.InitRepository(git.DefaultContext, dstPath, false, git.Sha1ObjectFormat.Name()))
// forcibly set default branch to master
- _, _, err := git.NewCommand(git.DefaultContext, "symbolic-ref", "HEAD", git.BranchPrefix+"master").RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, err := git.NewCommand("symbolic-ref", "HEAD", git.BranchPrefix+"master").RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
- assert.NoError(t, os.WriteFile(filepath.Join(dstPath, "README.md"), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s", dstPath)), 0o644))
+ assert.NoError(t, os.WriteFile(filepath.Join(dstPath, "README.md"), []byte("# Testing Repository\n\nOriginally created in: "+dstPath), 0o644))
assert.NoError(t, git.AddChanges(dstPath, true))
signature := git.Signature{
Email: "test@example.com",
@@ -141,21 +140,21 @@ func doGitInitTestRepository(dstPath string) func(*testing.T) {
func doGitAddRemote(dstPath, remoteName string, u *url.URL) func(*testing.T) {
return func(t *testing.T) {
- _, _, err := git.NewCommand(git.DefaultContext, "remote", "add").AddDynamicArguments(remoteName, u.String()).RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, err := git.NewCommand("remote", "add").AddDynamicArguments(remoteName, u.String()).RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
}
}
func doGitPushTestRepository(dstPath string, args ...string) func(*testing.T) {
return func(t *testing.T) {
- _, _, err := git.NewCommand(git.DefaultContext, "push", "-u").AddArguments(git.ToTrustedCmdArgs(args)...).RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, err := git.NewCommand("push", "-u").AddArguments(git.ToTrustedCmdArgs(args)...).RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
}
}
func doGitPushTestRepositoryFail(dstPath string, args ...string) func(*testing.T) {
return func(t *testing.T) {
- _, _, err := git.NewCommand(git.DefaultContext, "push").AddArguments(git.ToTrustedCmdArgs(args)...).RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, err := git.NewCommand("push").AddArguments(git.ToTrustedCmdArgs(args)...).RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.Error(t, err)
}
}
@@ -164,7 +163,7 @@ func doGitAddSomeCommits(dstPath, branch string) func(*testing.T) {
return func(t *testing.T) {
doGitCheckoutBranch(dstPath, branch)(t)
- assert.NoError(t, os.WriteFile(filepath.Join(dstPath, fmt.Sprintf("file-%s.txt", branch)), []byte(fmt.Sprintf("file %s", branch)), 0o644))
+ assert.NoError(t, os.WriteFile(filepath.Join(dstPath, fmt.Sprintf("file-%s.txt", branch)), []byte("file "+branch), 0o644))
assert.NoError(t, git.AddChanges(dstPath, true))
signature := git.Signature{
Email: "test@test.test",
@@ -173,35 +172,35 @@ func doGitAddSomeCommits(dstPath, branch string) func(*testing.T) {
assert.NoError(t, git.CommitChanges(dstPath, git.CommitChangesOptions{
Committer: &signature,
Author: &signature,
- Message: fmt.Sprintf("update %s", branch),
+ Message: "update " + branch,
}))
}
}
func doGitCreateBranch(dstPath, branch string) func(*testing.T) {
return func(t *testing.T) {
- _, _, err := git.NewCommand(git.DefaultContext, "checkout", "-b").AddDynamicArguments(branch).RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, err := git.NewCommand("checkout", "-b").AddDynamicArguments(branch).RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
}
}
func doGitCheckoutBranch(dstPath string, args ...string) func(*testing.T) {
return func(t *testing.T) {
- _, _, err := git.NewCommandContextNoGlobals(git.DefaultContext, git.AllowLFSFiltersArgs()...).AddArguments("checkout").AddArguments(git.ToTrustedCmdArgs(args)...).RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, err := git.NewCommandNoGlobals(git.AllowLFSFiltersArgs()...).AddArguments("checkout").AddArguments(git.ToTrustedCmdArgs(args)...).RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
}
}
func doGitMerge(dstPath string, args ...string) func(*testing.T) {
return func(t *testing.T) {
- _, _, err := git.NewCommand(git.DefaultContext, "merge").AddArguments(git.ToTrustedCmdArgs(args)...).RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, err := git.NewCommand("merge").AddArguments(git.ToTrustedCmdArgs(args)...).RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
}
}
func doGitPull(dstPath string, args ...string) func(*testing.T) {
return func(t *testing.T) {
- _, _, err := git.NewCommandContextNoGlobals(git.DefaultContext, git.AllowLFSFiltersArgs()...).AddArguments("pull").AddArguments(git.ToTrustedCmdArgs(args)...).RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, err := git.NewCommandNoGlobals(git.AllowLFSFiltersArgs()...).AddArguments("pull").AddArguments(git.ToTrustedCmdArgs(args)...).RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
}
}
diff --git a/tests/integration/git_lfs_ssh_test.go b/tests/integration/git_lfs_ssh_test.go
index 9cb7fd089b..64a403f513 100644
--- a/tests/integration/git_lfs_ssh_test.go
+++ b/tests/integration/git_lfs_ssh_test.go
@@ -4,7 +4,6 @@
package integration
import (
- gocontext "context"
"net/url"
"slices"
"strings"
@@ -46,7 +45,7 @@ func TestGitLFSSSH(t *testing.T) {
setting.LFS.AllowPureSSH = true
require.NoError(t, cfg.Save())
- _, _, cmdErr := git.NewCommand(gocontext.Background(), "config", "lfs.sshtransfer", "always").RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, cmdErr := git.NewCommand("config", "lfs.sshtransfer", "always").RunStdString(t.Context(), &git.RunOpts{Dir: dstPath})
assert.NoError(t, cmdErr)
lfsCommitAndPushTest(t, dstPath, 10)
})
@@ -55,9 +54,14 @@ func TestGitLFSSSH(t *testing.T) {
return strings.Contains(s, "POST /api/internal/repo/user2/repo1.git/info/lfs/objects/batch")
})
countUpload := slices.ContainsFunc(routerCalls, func(s string) bool {
- return strings.Contains(s, "PUT /user2/repo1.git/info/lfs/objects/")
+ return strings.Contains(s, "PUT /api/internal/repo/user2/repo1.git/info/lfs/objects/")
+ })
+ nonAPIRequests := slices.ContainsFunc(routerCalls, func(s string) bool {
+ fields := strings.Fields(s)
+ return !strings.HasPrefix(fields[1], "/api/")
})
assert.NotZero(t, countBatch)
assert.NotZero(t, countUpload)
+ assert.Zero(t, nonAPIRequests)
})
}
diff --git a/tests/integration/git_misc_test.go b/tests/integration/git_misc_test.go
index 00ed2a766f..d5a4af07ba 100644
--- a/tests/integration/git_misc_test.go
+++ b/tests/integration/git_misc_test.go
@@ -5,7 +5,6 @@ package integration
import (
"bytes"
- "context"
"io"
"net/url"
"sync"
@@ -91,7 +90,7 @@ func TestAgitPullPush(t *testing.T) {
dstPath := t.TempDir()
doGitClone(dstPath, u)(t)
- gitRepo, err := git.OpenRepository(context.Background(), dstPath)
+ gitRepo, err := git.OpenRepository(t.Context(), dstPath)
assert.NoError(t, err)
defer gitRepo.Close()
@@ -102,10 +101,10 @@ func TestAgitPullPush(t *testing.T) {
assert.NoError(t, err)
// push to create an agit pull request
- err = git.NewCommand(git.DefaultContext, "push", "origin",
+ err = git.NewCommand("push", "origin",
"-o", "title=test-title", "-o", "description=test-description",
"HEAD:refs/for/master/test-agit-push",
- ).Run(&git.RunOpts{Dir: dstPath})
+ ).Run(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
// check pull request exist
@@ -119,20 +118,122 @@ func TestAgitPullPush(t *testing.T) {
assert.NoError(t, err)
// push 2
- err = git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master/test-agit-push").Run(&git.RunOpts{Dir: dstPath})
+ err = git.NewCommand("push", "origin", "HEAD:refs/for/master/test-agit-push").Run(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
// reset to first commit
- err = git.NewCommand(git.DefaultContext, "reset", "--hard", "HEAD~1").Run(&git.RunOpts{Dir: dstPath})
+ err = git.NewCommand("reset", "--hard", "HEAD~1").Run(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
// test force push without confirm
- _, stderr, err := git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master/test-agit-push").RunStdString(&git.RunOpts{Dir: dstPath})
+ _, stderr, err := git.NewCommand("push", "origin", "HEAD:refs/for/master/test-agit-push").RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.Error(t, err)
assert.Contains(t, stderr, "[remote rejected] HEAD -> refs/for/master/test-agit-push (request `force-push` push option)")
// test force push with confirm
- err = git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master/test-agit-push", "-o", "force-push").Run(&git.RunOpts{Dir: dstPath})
+ err = git.NewCommand("push", "origin", "HEAD:refs/for/master/test-agit-push", "-o", "force-push").Run(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
})
}
+
+func TestAgitReviewStaleness(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ baseAPITestContext := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
+
+ u.Path = baseAPITestContext.GitPath()
+ u.User = url.UserPassword("user2", userPassword)
+
+ dstPath := t.TempDir()
+ doGitClone(dstPath, u)(t)
+
+ gitRepo, err := git.OpenRepository(t.Context(), dstPath)
+ assert.NoError(t, err)
+ defer gitRepo.Close()
+
+ doGitCreateBranch(dstPath, "test-agit-review")
+
+ // Create initial commit
+ _, err = generateCommitWithNewData(testFileSizeSmall, dstPath, "user2@example.com", "User Two", "initial-")
+ assert.NoError(t, err)
+
+ // create PR via agit
+ err = git.NewCommand("push", "origin",
+ "-o", "title=Test agit Review Staleness", "-o", "description=Testing review staleness",
+ "HEAD:refs/for/master/test-agit-review",
+ ).Run(git.DefaultContext, &git.RunOpts{Dir: dstPath})
+ assert.NoError(t, err)
+
+ pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
+ BaseRepoID: 1,
+ Flow: issues_model.PullRequestFlowAGit,
+ HeadBranch: "user2/test-agit-review",
+ })
+ assert.NoError(t, pr.LoadIssue(db.DefaultContext))
+
+ // Get initial commit ID for the review
+ initialCommitID := pr.HeadCommitID
+ t.Logf("Initial commit ID: %s", initialCommitID)
+
+ // Create a review on the PR (as user1 reviewing user2's PR)
+ reviewer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
+ review, err := issues_model.CreateReview(db.DefaultContext, issues_model.CreateReviewOptions{
+ Type: issues_model.ReviewTypeApprove,
+ Reviewer: reviewer,
+ Issue: pr.Issue,
+ CommitID: initialCommitID,
+ Content: "LGTM! Looks good to merge.",
+ Official: false,
+ })
+ assert.NoError(t, err)
+ assert.False(t, review.Stale, "New review should not be stale")
+
+ // Verify review exists and is not stale
+ reviews, err := issues_model.FindReviews(db.DefaultContext, issues_model.FindReviewOptions{
+ IssueID: pr.IssueID,
+ })
+ assert.NoError(t, err)
+ assert.Len(t, reviews, 1)
+ assert.Equal(t, initialCommitID, reviews[0].CommitID)
+ assert.False(t, reviews[0].Stale, "Review should not be stale initially")
+
+ // Create a new commit and update the agit PR
+ _, err = generateCommitWithNewData(testFileSizeSmall, dstPath, "user2@example.com", "User Two", "updated-")
+ assert.NoError(t, err)
+
+ err = git.NewCommand("push", "origin", "HEAD:refs/for/master/test-agit-review").Run(git.DefaultContext, &git.RunOpts{Dir: dstPath})
+ assert.NoError(t, err)
+
+ // Reload PR to get updated commit ID
+ pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
+ BaseRepoID: 1,
+ Flow: issues_model.PullRequestFlowAGit,
+ HeadBranch: "user2/test-agit-review",
+ })
+ assert.NoError(t, pr.LoadIssue(db.DefaultContext))
+
+ // For AGit PRs, HeadCommitID must be loaded from git references
+ baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+ baseGitRepo, err := gitrepo.OpenRepository(db.DefaultContext, baseRepo)
+ assert.NoError(t, err)
+ defer baseGitRepo.Close()
+
+ updatedCommitID, err := baseGitRepo.GetRefCommitID(pr.GetGitHeadRefName())
+ assert.NoError(t, err)
+ t.Logf("Updated commit ID: %s", updatedCommitID)
+
+ // Verify the PR was updated with new commit
+ assert.NotEqual(t, initialCommitID, updatedCommitID, "PR should have new commit ID after update")
+
+ // Check that the review is now marked as stale
+ reviews, err = issues_model.FindReviews(db.DefaultContext, issues_model.FindReviewOptions{
+ IssueID: pr.IssueID,
+ })
+ assert.NoError(t, err)
+ assert.Len(t, reviews, 1)
+
+ assert.True(t, reviews[0].Stale, "Review should be marked as stale after AGit PR update")
+
+ // The review commit ID should remain the same (pointing to the original commit)
+ assert.Equal(t, initialCommitID, reviews[0].CommitID, "Review commit ID should remain unchanged and point to original commit")
+ })
+}
diff --git a/tests/integration/git_push_test.go b/tests/integration/git_push_test.go
index e68f8bfce2..d716847b54 100644
--- a/tests/integration/git_push_test.go
+++ b/tests/integration/git_push_test.go
@@ -27,7 +27,7 @@ func TestGitPush(t *testing.T) {
func testGitPush(t *testing.T, u *url.URL) {
t.Run("Push branches at once", func(t *testing.T) {
runTestGitPush(t, u, func(t *testing.T, gitPath string) (pushed, deleted []string) {
- for i := 0; i < 100; i++ {
+ for i := range 100 {
branchName := fmt.Sprintf("branch-%d", i)
pushed = append(pushed, branchName)
doGitCreateBranch(gitPath, branchName)(t)
@@ -40,7 +40,7 @@ func testGitPush(t *testing.T, u *url.URL) {
t.Run("Push branches exists", func(t *testing.T) {
runTestGitPush(t, u, func(t *testing.T, gitPath string) (pushed, deleted []string) {
- for i := 0; i < 10; i++ {
+ for i := range 10 {
branchName := fmt.Sprintf("branch-%d", i)
if i < 5 {
pushed = append(pushed, branchName)
@@ -54,7 +54,7 @@ func testGitPush(t *testing.T, u *url.URL) {
pushed = pushed[:0]
// do some changes for the first 5 branches created above
- for i := 0; i < 5; i++ {
+ for i := range 5 {
branchName := fmt.Sprintf("branch-%d", i)
pushed = append(pushed, branchName)
@@ -75,7 +75,7 @@ func testGitPush(t *testing.T, u *url.URL) {
t.Run("Push branches one by one", func(t *testing.T) {
runTestGitPush(t, u, func(t *testing.T, gitPath string) (pushed, deleted []string) {
- for i := 0; i < 100; i++ {
+ for i := range 100 {
branchName := fmt.Sprintf("branch-%d", i)
doGitCreateBranch(gitPath, branchName)(t)
doGitPushTestRepository(gitPath, "origin", branchName)(t)
@@ -101,14 +101,14 @@ func testGitPush(t *testing.T, u *url.URL) {
doGitPushTestRepository(gitPath, "origin", "master")(t) // make sure master is the default branch instead of a branch we are going to delete
pushed = append(pushed, "master")
- for i := 0; i < 100; i++ {
+ for i := range 100 {
branchName := fmt.Sprintf("branch-%d", i)
pushed = append(pushed, branchName)
doGitCreateBranch(gitPath, branchName)(t)
}
doGitPushTestRepository(gitPath, "origin", "--all")(t)
- for i := 0; i < 10; i++ {
+ for i := range 10 {
branchName := fmt.Sprintf("branch-%d", i)
doGitPushTestRepository(gitPath, "origin", "--delete", branchName)(t)
deleted = append(deleted, branchName)
@@ -170,7 +170,7 @@ func runTestGitPush(t *testing.T, u *url.URL, gitOperation func(t *testing.T, gi
dbBranches := make([]*git_model.Branch, 0)
require.NoError(t, db.GetEngine(db.DefaultContext).Where("repo_id=?", repo.ID).Find(&dbBranches))
- assert.Equalf(t, len(pushedBranches), len(dbBranches), "mismatched number of branches in db")
+ assert.Lenf(t, dbBranches, len(pushedBranches), "mismatched number of branches in db")
dbBranchesMap := make(map[string]*git_model.Branch, len(dbBranches))
for _, branch := range dbBranches {
dbBranchesMap[branch.Name] = branch
@@ -191,7 +191,7 @@ func runTestGitPush(t *testing.T, u *url.URL, gitOperation func(t *testing.T, gi
assert.Equal(t, commitID, branch.CommitID)
}
- require.NoError(t, repo_service.DeleteRepositoryDirectly(db.DefaultContext, user, repo.ID))
+ require.NoError(t, repo_service.DeleteRepositoryDirectly(db.DefaultContext, repo.ID))
}
func TestPushPullRefs(t *testing.T) {
@@ -204,8 +204,8 @@ func TestPushPullRefs(t *testing.T) {
dstPath := t.TempDir()
doGitClone(dstPath, u)(t)
- cmd := git.NewCommand(git.DefaultContext, "push", "--delete", "origin", "refs/pull/2/head")
- stdout, stderr, err := cmd.RunStdString(&git.RunOpts{
+ cmd := git.NewCommand("push", "--delete", "origin", "refs/pull/2/head")
+ stdout, stderr, err := cmd.RunStdString(git.DefaultContext, &git.RunOpts{
Dir: dstPath,
})
assert.Error(t, err)
diff --git a/tests/integration/git_smart_http_test.go b/tests/integration/git_smart_http_test.go
index 15336b9b81..e984fd3aad 100644
--- a/tests/integration/git_smart_http_test.go
+++ b/tests/integration/git_smart_http_test.go
@@ -9,60 +9,90 @@ import (
"net/url"
"testing"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/test"
+ "code.gitea.io/gitea/modules/util"
+
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func TestGitSmartHTTP(t *testing.T) {
- onGiteaRun(t, testGitSmartHTTP)
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ testGitSmartHTTP(t, u)
+ testRenamedRepoRedirect(t)
+ })
}
func testGitSmartHTTP(t *testing.T, u *url.URL) {
kases := []struct {
- p string
- code int
+ method, path string
+ code int
}{
{
- p: "user2/repo1/info/refs",
+ path: "user2/repo1/info/refs",
code: http.StatusOK,
},
{
- p: "user2/repo1/HEAD",
+ method: "HEAD",
+ path: "user2/repo1/info/refs",
+ code: http.StatusOK,
+ },
+ {
+ path: "user2/repo1/HEAD",
code: http.StatusOK,
},
{
- p: "user2/repo1/objects/info/alternates",
+ path: "user2/repo1/objects/info/alternates",
code: http.StatusNotFound,
},
{
- p: "user2/repo1/objects/info/http-alternates",
+ path: "user2/repo1/objects/info/http-alternates",
code: http.StatusNotFound,
},
{
- p: "user2/repo1/../../custom/conf/app.ini",
+ path: "user2/repo1/../../custom/conf/app.ini",
code: http.StatusNotFound,
},
{
- p: "user2/repo1/objects/info/../../../../custom/conf/app.ini",
+ path: "user2/repo1/objects/info/../../../../custom/conf/app.ini",
code: http.StatusNotFound,
},
{
- p: `user2/repo1/objects/info/..\..\..\..\custom\conf\app.ini`,
+ path: `user2/repo1/objects/info/..\..\..\..\custom\conf\app.ini`,
code: http.StatusBadRequest,
},
}
for _, kase := range kases {
- t.Run(kase.p, func(t *testing.T) {
- p := u.String() + kase.p
- req, err := http.NewRequest("GET", p, nil)
- assert.NoError(t, err)
+ t.Run(kase.path, func(t *testing.T) {
+ req, err := http.NewRequest(util.IfZero(kase.method, "GET"), u.String()+kase.path, nil)
+ require.NoError(t, err)
req.SetBasicAuth("user2", userPassword)
resp, err := http.DefaultClient.Do(req)
- assert.NoError(t, err)
+ require.NoError(t, err)
defer resp.Body.Close()
- assert.EqualValues(t, kase.code, resp.StatusCode)
+ assert.Equal(t, kase.code, resp.StatusCode)
_, err = io.ReadAll(resp.Body)
- assert.NoError(t, err)
+ require.NoError(t, err)
})
}
}
+
+func testRenamedRepoRedirect(t *testing.T) {
+ defer test.MockVariableValue(&setting.Service.RequireSignInViewStrict, true)()
+
+ // git client requires to get a 301 redirect response before 401 unauthorized response
+ req := NewRequest(t, "GET", "/user2/oldrepo1/info/refs")
+ resp := MakeRequest(t, req, http.StatusMovedPermanently)
+ redirect := resp.Header().Get("Location")
+ assert.Equal(t, "/user2/repo1/info/refs", redirect)
+
+ req = NewRequest(t, "GET", redirect)
+ resp = MakeRequest(t, req, http.StatusUnauthorized)
+ assert.Equal(t, "Unauthorized\n", resp.Body.String())
+
+ req = NewRequest(t, "GET", redirect).AddBasicAuth("user2")
+ resp = MakeRequest(t, req, http.StatusOK)
+ assert.Contains(t, resp.Body.String(), "65f1bf27bc3bf70f64657658635e66094edbcb4d\trefs/tags/v1.1")
+}
diff --git a/tests/integration/gpg_git_test.go b/tests/integration/gpg_ssh_git_test.go
index acfe70026e..56f9f87783 100644
--- a/tests/integration/gpg_git_test.go
+++ b/tests/integration/gpg_ssh_git_test.go
@@ -4,7 +4,10 @@
package integration
import (
+ "crypto/ed25519"
+ "crypto/rand"
"encoding/base64"
+ "encoding/pem"
"fmt"
"net/url"
"os"
@@ -22,6 +25,8 @@ import (
"github.com/ProtonMail/go-crypto/openpgp"
"github.com/ProtonMail/go-crypto/openpgp/armor"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "golang.org/x/crypto/ssh"
)
func TestGPGGit(t *testing.T) {
@@ -33,9 +38,7 @@ func TestGPGGit(t *testing.T) {
// Need to create a root key
rootKeyPair, err := importTestingKey()
- if !assert.NoError(t, err, "importTestingKey") {
- return
- }
+ require.NoError(t, err, "importTestingKey")
defer test.MockVariableValue(&setting.Repository.Signing.SigningKey, rootKeyPair.PrimaryKey.KeyIdShortString())()
defer test.MockVariableValue(&setting.Repository.Signing.SigningName, "gitea")()
@@ -43,6 +46,37 @@ func TestGPGGit(t *testing.T) {
defer test.MockVariableValue(&setting.Repository.Signing.InitialCommit, []string{"never"})()
defer test.MockVariableValue(&setting.Repository.Signing.CRUDActions, []string{"never"})()
+ testGitSigning(t)
+}
+
+func TestSSHGit(t *testing.T) {
+ tmpDir := t.TempDir() // use a temp dir to store the SSH keys
+ err := os.Chmod(tmpDir, 0o700)
+ assert.NoError(t, err)
+
+ pub, priv, err := ed25519.GenerateKey(rand.Reader)
+ require.NoError(t, err, "ed25519.GenerateKey")
+ sshPubKey, err := ssh.NewPublicKey(pub)
+ require.NoError(t, err, "ssh.NewPublicKey")
+
+ err = os.WriteFile(tmpDir+"/id_ed25519.pub", ssh.MarshalAuthorizedKey(sshPubKey), 0o600)
+ require.NoError(t, err, "os.WriteFile id_ed25519.pub")
+ block, err := ssh.MarshalPrivateKey(priv, "")
+ require.NoError(t, err, "ssh.MarshalPrivateKey")
+ err = os.WriteFile(tmpDir+"/id_ed25519", pem.EncodeToMemory(block), 0o600)
+ require.NoError(t, err, "os.WriteFile id_ed25519")
+
+ defer test.MockVariableValue(&setting.Repository.Signing.SigningKey, tmpDir+"/id_ed25519.pub")()
+ defer test.MockVariableValue(&setting.Repository.Signing.SigningName, "gitea")()
+ defer test.MockVariableValue(&setting.Repository.Signing.SigningEmail, "gitea@fake.local")()
+ defer test.MockVariableValue(&setting.Repository.Signing.SigningFormat, "ssh")()
+ defer test.MockVariableValue(&setting.Repository.Signing.InitialCommit, []string{"never"})()
+ defer test.MockVariableValue(&setting.Repository.Signing.CRUDActions, []string{"never"})()
+
+ testGitSigning(t)
+}
+
+func testGitSigning(t *testing.T) {
username := "user2"
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: username})
baseAPITestContext := NewAPITestContext(t, username, "repo1")
@@ -100,26 +134,14 @@ func TestGPGGit(t *testing.T) {
testCtx := NewAPITestContext(t, username, "initial-unsigned", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
t.Run("CreateCRUDFile-Always", crudActionCreateFile(
t, testCtx, user, "master", "always", "signed-always.txt", func(t *testing.T, response api.FileResponse) {
- assert.NotNil(t, response.Verification)
- if response.Verification == nil {
- assert.FailNow(t, "no verification provided with response! %v", response)
- }
- assert.True(t, response.Verification.Verified)
- if !response.Verification.Verified {
- t.FailNow()
- }
+ require.NotNil(t, response.Verification, "no verification provided with response! %v", response)
+ require.True(t, response.Verification.Verified)
assert.Equal(t, "gitea@fake.local", response.Verification.Signer.Email)
}))
t.Run("CreateCRUDFile-ParentSigned-always", crudActionCreateFile(
t, testCtx, user, "parentsigned", "parentsigned-always", "signed-parent2.txt", func(t *testing.T, response api.FileResponse) {
- assert.NotNil(t, response.Verification)
- if response.Verification == nil {
- assert.FailNow(t, "no verification provided with response! %v", response)
- }
- assert.True(t, response.Verification.Verified)
- if !response.Verification.Verified {
- t.FailNow()
- }
+ require.NotNil(t, response.Verification, "no verification provided with response! %v", response)
+ require.True(t, response.Verification.Verified)
assert.Equal(t, "gitea@fake.local", response.Verification.Signer.Email)
}))
})
@@ -130,14 +152,8 @@ func TestGPGGit(t *testing.T) {
testCtx := NewAPITestContext(t, username, "initial-unsigned", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
t.Run("CreateCRUDFile-Always-ParentSigned", crudActionCreateFile(
t, testCtx, user, "always", "always-parentsigned", "signed-always-parentsigned.txt", func(t *testing.T, response api.FileResponse) {
- assert.NotNil(t, response.Verification)
- if response.Verification == nil {
- assert.FailNow(t, "no verification provided with response! %v", response)
- }
- assert.True(t, response.Verification.Verified)
- if !response.Verification.Verified {
- t.FailNow()
- }
+ require.NotNil(t, response.Verification, "no verification provided with response! %v", response)
+ require.True(t, response.Verification.Verified)
assert.Equal(t, "gitea@fake.local", response.Verification.Signer.Email)
}))
})
@@ -148,18 +164,9 @@ func TestGPGGit(t *testing.T) {
testCtx := NewAPITestContext(t, username, "initial-always", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
t.Run("CreateRepository", doAPICreateRepository(testCtx, false))
t.Run("CheckMasterBranchSigned", doAPIGetBranch(testCtx, "master", func(t *testing.T, branch api.Branch) {
- assert.NotNil(t, branch.Commit)
- if branch.Commit == nil {
- assert.FailNow(t, "no commit provided with branch! %v", branch)
- }
- assert.NotNil(t, branch.Commit.Verification)
- if branch.Commit.Verification == nil {
- assert.FailNow(t, "no verification provided with branch commit! %v", branch.Commit)
- }
- assert.True(t, branch.Commit.Verification.Verified)
- if !branch.Commit.Verification.Verified {
- t.FailNow()
- }
+ require.NotNil(t, branch.Commit, "no commit provided with branch! %v", branch)
+ require.NotNil(t, branch.Commit.Verification, "no verification provided with branch commit! %v", branch.Commit)
+ require.True(t, branch.Commit.Verification.Verified)
assert.Equal(t, "gitea@fake.local", branch.Commit.Verification.Signer.Email)
}))
})
@@ -182,11 +189,7 @@ func TestGPGGit(t *testing.T) {
t.Run("CreateRepository", doAPICreateRepository(testCtx, false))
t.Run("CreateCRUDFile-ParentSigned", crudActionCreateFile(
t, testCtx, user, "master", "parentsigned", "signed-parent.txt", func(t *testing.T, response api.FileResponse) {
- assert.True(t, response.Verification.Verified)
- if !response.Verification.Verified {
- t.FailNow()
- return
- }
+ require.True(t, response.Verification.Verified)
assert.Equal(t, "gitea@fake.local", response.Verification.Signer.Email)
}))
})
@@ -198,11 +201,7 @@ func TestGPGGit(t *testing.T) {
t.Run("CreateRepository", doAPICreateRepository(testCtx, false))
t.Run("CreateCRUDFile-Always", crudActionCreateFile(
t, testCtx, user, "master", "always", "signed-always.txt", func(t *testing.T, response api.FileResponse) {
- assert.True(t, response.Verification.Verified)
- if !response.Verification.Verified {
- t.FailNow()
- return
- }
+ require.True(t, response.Verification.Verified)
assert.Equal(t, "gitea@fake.local", response.Verification.Signer.Email)
}))
})
@@ -274,7 +273,7 @@ func crudActionCreateFile(_ *testing.T, ctx APITestContext, user *user_model.Use
Email: user.Email,
},
},
- ContentBase64: base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("This is new text for %s", path))),
+ ContentBase64: base64.StdEncoding.EncodeToString([]byte("This is new text for " + path)),
}, callback...)
}
diff --git a/tests/integration/html_helper.go b/tests/integration/html_helper.go
index 2217ddec2e..4d589b32e7 100644
--- a/tests/integration/html_helper.go
+++ b/tests/integration/html_helper.go
@@ -42,12 +42,13 @@ func (doc *HTMLDoc) GetCSRF() string {
return doc.GetInputValueByName("_csrf")
}
-// AssertElement check if element by selector exists or does not exist depending on checkExists
-func (doc *HTMLDoc) AssertElement(t testing.TB, selector string, checkExists bool) {
+// AssertHTMLElement check if the element by selector exists or does not exist depending on checkExists
+func AssertHTMLElement[T int | bool](t testing.TB, doc *HTMLDoc, selector string, checkExists T) {
sel := doc.doc.Find(selector)
- if checkExists {
- assert.Equal(t, 1, sel.Length())
- } else {
- assert.Equal(t, 0, sel.Length())
+ switch v := any(checkExists).(type) {
+ case bool:
+ assert.Equal(t, v, sel.Length() > 0)
+ case int:
+ assert.Equal(t, v, sel.Length())
}
}
diff --git a/tests/integration/incoming_email_test.go b/tests/integration/incoming_email_test.go
index e968a2956e..6ccf82a9eb 100644
--- a/tests/integration/incoming_email_test.go
+++ b/tests/integration/incoming_email_test.go
@@ -50,12 +50,12 @@ func TestIncomingEmail(t *testing.T) {
ref, err := incoming_payload.GetReferenceFromPayload(db.DefaultContext, issuePayload)
assert.NoError(t, err)
assert.IsType(t, ref, new(issues_model.Issue))
- assert.EqualValues(t, issue.ID, ref.(*issues_model.Issue).ID)
+ assert.Equal(t, issue.ID, ref.(*issues_model.Issue).ID)
ref, err = incoming_payload.GetReferenceFromPayload(db.DefaultContext, commentPayload)
assert.NoError(t, err)
assert.IsType(t, ref, new(issues_model.Comment))
- assert.EqualValues(t, comment.ID, ref.(*issues_model.Comment).ID)
+ assert.Equal(t, comment.ID, ref.(*issues_model.Comment).ID)
})
t.Run("Token", func(t *testing.T) {
diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go
index 9b3b2f2b92..5896a97ef1 100644
--- a/tests/integration/integration_test.go
+++ b/tests/integration/integration_test.go
@@ -1,7 +1,7 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
-//nolint:forbidigo
+//nolint:forbidigo // use of print functions is allowed in tests
package integration
import (
@@ -29,6 +29,7 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
+ "code.gitea.io/gitea/modules/web/middleware"
"code.gitea.io/gitea/routers"
gitea_context "code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/tests"
@@ -88,18 +89,6 @@ func TestMain(m *testing.M) {
tests.InitTest(true)
testWebRoutes = routers.NormalRoutes()
- os.Unsetenv("GIT_AUTHOR_NAME")
- os.Unsetenv("GIT_AUTHOR_EMAIL")
- os.Unsetenv("GIT_AUTHOR_DATE")
- os.Unsetenv("GIT_COMMITTER_NAME")
- os.Unsetenv("GIT_COMMITTER_EMAIL")
- os.Unsetenv("GIT_COMMITTER_DATE")
-
- // Avoid loading the default system config. On MacOS, this config
- // sets the osxkeychain credential helper, which will cause tests
- // to freeze with a dialog.
- os.Setenv("GIT_CONFIG_NOSYSTEM", "true")
-
err := unittest.InitFixtures(
unittest.FixturesOptions{
Dir: filepath.Join(filepath.Dir(setting.AppPath), "models/fixtures/"),
@@ -130,12 +119,11 @@ type TestSession struct {
jar http.CookieJar
}
-func (s *TestSession) GetCookie(name string) *http.Cookie {
+func (s *TestSession) GetRawCookie(name string) *http.Cookie {
baseURL, err := url.Parse(setting.AppURL)
if err != nil {
return nil
}
-
for _, c := range s.jar.Cookies(baseURL) {
if c.Name == name {
return c
@@ -144,8 +132,25 @@ func (s *TestSession) GetCookie(name string) *http.Cookie {
return nil
}
+func (s *TestSession) GetSiteCookie(name string) string {
+ c := s.GetRawCookie(name)
+ if c != nil {
+ v, _ := url.QueryUnescape(c.Value)
+ return v
+ }
+ return ""
+}
+
+func (s *TestSession) GetCookieFlashMessage() *middleware.Flash {
+ cookie := s.GetSiteCookie(gitea_context.CookieNameFlash)
+ return middleware.ParseCookieFlashMessage(cookie)
+}
+
func (s *TestSession) MakeRequest(t testing.TB, rw *RequestWrapper, expectedStatus int) *httptest.ResponseRecorder {
t.Helper()
+ if s == nil {
+ return MakeRequest(t, rw, expectedStatus)
+ }
req := rw.Request
baseURL, err := url.Parse(setting.AppURL)
assert.NoError(t, err)
@@ -247,55 +252,19 @@ func loginUserWithPassword(t testing.TB, userName, password string) *TestSession
// token has to be unique this counter take care of
var tokenCounter int64
-// getTokenForLoggedInUser returns a token for a logged in user.
-// The scope is an optional list of snake_case strings like the frontend form fields,
-// but without the "scope_" prefix.
+// getTokenForLoggedInUser returns a token for a logged-in user.
func getTokenForLoggedInUser(t testing.TB, session *TestSession, scopes ...auth.AccessTokenScope) string {
t.Helper()
- var token string
- req := NewRequest(t, "GET", "/user/settings/applications")
- resp := session.MakeRequest(t, req, http.StatusOK)
- var csrf string
- for _, cookie := range resp.Result().Cookies() {
- if cookie.Name != "_csrf" {
- continue
- }
- csrf = cookie.Value
- break
- }
- if csrf == "" {
- doc := NewHTMLParser(t, resp.Body)
- csrf = doc.GetCSRF()
- }
- assert.NotEmpty(t, csrf)
urlValues := url.Values{}
- urlValues.Add("_csrf", csrf)
+ urlValues.Add("_csrf", GetUserCSRFToken(t, session))
urlValues.Add("name", fmt.Sprintf("api-testing-token-%d", atomic.AddInt64(&tokenCounter, 1)))
for _, scope := range scopes {
- urlValues.Add("scope", string(scope))
+ urlValues.Add("scope-dummy", string(scope)) // it only needs to start with "scope-" to be accepted
}
- req = NewRequestWithURLValues(t, "POST", "/user/settings/applications", urlValues)
- resp = session.MakeRequest(t, req, http.StatusSeeOther)
-
- // Log the flash values on failure
- if !assert.Equal(t, []string{"/user/settings/applications"}, resp.Result().Header["Location"]) {
- for _, cookie := range resp.Result().Cookies() {
- if cookie.Name != gitea_context.CookieNameFlash {
- continue
- }
- flash, _ := url.ParseQuery(cookie.Value)
- for key, value := range flash {
- t.Logf("Flash %q: %q", key, value)
- }
- }
- }
-
- req = NewRequest(t, "GET", "/user/settings/applications")
- resp = session.MakeRequest(t, req, http.StatusOK)
- htmlDoc := NewHTMLParser(t, resp.Body)
- token = htmlDoc.doc.Find(".ui.info p").Text()
- assert.NotEmpty(t, token)
- return token
+ req := NewRequestWithURLValues(t, "POST", "/user/settings/applications", urlValues)
+ session.MakeRequest(t, req, http.StatusSeeOther)
+ flashes := session.GetCookieFlashMessage()
+ return flashes.InfoMsg
}
type RequestWrapper struct {
@@ -344,7 +313,7 @@ func NewRequestWithValues(t testing.TB, method, urlStr string, values map[string
func NewRequestWithURLValues(t testing.TB, method, urlStr string, urlValues url.Values) *RequestWrapper {
t.Helper()
- return NewRequestWithBody(t, method, urlStr, bytes.NewBufferString(urlValues.Encode())).
+ return NewRequestWithBody(t, method, urlStr, strings.NewReader(urlValues.Encode())).
SetHeader("Content-Type", "application/x-www-form-urlencoded")
}
@@ -394,7 +363,7 @@ func MakeRequestNilResponseRecorder(t testing.TB, rw *RequestWrapper, expectedSt
recorder := NewNilResponseRecorder()
testWebRoutes.ServeHTTP(recorder, req)
if expectedStatus != NoExpectedStatus {
- if !assert.EqualValues(t, expectedStatus, recorder.Code,
+ if !assert.Equal(t, expectedStatus, recorder.Code,
"Request: %s %s", req.Method, req.URL.String()) {
logUnexpectedResponse(t, &recorder.ResponseRecorder)
}
@@ -408,7 +377,7 @@ func MakeRequestNilResponseHashSumRecorder(t testing.TB, rw *RequestWrapper, exp
recorder := NewNilResponseHashSumRecorder()
testWebRoutes.ServeHTTP(recorder, req)
if expectedStatus != NoExpectedStatus {
- if !assert.EqualValues(t, expectedStatus, recorder.Code,
+ if !assert.Equal(t, expectedStatus, recorder.Code,
"Request: %s %s", req.Method, req.URL.String()) {
logUnexpectedResponse(t, &recorder.ResponseRecorder)
}
@@ -470,9 +439,9 @@ func VerifyJSONSchema(t testing.TB, resp *httptest.ResponseRecorder, schemaFile
// GetUserCSRFToken returns CSRF token for current user
func GetUserCSRFToken(t testing.TB, session *TestSession) string {
t.Helper()
- cookie := session.GetCookie("_csrf")
+ cookie := session.GetSiteCookie("_csrf")
require.NotEmpty(t, cookie)
- return cookie.Value
+ return cookie
}
// GetUserCSRFToken returns CSRF token for anonymous user (not logged in)
diff --git a/tests/integration/issue_test.go b/tests/integration/issue_test.go
index 4617c5f89a..b5dca58357 100644
--- a/tests/integration/issue_test.go
+++ b/tests/integration/issue_test.go
@@ -4,7 +4,6 @@
package integration
import (
- "context"
"fmt"
"html/template"
"net/http"
@@ -33,7 +32,7 @@ import (
func getIssuesSelection(t testing.TB, htmlDoc *HTMLDoc) *goquery.Selection {
issueList := htmlDoc.doc.Find("#issue-list")
- assert.EqualValues(t, 1, issueList.Length())
+ assert.Equal(t, 1, issueList.Length())
return issueList.Find(".flex-item").Find(".issue-title")
}
@@ -77,19 +76,16 @@ func TestViewIssuesSortByType(t *testing.T) {
htmlDoc := NewHTMLParser(t, resp.Body)
issuesSelection := getIssuesSelection(t, htmlDoc)
- expectedNumIssues := unittest.GetCount(t,
+ expectedNumIssues := min(unittest.GetCount(t,
&issues_model.Issue{RepoID: repo.ID, PosterID: user.ID},
unittest.Cond("is_closed=?", false),
unittest.Cond("is_pull=?", false),
- )
- if expectedNumIssues > setting.UI.IssuePagingNum {
- expectedNumIssues = setting.UI.IssuePagingNum
- }
- assert.EqualValues(t, expectedNumIssues, issuesSelection.Length())
+ ), setting.UI.IssuePagingNum)
+ assert.Equal(t, expectedNumIssues, issuesSelection.Length())
issuesSelection.Each(func(_ int, selection *goquery.Selection) {
issue := getIssue(t, repo.ID, selection)
- assert.EqualValues(t, user.ID, issue.PosterID)
+ assert.Equal(t, user.ID, issue.PosterID)
})
}
@@ -101,7 +97,7 @@ func TestViewIssuesKeyword(t *testing.T) {
RepoID: repo.ID,
Index: 1,
})
- issues.UpdateIssueIndexer(context.Background(), issue.ID)
+ issues.UpdateIssueIndexer(t.Context(), issue.ID)
time.Sleep(time.Second * 1)
const keyword = "first"
req := NewRequestf(t, "GET", "%s/issues?q=%s", repo.Link(), keyword)
@@ -109,7 +105,7 @@ func TestViewIssuesKeyword(t *testing.T) {
htmlDoc := NewHTMLParser(t, resp.Body)
issuesSelection := getIssuesSelection(t, htmlDoc)
- assert.EqualValues(t, 1, issuesSelection.Length())
+ assert.Equal(t, 1, issuesSelection.Length())
issuesSelection.Each(func(_ int, selection *goquery.Selection) {
issue := getIssue(t, repo.ID, selection)
assert.False(t, issue.IsClosed)
@@ -152,6 +148,22 @@ func testNewIssue(t *testing.T, session *TestSession, user, repo, title, content
return issueURL
}
+func testIssueDelete(t *testing.T, session *TestSession, issueURL string) {
+ req := NewRequestWithValues(t, "POST", path.Join(issueURL, "delete"), map[string]string{
+ "_csrf": GetUserCSRFToken(t, session),
+ })
+ session.MakeRequest(t, req, http.StatusSeeOther)
+}
+
+func testIssueAssign(t *testing.T, session *TestSession, repoLink string, issueID, assigneeID int64) {
+ req := NewRequestWithValues(t, "POST", fmt.Sprintf(repoLink+"/issues/assignee?issue_ids=%d", issueID), map[string]string{
+ "_csrf": GetUserCSRFToken(t, session),
+ "id": strconv.FormatInt(assigneeID, 10),
+ "action": "", // empty action means assign
+ })
+ session.MakeRequest(t, req, http.StatusOK)
+}
+
func testIssueAddComment(t *testing.T, session *TestSession, issueURL, content, status string) int64 {
req := NewRequest(t, "GET", issueURL)
resp := session.MakeRequest(t, req, http.StatusOK)
@@ -174,7 +186,7 @@ func testIssueAddComment(t *testing.T, session *TestSession, issueURL, content,
htmlDoc = NewHTMLParser(t, resp.Body)
- val := htmlDoc.doc.Find(".comment-list .comment .render-content p").Eq(commentCount).Text()
+ val := strings.TrimSpace(htmlDoc.doc.Find(".comment-list .comment .render-content").Eq(commentCount).Text())
assert.Equal(t, content, val)
idAttr, has := htmlDoc.doc.Find(".comment-list .comment").Eq(commentCount).Attr("id")
@@ -185,6 +197,15 @@ func testIssueAddComment(t *testing.T, session *TestSession, issueURL, content,
return int64(id)
}
+func testIssueChangeMilestone(t *testing.T, session *TestSession, repoLink string, issueID, milestoneID int64) {
+ req := NewRequestWithValues(t, "POST", fmt.Sprintf(repoLink+"/issues/milestone?issue_ids=%d", issueID), map[string]string{
+ "_csrf": GetUserCSRFToken(t, session),
+ "id": strconv.FormatInt(milestoneID, 10),
+ })
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ assert.Equal(t, `{"ok":true}`, strings.TrimSpace(resp.Body.String()))
+}
+
func TestNewIssue(t *testing.T) {
defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user2")
@@ -196,21 +217,21 @@ func TestEditIssue(t *testing.T) {
session := loginUser(t, "user2")
issueURL := testNewIssue(t, session, "user2", "repo1", "Title", "Description")
- req := NewRequestWithValues(t, "POST", fmt.Sprintf("%s/content", issueURL), map[string]string{
+ req := NewRequestWithValues(t, "POST", issueURL+"/content", map[string]string{
"_csrf": GetUserCSRFToken(t, session),
"content": "modified content",
"context": fmt.Sprintf("/%s/%s", "user2", "repo1"),
})
session.MakeRequest(t, req, http.StatusOK)
- req = NewRequestWithValues(t, "POST", fmt.Sprintf("%s/content", issueURL), map[string]string{
+ req = NewRequestWithValues(t, "POST", issueURL+"/content", map[string]string{
"_csrf": GetUserCSRFToken(t, session),
"content": "modified content",
"context": fmt.Sprintf("/%s/%s", "user2", "repo1"),
})
session.MakeRequest(t, req, http.StatusBadRequest)
- req = NewRequestWithValues(t, "POST", fmt.Sprintf("%s/content", issueURL), map[string]string{
+ req = NewRequestWithValues(t, "POST", issueURL+"/content", map[string]string{
"_csrf": GetUserCSRFToken(t, session),
"content": "modified content",
"content_version": "1",
@@ -474,10 +495,7 @@ func TestSearchIssues(t *testing.T) {
session := loginUser(t, "user2")
- expectedIssueCount := 20 // from the fixtures
- if expectedIssueCount > setting.UI.IssuePagingNum {
- expectedIssueCount = setting.UI.IssuePagingNum
- }
+ expectedIssueCount := min(20, setting.UI.IssuePagingNum) // 20 is from the fixtures
link, _ := url.Parse("/issues/search")
req := NewRequest(t, "GET", link.String())
@@ -511,7 +529,7 @@ func TestSearchIssues(t *testing.T) {
req = NewRequest(t, "GET", link.String())
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
- assert.EqualValues(t, "22", resp.Header().Get("X-Total-Count"))
+ assert.Equal(t, "22", resp.Header().Get("X-Total-Count"))
assert.Len(t, apiIssues, 20)
query.Add("limit", "5")
@@ -519,7 +537,7 @@ func TestSearchIssues(t *testing.T) {
req = NewRequest(t, "GET", link.String())
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
- assert.EqualValues(t, "22", resp.Header().Get("X-Total-Count"))
+ assert.Equal(t, "22", resp.Header().Get("X-Total-Count"))
assert.Len(t, apiIssues, 5)
query = url.Values{"assigned": {"true"}, "state": {"all"}}
@@ -568,10 +586,7 @@ func TestSearchIssues(t *testing.T) {
func TestSearchIssuesWithLabels(t *testing.T) {
defer tests.PrepareTestEnv(t)()
- expectedIssueCount := 20 // from the fixtures
- if expectedIssueCount > setting.UI.IssuePagingNum {
- expectedIssueCount = setting.UI.IssuePagingNum
- }
+ expectedIssueCount := min(20, setting.UI.IssuePagingNum) // 20 is from the fixtures
session := loginUser(t, "user1")
link, _ := url.Parse("/issues/search")
@@ -646,7 +661,7 @@ func TestGetIssueInfo(t *testing.T) {
}
DecodeJSON(t, resp, &respStruct)
- assert.EqualValues(t, issue.ID, respStruct.ConvertedIssue.ID)
+ assert.Equal(t, issue.ID, respStruct.ConvertedIssue.ID)
assert.Contains(t, string(respStruct.RenderedLabels), `"labels-list"`)
}
@@ -666,7 +681,7 @@ func TestUpdateIssueDeadline(t *testing.T) {
req := NewRequestWithValues(t, "POST", urlStr, map[string]string{"deadline": "2022-04-06"})
session.MakeRequest(t, req, http.StatusOK)
issueAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10})
- assert.EqualValues(t, "2022-04-06", issueAfter.DeadlineUnix.FormatDate())
+ assert.Equal(t, "2022-04-06", issueAfter.DeadlineUnix.FormatDate())
req = NewRequestWithValues(t, "POST", urlStr, map[string]string{"deadline": ""})
session.MakeRequest(t, req, http.StatusOK)
@@ -687,8 +702,8 @@ func TestIssueReferenceURL(t *testing.T) {
// the "reference" uses relative URLs, then JS code will convert them to absolute URLs for current origin, in case users are using multiple domains
ref, _ := htmlDoc.Find(`.timeline-item.comment.first .reference-issue`).Attr("data-reference")
- assert.EqualValues(t, "/user2/repo1/issues/1#issue-1", ref)
+ assert.Equal(t, "/user2/repo1/issues/1#issue-1", ref)
ref, _ = htmlDoc.Find(`.timeline-item.comment:not(.first) .reference-issue`).Attr("data-reference")
- assert.EqualValues(t, "/user2/repo1/issues/1#issuecomment-2", ref)
+ assert.Equal(t, "/user2/repo1/issues/1#issuecomment-2", ref)
}
diff --git a/tests/integration/lfs_local_endpoint_test.go b/tests/integration/lfs_local_endpoint_test.go
index d42888bbe1..e67f0712a3 100644
--- a/tests/integration/lfs_local_endpoint_test.go
+++ b/tests/integration/lfs_local_endpoint_test.go
@@ -4,7 +4,6 @@
package integration
import (
- "fmt"
"net/url"
"os"
"path/filepath"
@@ -41,55 +40,55 @@ func TestDetermineLocalEndpoint(t *testing.T) {
{
cloneurl: root,
lfsurl: "",
- expected: str2url(fmt.Sprintf("file://%s", root)),
+ expected: str2url("file://" + root),
},
// case 1
{
cloneurl: root,
lfsurl: lfsroot,
- expected: str2url(fmt.Sprintf("file://%s", lfsroot)),
+ expected: str2url("file://" + lfsroot),
},
// case 2
{
cloneurl: "https://git.com/repo.git",
lfsurl: lfsroot,
- expected: str2url(fmt.Sprintf("file://%s", lfsroot)),
+ expected: str2url("file://" + lfsroot),
},
// case 3
{
cloneurl: rootdotgit,
lfsurl: "",
- expected: str2url(fmt.Sprintf("file://%s", filepath.Join(rootdotgit, ".git"))),
+ expected: str2url("file://" + filepath.Join(rootdotgit, ".git")),
},
// case 4
{
cloneurl: "",
lfsurl: rootdotgit,
- expected: str2url(fmt.Sprintf("file://%s", filepath.Join(rootdotgit, ".git"))),
+ expected: str2url("file://" + filepath.Join(rootdotgit, ".git")),
},
// case 5
{
cloneurl: rootdotgit,
lfsurl: rootdotgit,
- expected: str2url(fmt.Sprintf("file://%s", filepath.Join(rootdotgit, ".git"))),
+ expected: str2url("file://" + filepath.Join(rootdotgit, ".git")),
},
// case 6
{
- cloneurl: fmt.Sprintf("file://%s", root),
+ cloneurl: "file://" + root,
lfsurl: "",
- expected: str2url(fmt.Sprintf("file://%s", root)),
+ expected: str2url("file://" + root),
},
// case 7
{
- cloneurl: fmt.Sprintf("file://%s", root),
- lfsurl: fmt.Sprintf("file://%s", lfsroot),
- expected: str2url(fmt.Sprintf("file://%s", lfsroot)),
+ cloneurl: "file://" + root,
+ lfsurl: "file://" + lfsroot,
+ expected: str2url("file://" + lfsroot),
},
// case 8
{
cloneurl: root,
- lfsurl: fmt.Sprintf("file://%s", lfsroot),
- expected: str2url(fmt.Sprintf("file://%s", lfsroot)),
+ lfsurl: "file://" + lfsroot,
+ expected: str2url("file://" + lfsroot),
},
// case 9
{
diff --git a/tests/integration/lfs_view_test.go b/tests/integration/lfs_view_test.go
index a0e004ed58..c26ece22be 100644
--- a/tests/integration/lfs_view_test.go
+++ b/tests/integration/lfs_view_test.go
@@ -4,7 +4,6 @@
package integration
import (
- "context"
"fmt"
"net/http"
"strings"
@@ -39,7 +38,7 @@ func TestLFSRender(t *testing.T) {
doc := NewHTMLParser(t, resp.Body).doc
fileInfo := doc.Find("div.file-info-entry").First().Text()
- assert.Contains(t, fileInfo, "Stored with Git LFS")
+ assert.Contains(t, fileInfo, "LFS")
content := doc.Find("div.file-view").Text()
assert.Contains(t, content, "Testing documents in LFS")
@@ -55,7 +54,7 @@ func TestLFSRender(t *testing.T) {
doc := NewHTMLParser(t, resp.Body).doc
fileInfo := doc.Find("div.file-info-entry").First().Text()
- assert.Contains(t, fileInfo, "Stored with Git LFS")
+ assert.Contains(t, fileInfo, "LFS")
src, exists := doc.Find(".file-view img").Attr("src")
assert.True(t, exists, "The image should be in an <img> tag")
@@ -69,14 +68,15 @@ func TestLFSRender(t *testing.T) {
req := NewRequest(t, "GET", "/user2/lfs/src/branch/master/crypt.bin")
resp := session.MakeRequest(t, req, http.StatusOK)
- doc := NewHTMLParser(t, resp.Body).doc
+ doc := NewHTMLParser(t, resp.Body)
fileInfo := doc.Find("div.file-info-entry").First().Text()
- assert.Contains(t, fileInfo, "Stored with Git LFS")
+ assert.Contains(t, fileInfo, "LFS")
- rawLink, exists := doc.Find("div.file-view > div.view-raw > a").Attr("href")
- assert.True(t, exists, "Download link should render instead of content because this is a binary file")
- assert.Equal(t, "/user2/lfs/media/branch/master/crypt.bin", rawLink, "The download link should use the proper /media link because it's in LFS")
+ // find new file view container
+ fileViewContainer := doc.Find("[data-global-init=initRepoFileView]")
+ assert.Equal(t, "/user2/lfs/media/branch/master/crypt.bin", fileViewContainer.AttrOr("data-raw-file-link", ""))
+ AssertHTMLElement(t, doc, ".view-raw > .file-view-render-container > .file-view-raw-prompt", 1)
})
// check that a directory with a README file shows its text
@@ -143,7 +143,7 @@ func TestLFSLockView(t *testing.T) {
defer tests.PrintCurrentTest(t)()
// make sure the display names are different, or the test is meaningless
- require.NoError(t, repo3.LoadOwner(context.Background()))
+ require.NoError(t, repo3.LoadOwner(t.Context()))
require.NotEqual(t, user2.DisplayName(), repo3.Owner.DisplayName())
req := NewRequest(t, "GET", fmt.Sprintf("/%s/settings/lfs/locks", repo3.FullName()))
diff --git a/tests/integration/linguist_test.go b/tests/integration/linguist_test.go
index 2d50dc599a..d156dd6f3d 100644
--- a/tests/integration/linguist_test.go
+++ b/tests/integration/linguist_test.go
@@ -4,7 +4,6 @@
package integration
import (
- "context"
"net/url"
"strconv"
"strings"
@@ -246,7 +245,7 @@ func TestLinguist(t *testing.T) {
assert.NoError(t, err)
assert.NoError(t, stats.UpdateRepoIndexer(repo))
- assert.NoError(t, queue.GetManager().FlushAll(context.Background(), 10*time.Second))
+ assert.NoError(t, queue.GetManager().FlushAll(t.Context(), 10*time.Second))
stats, err := repo_model.GetTopLanguageStats(db.DefaultContext, repo, len(c.FilesToAdd))
assert.NoError(t, err)
diff --git a/tests/integration/links_test.go b/tests/integration/links_test.go
index b54f670c23..f80cc6f3f9 100644
--- a/tests/integration/links_test.go
+++ b/tests/integration/links_test.go
@@ -17,56 +17,68 @@ import (
"github.com/stretchr/testify/assert"
)
-func TestLinksNoLogin(t *testing.T) {
+func assertLinkPageComplete(t *testing.T, session *TestSession, link string) {
+ req := NewRequest(t, "GET", link)
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ assert.True(t, test.IsNormalPageCompleted(resp.Body.String()), "Page did not complete: "+link)
+}
+
+func TestLinks(t *testing.T) {
defer tests.PrepareTestEnv(t)()
+ t.Run("NoLogin", testLinksNoLogin)
+ t.Run("RedirectsNoLogin", testLinksRedirectsNoLogin)
+ t.Run("NoLoginNotExist", testLinksNoLoginNotExist)
+ t.Run("AsUser", testLinksAsUser)
+ t.Run("RepoCommon", testLinksRepoCommon)
+}
+
+func testLinksNoLogin(t *testing.T) {
links := []string{
+ "/",
"/explore/repos",
"/explore/repos?q=test",
"/explore/users",
"/explore/users?q=test",
"/explore/organizations",
"/explore/organizations?q=test",
- "/",
"/user/sign_up",
"/user/login",
"/user/forgot_password",
- "/api/swagger",
"/user2/repo1",
"/user2/repo1/",
"/user2/repo1/projects",
"/user2/repo1/projects/1",
"/user2/repo1/releases/tag/delete-tag", // It's the only one existing record on release.yml which has is_tag: true
- "/.well-known/security.txt",
+ "/api/swagger",
}
-
for _, link := range links {
- req := NewRequest(t, "GET", link)
- MakeRequest(t, req, http.StatusOK)
+ assertLinkPageComplete(t, nil, link)
}
+ MakeRequest(t, NewRequest(t, "GET", "/.well-known/security.txt"), http.StatusOK)
}
-func TestRedirectsNoLogin(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
-
+func testLinksRedirectsNoLogin(t *testing.T) {
redirects := []struct{ from, to string }{
{"/user2/repo1/commits/master", "/user2/repo1/commits/branch/master"},
{"/user2/repo1/src/master", "/user2/repo1/src/branch/master"},
- {"/user2/repo1/src/master/file.txt", "/user2/repo1/src/branch/master/file.txt"},
- {"/user2/repo1/src/master/directory/file.txt", "/user2/repo1/src/branch/master/directory/file.txt"},
- {"/user/avatar/Ghost/-1", "/assets/img/avatar_default.png"},
+ {"/user2/repo1/src/master/a%2fb.txt", "/user2/repo1/src/branch/master/a%2fb.txt"},
+ {"/user2/repo1/src/master/directory/file.txt?a=1", "/user2/repo1/src/branch/master/directory/file.txt?a=1"},
+ {"/user2/repo1/src/branch/master/directory/file.txt?raw=1&other=2", "/user2/repo1/raw/branch/master/directory/file.txt"},
+ {"/user2/repo1/tree/a%2fb?a=1", "/user2/repo1/src/a%2fb?a=1"},
+ {"/user2/repo1/blob/123456/%20?a=1", "/user2/repo1/src/commit/123456/%20?a=1"},
+ {"/user/avatar/GhosT/-1", "/assets/img/avatar_default.png"},
+ {"/user/avatar/Gitea-ActionS/0", "/assets/img/avatar_default.png"},
{"/api/v1/swagger", "/api/swagger"},
}
for _, c := range redirects {
req := NewRequest(t, "GET", c.from)
resp := MakeRequest(t, req, http.StatusSeeOther)
- assert.EqualValues(t, path.Join(setting.AppSubURL, c.to), test.RedirectURL(resp))
+ assert.Equal(t, path.Join(setting.AppSubURL, c.to), test.RedirectURL(resp))
}
}
-func TestNoLoginNotExist(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
-
+func testLinksNoLoginNotExist(t *testing.T) {
links := []string{
"/user5/repo4/projects",
"/user5/repo4/projects/3",
@@ -78,7 +90,8 @@ func TestNoLoginNotExist(t *testing.T) {
}
}
-func testLinksAsUser(userName string, t *testing.T) {
+func testLinksAsUser(t *testing.T) {
+ session := loginUser(t, "user2")
links := []string{
"/explore/repos",
"/explore/repos?q=test",
@@ -126,18 +139,14 @@ func testLinksAsUser(userName string, t *testing.T) {
"/user/settings/repos",
}
- session := loginUser(t, userName)
for _, link := range links {
- req := NewRequest(t, "GET", link)
- session.MakeRequest(t, req, http.StatusOK)
+ assertLinkPageComplete(t, session, link)
}
- reqAPI := NewRequestf(t, "GET", "/api/v1/users/%s/repos", userName)
+ reqAPI := NewRequestf(t, "GET", "/api/v1/users/user2/repos")
respAPI := MakeRequest(t, reqAPI, http.StatusOK)
-
var apiRepos []*api.Repository
DecodeJSON(t, respAPI, &apiRepos)
-
repoLinks := []string{
"",
"/issues",
@@ -160,24 +169,15 @@ func testLinksAsUser(userName string, t *testing.T) {
"/wiki/?action=_new",
"/activity",
}
-
for _, repo := range apiRepos {
for _, link := range repoLinks {
- req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s%s", userName, repo.Name, link))
- session.MakeRequest(t, req, http.StatusOK)
+ link = fmt.Sprintf("/user2/%s%s", repo.Name, link)
+ assertLinkPageComplete(t, session, link)
}
}
}
-func TestLinksLogin(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
-
- testLinksAsUser("user2", t)
-}
-
-func TestRepoLinks(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
-
+func testLinksRepoCommon(t *testing.T) {
// repo1 has enabled almost features, so we can test most links
repoLink := "/user2/repo1"
links := []string{
@@ -188,21 +188,18 @@ func TestRepoLinks(t *testing.T) {
// anonymous user
for _, link := range links {
- req := NewRequest(t, "GET", repoLink+link)
- MakeRequest(t, req, http.StatusOK)
+ assertLinkPageComplete(t, nil, repoLink+link)
}
// admin/owner user
session := loginUser(t, "user1")
for _, link := range links {
- req := NewRequest(t, "GET", repoLink+link)
- session.MakeRequest(t, req, http.StatusOK)
+ assertLinkPageComplete(t, session, repoLink+link)
}
// non-admin non-owner user
session = loginUser(t, "user2")
for _, link := range links {
- req := NewRequest(t, "GET", repoLink+link)
- session.MakeRequest(t, req, http.StatusOK)
+ assertLinkPageComplete(t, session, repoLink+link)
}
}
diff --git a/tests/integration/markup_external_test.go b/tests/integration/markup_external_test.go
index 2d713b0eb9..47d143a29e 100644
--- a/tests/integration/markup_external_test.go
+++ b/tests/integration/markup_external_test.go
@@ -27,7 +27,7 @@ func TestExternalMarkupRenderer(t *testing.T) {
req := NewRequest(t, "GET", "/user30/renderer/src/branch/master/README.html")
resp := MakeRequest(t, req, http.StatusOK)
- assert.EqualValues(t, "text/html; charset=utf-8", resp.Header().Get("Content-Type"))
+ assert.Equal(t, "text/html; charset=utf-8", resp.Header().Get("Content-Type"))
bs, err := io.ReadAll(resp.Body)
assert.NoError(t, err)
@@ -36,25 +36,25 @@ func TestExternalMarkupRenderer(t *testing.T) {
div := doc.Find("div.file-view")
data, err := div.Html()
assert.NoError(t, err)
- assert.EqualValues(t, "<div>\n\ttest external renderer\n</div>", strings.TrimSpace(data))
+ assert.Equal(t, "<div>\n\ttest external renderer\n</div>", strings.TrimSpace(data))
r := markup.GetRendererByFileName("a.html").(*external.Renderer)
r.RenderContentMode = setting.RenderContentModeIframe
req = NewRequest(t, "GET", "/user30/renderer/src/branch/master/README.html")
resp = MakeRequest(t, req, http.StatusOK)
- assert.EqualValues(t, "text/html; charset=utf-8", resp.Header().Get("Content-Type"))
+ assert.Equal(t, "text/html; charset=utf-8", resp.Header().Get("Content-Type"))
bs, err = io.ReadAll(resp.Body)
assert.NoError(t, err)
doc = NewHTMLParser(t, bytes.NewBuffer(bs))
iframe := doc.Find("iframe")
- assert.EqualValues(t, "/user30/renderer/render/branch/master/README.html", iframe.AttrOr("src", ""))
+ assert.Equal(t, "/user30/renderer/render/branch/master/README.html", iframe.AttrOr("src", ""))
req = NewRequest(t, "GET", "/user30/renderer/render/branch/master/README.html")
resp = MakeRequest(t, req, http.StatusOK)
- assert.EqualValues(t, "text/html; charset=utf-8", resp.Header().Get("Content-Type"))
+ assert.Equal(t, "text/html; charset=utf-8", resp.Header().Get("Content-Type"))
bs, err = io.ReadAll(resp.Body)
assert.NoError(t, err)
- assert.EqualValues(t, "frame-src 'self'; sandbox allow-scripts", resp.Header().Get("Content-Security-Policy"))
- assert.EqualValues(t, "<div>\n\ttest external renderer\n</div>\n", string(bs))
+ assert.Equal(t, "frame-src 'self'; sandbox allow-scripts", resp.Header().Get("Content-Security-Policy"))
+ assert.Equal(t, "<div>\n\ttest external renderer\n</div>\n", string(bs))
}
diff --git a/tests/integration/migrate_test.go b/tests/integration/migrate_test.go
index 4c784dd22b..a89dc8b85c 100644
--- a/tests/integration/migrate_test.go
+++ b/tests/integration/migrate_test.go
@@ -9,6 +9,7 @@ import (
"net/url"
"os"
"path/filepath"
+ "strconv"
"testing"
auth_model "code.gitea.io/gitea/models/auth"
@@ -79,8 +80,12 @@ func TestMigrateGiteaForm(t *testing.T) {
resp := session.MakeRequest(t, req, http.StatusOK)
// Step 2: load the form
htmlDoc := NewHTMLParser(t, resp.Body)
- link, exists := htmlDoc.doc.Find(`form.ui.form[action^="/repo/migrate"]`).Attr("action")
+ form := htmlDoc.doc.Find(`form.ui.form[action^="/repo/migrate"]`)
+ link, exists := form.Attr("action")
assert.True(t, exists, "The template has changed")
+ serviceInput, exists := form.Find(`input[name="service"]`).Attr("value")
+ assert.True(t, exists)
+ assert.Equal(t, fmt.Sprintf("%d", structs.GiteaService), serviceInput)
// Step 4: submit the migration to only migrate issues
migratedRepoName := "otherrepo"
req = NewRequestWithValues(t, "POST", link, map[string]string{
@@ -91,12 +96,12 @@ func TestMigrateGiteaForm(t *testing.T) {
"issues": "on",
"repo_name": migratedRepoName,
"description": "",
- "uid": fmt.Sprintf("%d", repoOwner.ID),
+ "uid": strconv.FormatInt(repoOwner.ID, 10),
})
resp = session.MakeRequest(t, req, http.StatusSeeOther)
// Step 5: a redirection displays the migrated repository
loc := resp.Header().Get("Location")
- assert.EqualValues(t, fmt.Sprintf("/%s/%s", ownerName, migratedRepoName), loc)
+ assert.Equal(t, fmt.Sprintf("/%s/%s", ownerName, migratedRepoName), loc)
// Step 6: check the repo was created
unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: migratedRepoName})
})
diff --git a/tests/integration/migration-test/migration_test.go b/tests/integration/migration-test/migration_test.go
index 616ccf291a..0fc8a6e24d 100644
--- a/tests/integration/migration-test/migration_test.go
+++ b/tests/integration/migration-test/migration_test.go
@@ -38,7 +38,7 @@ var currentEngine *xorm.Engine
func initMigrationTest(t *testing.T) func() {
testlogger.Init()
giteaRoot := test.SetupGiteaRoot()
- setting.AppPath = path.Join(giteaRoot, "gitea")
+ setting.AppPath = filepath.Join(giteaRoot, "gitea")
if _, err := os.Stat(setting.AppPath); err != nil {
testlogger.Fatalf(fmt.Sprintf("Could not find gitea binary at %s\n", setting.AppPath))
}
@@ -47,16 +47,16 @@ func initMigrationTest(t *testing.T) func() {
if giteaConf == "" {
testlogger.Fatalf("Environment variable $GITEA_CONF not set\n")
} else if !path.IsAbs(giteaConf) {
- setting.CustomConf = path.Join(giteaRoot, giteaConf)
+ setting.CustomConf = filepath.Join(giteaRoot, giteaConf)
} else {
setting.CustomConf = giteaConf
}
- unittest.InitSettings()
+ unittest.InitSettingsForTesting()
assert.NotEmpty(t, setting.RepoRootPath)
- assert.NoError(t, unittest.SyncDirs(path.Join(filepath.Dir(setting.AppPath), "tests/gitea-repositories-meta"), setting.RepoRootPath))
- assert.NoError(t, git.InitFull(context.Background()))
+ assert.NoError(t, unittest.SyncDirs(filepath.Join(filepath.Dir(setting.AppPath), "tests/gitea-repositories-meta"), setting.RepoRootPath))
+ assert.NoError(t, git.InitFull(t.Context()))
setting.LoadDBSetting()
setting.InitLoggersForTest()
@@ -140,10 +140,10 @@ func restoreOldDB(t *testing.T, version string) {
assert.NoError(t, err)
defer db.Close()
- _, err = db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %s", setting.Database.Name))
+ _, err = db.Exec("DROP DATABASE IF EXISTS " + setting.Database.Name)
assert.NoError(t, err)
- _, err = db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s", setting.Database.Name))
+ _, err = db.Exec("CREATE DATABASE IF NOT EXISTS " + setting.Database.Name)
assert.NoError(t, err)
db.Close()
@@ -170,10 +170,10 @@ func restoreOldDB(t *testing.T, version string) {
}
defer db.Close()
- _, err = db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %s", setting.Database.Name))
+ _, err = db.Exec("DROP DATABASE IF EXISTS " + setting.Database.Name)
assert.NoError(t, err)
- _, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s", setting.Database.Name))
+ _, err = db.Exec("CREATE DATABASE " + setting.Database.Name)
assert.NoError(t, err)
db.Close()
@@ -195,7 +195,7 @@ func restoreOldDB(t *testing.T, version string) {
if !schrows.Next() {
// Create and setup a DB schema
- _, err = db.Exec(fmt.Sprintf("CREATE SCHEMA %s", setting.Database.Schema))
+ _, err = db.Exec("CREATE SCHEMA " + setting.Database.Schema)
assert.NoError(t, err)
}
schrows.Close()
@@ -248,7 +248,7 @@ func restoreOldDB(t *testing.T, version string) {
}
}
-func wrappedMigrate(x *xorm.Engine) error {
+func wrappedMigrate(ctx context.Context, x *xorm.Engine) error {
currentEngine = x
return migrations.Migrate(x)
}
@@ -259,13 +259,13 @@ func doMigrationTest(t *testing.T, version string) {
setting.InitSQLLoggersForCli(log.INFO)
- err := db.InitEngineWithMigration(context.Background(), wrappedMigrate)
+ err := db.InitEngineWithMigration(t.Context(), wrappedMigrate)
assert.NoError(t, err)
currentEngine.Close()
beans, _ := db.NamesToBean()
- err = db.InitEngineWithMigration(context.Background(), func(x *xorm.Engine) error {
+ err = db.InitEngineWithMigration(t.Context(), func(ctx context.Context, x *xorm.Engine) error {
currentEngine = x
return migrate_base.RecreateTables(beans...)(x)
})
@@ -273,7 +273,7 @@ func doMigrationTest(t *testing.T, version string) {
currentEngine.Close()
// We do this a second time to ensure that there is not a problem with retained indices
- err = db.InitEngineWithMigration(context.Background(), func(x *xorm.Engine) error {
+ err = db.InitEngineWithMigration(t.Context(), func(ctx context.Context, x *xorm.Engine) error {
currentEngine = x
return migrate_base.RecreateTables(beans...)(x)
})
diff --git a/tests/integration/mirror_pull_test.go b/tests/integration/mirror_pull_test.go
index 77050c4bbc..c33b2eb04d 100644
--- a/tests/integration/mirror_pull_test.go
+++ b/tests/integration/mirror_pull_test.go
@@ -4,11 +4,12 @@
package integration
import (
- "context"
+ "slices"
"testing"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
@@ -20,11 +21,13 @@ import (
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func TestMirrorPull(t *testing.T) {
defer tests.PrepareTestEnv(t)()
+ ctx := t.Context()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
repoPath := repo_model.RepoPath(user.Name, repo.Name)
@@ -36,24 +39,28 @@ func TestMirrorPull(t *testing.T) {
Mirror: true,
CloneAddr: repoPath,
Wiki: true,
- Releases: false,
+ Releases: true,
}
- mirrorRepo, err := repo_service.CreateRepositoryDirectly(db.DefaultContext, user, user, repo_service.CreateRepoOptions{
+ mirrorRepo, err := repo_service.CreateRepositoryDirectly(ctx, user, user, repo_service.CreateRepoOptions{
Name: opts.RepoName,
Description: opts.Description,
IsPrivate: opts.Private,
IsMirror: opts.Mirror,
Status: repo_model.RepositoryBeingMigrated,
- })
+ }, false)
assert.NoError(t, err)
assert.True(t, mirrorRepo.IsMirror, "expected pull-mirror repo to be marked as a mirror immediately after its creation")
- ctx := context.Background()
-
- mirror, err := repo_service.MigrateRepositoryGitData(ctx, user, mirrorRepo, opts, nil)
+ mirrorRepo, err = repo_service.MigrateRepositoryGitData(ctx, user, mirrorRepo, opts, nil)
assert.NoError(t, err)
+ // these units should have been enabled
+ mirrorRepo.Units = nil
+ require.NoError(t, mirrorRepo.LoadUnits(ctx))
+ assert.True(t, slices.ContainsFunc(mirrorRepo.Units, func(u *repo_model.RepoUnit) bool { return u.Type == unit.TypeReleases }))
+ assert.True(t, slices.ContainsFunc(mirrorRepo.Units, func(u *repo_model.RepoUnit) bool { return u.Type == unit.TypeWiki }))
+
gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo)
assert.NoError(t, err)
defer gitRepo.Close()
@@ -61,10 +68,11 @@ func TestMirrorPull(t *testing.T) {
findOptions := repo_model.FindReleasesOptions{
IncludeDrafts: true,
IncludeTags: true,
- RepoID: mirror.ID,
+ RepoID: mirrorRepo.ID,
}
initCount, err := db.Count[repo_model.Release](db.DefaultContext, findOptions)
assert.NoError(t, err)
+ assert.Zero(t, initCount) // no sync yet, so even though there is a tag in source repo, the mirror's release table is still empty
assert.NoError(t, release_service.CreateRelease(gitRepo, &repo_model.Release{
RepoID: repo.ID,
@@ -80,24 +88,27 @@ func TestMirrorPull(t *testing.T) {
IsTag: true,
}, nil, ""))
- _, err = repo_model.GetMirrorByRepoID(ctx, mirror.ID)
+ _, err = repo_model.GetMirrorByRepoID(ctx, mirrorRepo.ID)
assert.NoError(t, err)
- ok := mirror_service.SyncPullMirror(ctx, mirror.ID)
+ ok := mirror_service.SyncPullMirror(ctx, mirrorRepo.ID)
assert.True(t, ok)
+ // actually there is a tag in the source repo, so after "sync", that tag will also come into the mirror
+ initCount++
+
count, err := db.Count[repo_model.Release](db.DefaultContext, findOptions)
assert.NoError(t, err)
- assert.EqualValues(t, initCount+1, count)
+ assert.Equal(t, initCount+1, count)
release, err := repo_model.GetRelease(db.DefaultContext, repo.ID, "v0.2")
assert.NoError(t, err)
assert.NoError(t, release_service.DeleteReleaseByID(ctx, repo, release, user, true))
- ok = mirror_service.SyncPullMirror(ctx, mirror.ID)
+ ok = mirror_service.SyncPullMirror(ctx, mirrorRepo.ID)
assert.True(t, ok)
count, err = db.Count[repo_model.Release](db.DefaultContext, findOptions)
assert.NoError(t, err)
- assert.EqualValues(t, initCount, count)
+ assert.Equal(t, initCount, count)
}
diff --git a/tests/integration/mirror_push_test.go b/tests/integration/mirror_push_test.go
index 0dd8919bff..9b6d4c4017 100644
--- a/tests/integration/mirror_push_test.go
+++ b/tests/integration/mirror_push_test.go
@@ -4,12 +4,10 @@
package integration
import (
- "context"
"fmt"
"net/http"
"net/url"
"strconv"
- "strings"
"testing"
"time"
@@ -20,7 +18,6 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/setting"
- gitea_context "code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/migrations"
mirror_service "code.gitea.io/gitea/services/mirror"
repo_service "code.gitea.io/gitea/services/repository"
@@ -43,7 +40,7 @@ func testMirrorPush(t *testing.T, u *url.URL) {
mirrorRepo, err := repo_service.CreateRepositoryDirectly(db.DefaultContext, user, user, repo_service.CreateRepoOptions{
Name: "test-push-mirror",
- })
+ }, true)
assert.NoError(t, err)
session := loginUser(t, user.Name)
@@ -55,7 +52,7 @@ func testMirrorPush(t *testing.T, u *url.URL) {
assert.NoError(t, err)
assert.Len(t, mirrors, 1)
- ok := mirror_service.SyncPushMirror(context.Background(), mirrors[0].ID)
+ ok := mirror_service.SyncPushMirror(t.Context(), mirrors[0].ID)
assert.True(t, ok)
srcGitRepo, err := gitrepo.OpenRepository(git.DefaultContext, srcRepo)
@@ -92,9 +89,8 @@ func testCreatePushMirror(t *testing.T, session *TestSession, owner, repo, addre
})
session.MakeRequest(t, req, http.StatusSeeOther)
- flashCookie := session.GetCookie(gitea_context.CookieNameFlash)
- assert.NotNil(t, flashCookie)
- assert.Contains(t, flashCookie.Value, "success")
+ flashMsg := session.GetCookieFlashMessage()
+ assert.NotEmpty(t, flashMsg.SuccessMsg)
}
func doRemovePushMirror(t *testing.T, session *TestSession, owner, repo string, pushMirrorID int64) bool {
@@ -104,8 +100,8 @@ func doRemovePushMirror(t *testing.T, session *TestSession, owner, repo string,
"push_mirror_id": strconv.FormatInt(pushMirrorID, 10),
})
resp := session.MakeRequest(t, req, NoExpectedStatus)
- flashCookie := session.GetCookie(gitea_context.CookieNameFlash)
- return resp.Code == http.StatusSeeOther && flashCookie != nil && strings.Contains(flashCookie.Value, "success")
+ flashMsg := session.GetCookieFlashMessage()
+ return resp.Code == http.StatusSeeOther && assert.NotEmpty(t, flashMsg.SuccessMsg)
}
func doUpdatePushMirror(t *testing.T, session *TestSession, owner, repo string, pushMirrorID int64, interval string) bool {
@@ -132,18 +128,18 @@ func TestRepoSettingPushMirrorUpdate(t *testing.T) {
pushMirrors, cnt, err := repo_model.GetPushMirrorsByRepoID(db.DefaultContext, repo2.ID, db.ListOptions{})
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
- assert.EqualValues(t, 24*time.Hour, pushMirrors[0].Interval)
+ assert.Equal(t, 24*time.Hour, pushMirrors[0].Interval)
repo2PushMirrorID := pushMirrors[0].ID
// update repo2 push mirror
assert.True(t, doUpdatePushMirror(t, session, "user2", "repo2", repo2PushMirrorID, "10m0s"))
pushMirror := unittest.AssertExistsAndLoadBean(t, &repo_model.PushMirror{ID: repo2PushMirrorID})
- assert.EqualValues(t, 10*time.Minute, pushMirror.Interval)
+ assert.Equal(t, 10*time.Minute, pushMirror.Interval)
// avoid updating repo2 push mirror from repo1
assert.False(t, doUpdatePushMirror(t, session, "user2", "repo1", repo2PushMirrorID, "20m0s"))
pushMirror = unittest.AssertExistsAndLoadBean(t, &repo_model.PushMirror{ID: repo2PushMirrorID})
- assert.EqualValues(t, 10*time.Minute, pushMirror.Interval) // not changed
+ assert.Equal(t, 10*time.Minute, pushMirror.Interval) // not changed
// avoid deleting repo2 push mirror from repo1
assert.False(t, doRemovePushMirror(t, session, "user2", "repo1", repo2PushMirrorID))
diff --git a/tests/integration/nonascii_branches_test.go b/tests/integration/nonascii_branches_test.go
index e5934a148d..cc71acf002 100644
--- a/tests/integration/nonascii_branches_test.go
+++ b/tests/integration/nonascii_branches_test.go
@@ -12,7 +12,7 @@ import (
"code.gitea.io/gitea/tests"
- "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func setDefaultBranch(t *testing.T, session *TestSession, user, repo, branch string) {
@@ -46,21 +46,21 @@ func TestNonAsciiBranches(t *testing.T) {
{
from: "master/badfile",
to: "branch/master/badfile",
- status: http.StatusNotFound, // it does not exists
+ status: http.StatusNotFound, // it does not exist
},
{
from: "ГлавнаяВетка",
- to: "branch/%D0%93%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F%D0%92%D0%B5%D1%82%D0%BA%D0%B0",
+ to: "branch/%d0%93%d0%bb%d0%b0%d0%b2%d0%bd%d0%b0%d1%8f%d0%92%d0%b5%d1%82%d0%ba%d0%b0",
status: http.StatusOK,
},
{
from: "а/б/в",
- to: "branch/%D0%B0/%D0%B1/%D0%B2",
+ to: "branch/%d0%b0/%d0%b1/%d0%b2",
status: http.StatusOK,
},
{
from: "Grüßen/README.md",
- to: "branch/Gr%C3%BC%C3%9Fen/README.md",
+ to: "branch/Gr%c3%bc%c3%9fen/README.md",
status: http.StatusOK,
},
{
@@ -70,7 +70,7 @@ func TestNonAsciiBranches(t *testing.T) {
},
{
from: "Plus+Is+Not+Space/Файл.md",
- to: "branch/Plus+Is+Not+Space/%D0%A4%D0%B0%D0%B9%D0%BB.md",
+ to: "branch/Plus+Is+Not+Space/%d0%a4%d0%b0%d0%b9%d0%bb.md",
status: http.StatusOK,
},
{
@@ -80,29 +80,29 @@ func TestNonAsciiBranches(t *testing.T) {
},
{
from: "ブランチ",
- to: "branch/%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81",
+ to: "branch/%e3%83%96%e3%83%a9%e3%83%b3%e3%83%81",
status: http.StatusOK,
},
// Tags
{
from: "Тэг",
- to: "tag/%D0%A2%D1%8D%D0%B3",
+ to: "tag/%d0%a2%d1%8d%d0%b3",
status: http.StatusOK,
},
{
from: "Ё/人",
- to: "tag/%D0%81/%E4%BA%BA",
+ to: "tag/%d0%81/%e4%ba%ba",
status: http.StatusOK,
},
{
from: "タグ",
- to: "tag/%E3%82%BF%E3%82%B0",
+ to: "tag/%e3%82%bf%e3%82%b0",
status: http.StatusOK,
},
{
from: "タグ/ファイル.md",
- to: "tag/%E3%82%BF%E3%82%B0/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.md",
+ to: "tag/%e3%82%bf%e3%82%b0/%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab.md",
status: http.StatusOK,
},
@@ -114,12 +114,12 @@ func TestNonAsciiBranches(t *testing.T) {
},
{
from: "Файл.md",
- to: "branch/Plus+Is+Not+Space/%D0%A4%D0%B0%D0%B9%D0%BB.md",
+ to: "branch/Plus+Is+Not+Space/%d0%a4%d0%b0%d0%b9%d0%bb.md",
status: http.StatusOK,
},
{
from: "ファイル.md",
- to: "branch/Plus+Is+Not+Space/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.md",
+ to: "branch/Plus+Is+Not+Space/%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab.md",
status: http.StatusNotFound, // it's not on default branch
},
@@ -131,7 +131,7 @@ func TestNonAsciiBranches(t *testing.T) {
},
{
from: "%E3%82%BF%E3%82%b0",
- to: "tag/%E3%82%BF%E3%82%B0",
+ to: "tag/%E3%82%BF%E3%82%b0",
status: http.StatusOK,
},
{
@@ -141,12 +141,12 @@ func TestNonAsciiBranches(t *testing.T) {
},
{
from: "%D0%81%2F%E4%BA%BA",
- to: "tag/%D0%81/%E4%BA%BA",
+ to: "tag/%D0%81%2F%E4%BA%BA",
status: http.StatusOK,
},
{
from: "Ё%2F%E4%BA%BA",
- to: "tag/%D0%81/%E4%BA%BA",
+ to: "tag/%d0%81%2F%E4%BA%BA",
status: http.StatusOK,
},
{
@@ -199,14 +199,10 @@ func TestNonAsciiBranches(t *testing.T) {
t.Run(test.from, func(t *testing.T) {
req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/src/%s", user, repo, test.from))
resp := session.MakeRequest(t, req, http.StatusSeeOther)
- if resp.Code != http.StatusSeeOther {
- return
- }
+ require.Equal(t, http.StatusSeeOther, resp.Code)
redirectLocation := resp.Header().Get("Location")
- if !assert.Equal(t, fmt.Sprintf("/%s/%s/src/%s", user, repo, test.to), redirectLocation) {
- return
- }
+ require.Equal(t, fmt.Sprintf("/%s/%s/src/%s", user, repo, test.to), redirectLocation)
req = NewRequest(t, "GET", redirectLocation)
session.MakeRequest(t, req, test.status)
diff --git a/tests/integration/oauth_test.go b/tests/integration/oauth_test.go
index d6f1ba33ec..a2247801f7 100644
--- a/tests/integration/oauth_test.go
+++ b/tests/integration/oauth_test.go
@@ -9,9 +9,11 @@ import (
"fmt"
"io"
"net/http"
+ "net/http/httptest"
"strings"
"testing"
+ asymkey_model "code.gitea.io/gitea/models/asymkey"
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
@@ -19,31 +21,45 @@ import (
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
- oauth2_provider "code.gitea.io/gitea/services/oauth2_provider"
+ "code.gitea.io/gitea/modules/test"
+ "code.gitea.io/gitea/modules/util"
+ "code.gitea.io/gitea/services/auth/source/oauth2"
+ "code.gitea.io/gitea/services/oauth2_provider"
"code.gitea.io/gitea/tests"
+ "github.com/markbates/goth"
+ "github.com/markbates/goth/gothic"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
-func TestAuthorizeNoClientID(t *testing.T) {
+func TestOAuth2Provider(t *testing.T) {
defer tests.PrepareTestEnv(t)()
+
+ t.Run("AuthorizeNoClientID", testAuthorizeNoClientID)
+ t.Run("AuthorizeUnregisteredRedirect", testAuthorizeUnregisteredRedirect)
+ t.Run("AuthorizeUnsupportedResponseType", testAuthorizeUnsupportedResponseType)
+ t.Run("AuthorizeUnsupportedCodeChallengeMethod", testAuthorizeUnsupportedCodeChallengeMethod)
+ t.Run("AuthorizeLoginRedirect", testAuthorizeLoginRedirect)
+
+ t.Run("OAuth2WellKnown", testOAuth2WellKnown)
+}
+
+func testAuthorizeNoClientID(t *testing.T) {
req := NewRequest(t, "GET", "/login/oauth/authorize")
ctx := loginUser(t, "user2")
resp := ctx.MakeRequest(t, req, http.StatusBadRequest)
assert.Contains(t, resp.Body.String(), "Client ID not registered")
}
-func TestAuthorizeUnregisteredRedirect(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
+func testAuthorizeUnregisteredRedirect(t *testing.T) {
req := NewRequest(t, "GET", "/login/oauth/authorize?client_id=da7da3ba-9a13-4167-856f-3899de0b0138&redirect_uri=UNREGISTERED&response_type=code&state=thestate")
ctx := loginUser(t, "user1")
resp := ctx.MakeRequest(t, req, http.StatusBadRequest)
assert.Contains(t, resp.Body.String(), "Unregistered Redirect URI")
}
-func TestAuthorizeUnsupportedResponseType(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
+func testAuthorizeUnsupportedResponseType(t *testing.T) {
req := NewRequest(t, "GET", "/login/oauth/authorize?client_id=da7da3ba-9a13-4167-856f-3899de0b0138&redirect_uri=a&response_type=UNEXPECTED&state=thestate")
ctx := loginUser(t, "user1")
resp := ctx.MakeRequest(t, req, http.StatusSeeOther)
@@ -53,8 +69,7 @@ func TestAuthorizeUnsupportedResponseType(t *testing.T) {
assert.Equal(t, "Only code response type is supported.", u.Query().Get("error_description"))
}
-func TestAuthorizeUnsupportedCodeChallengeMethod(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
+func testAuthorizeUnsupportedCodeChallengeMethod(t *testing.T) {
req := NewRequest(t, "GET", "/login/oauth/authorize?client_id=da7da3ba-9a13-4167-856f-3899de0b0138&redirect_uri=a&response_type=code&state=thestate&code_challenge_method=UNEXPECTED")
ctx := loginUser(t, "user1")
resp := ctx.MakeRequest(t, req, http.StatusSeeOther)
@@ -64,8 +79,7 @@ func TestAuthorizeUnsupportedCodeChallengeMethod(t *testing.T) {
assert.Equal(t, "unsupported code challenge method", u.Query().Get("error_description"))
}
-func TestAuthorizeLoginRedirect(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
+func testAuthorizeLoginRedirect(t *testing.T) {
req := NewRequest(t, "GET", "/login/oauth/authorize")
assert.Contains(t, MakeRequest(t, req, http.StatusSeeOther).Body.String(), "/user/login")
}
@@ -77,7 +91,7 @@ func TestAuthorizeShow(t *testing.T) {
resp := ctx.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
- htmlDoc.AssertElement(t, "#authorize-app", true)
+ AssertHTMLElement(t, htmlDoc, "#authorize-app", true)
htmlDoc.GetCSRF()
}
@@ -691,10 +705,6 @@ func TestOAuth_GrantScopesReadRepositoryFailOrganization(t *testing.T) {
FullRepoName: "user2/commitsonpr",
Private: false,
},
- {
- FullRepoName: "user2/test_commit_revert",
- Private: true,
- },
}
assert.Equal(t, reposExpected, reposCaptured)
@@ -907,3 +917,127 @@ func TestOAuth_GrantScopesClaimAllGroups(t *testing.T) {
assert.Contains(t, userinfoParsed.Groups, group)
}
}
+
+func testOAuth2WellKnown(t *testing.T) {
+ urlOpenidConfiguration := "/.well-known/openid-configuration"
+
+ defer test.MockVariableValue(&setting.AppURL, "https://try.gitea.io/")()
+ req := NewRequest(t, "GET", urlOpenidConfiguration)
+ resp := MakeRequest(t, req, http.StatusOK)
+ var respMap map[string]any
+ DecodeJSON(t, resp, &respMap)
+ assert.Equal(t, "https://try.gitea.io", respMap["issuer"])
+ assert.Equal(t, "https://try.gitea.io/login/oauth/authorize", respMap["authorization_endpoint"])
+ assert.Equal(t, "https://try.gitea.io/login/oauth/access_token", respMap["token_endpoint"])
+ assert.Equal(t, "https://try.gitea.io/login/oauth/keys", respMap["jwks_uri"])
+ assert.Equal(t, "https://try.gitea.io/login/oauth/userinfo", respMap["userinfo_endpoint"])
+ assert.Equal(t, "https://try.gitea.io/login/oauth/introspect", respMap["introspection_endpoint"])
+ assert.Equal(t, []any{"RS256"}, respMap["id_token_signing_alg_values_supported"])
+
+ defer test.MockVariableValue(&setting.OAuth2.Enabled, false)()
+ MakeRequest(t, NewRequest(t, "GET", urlOpenidConfiguration), http.StatusNotFound)
+}
+
+func addOAuth2Source(t *testing.T, authName string, cfg oauth2.Source) {
+ cfg.Provider = util.IfZero(cfg.Provider, "gitea")
+ err := auth_model.CreateSource(db.DefaultContext, &auth_model.Source{
+ Type: auth_model.OAuth2,
+ Name: authName,
+ IsActive: true,
+ Cfg: &cfg,
+ })
+ require.NoError(t, err)
+}
+
+func TestSignInOauthCallbackSyncSSHKeys(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+
+ var mockServer *httptest.Server
+ mockServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ switch r.URL.Path {
+ case "/.well-known/openid-configuration":
+ _, _ = w.Write([]byte(`{
+ "issuer": "` + mockServer.URL + `",
+ "authorization_endpoint": "` + mockServer.URL + `/authorize",
+ "token_endpoint": "` + mockServer.URL + `/token",
+ "userinfo_endpoint": "` + mockServer.URL + `/userinfo"
+ }`))
+ default:
+ http.NotFound(w, r)
+ }
+ }))
+ defer mockServer.Close()
+
+ ctx := t.Context()
+ oauth2Source := oauth2.Source{
+ Provider: "openidConnect",
+ ClientID: "test-client-id",
+ SSHPublicKeyClaimName: "sshpubkey",
+ FullNameClaimName: "name",
+ OpenIDConnectAutoDiscoveryURL: mockServer.URL + "/.well-known/openid-configuration",
+ }
+ addOAuth2Source(t, "test-oidc-source", oauth2Source)
+ authSource, err := auth_model.GetActiveOAuth2SourceByAuthName(ctx, "test-oidc-source")
+ require.NoError(t, err)
+
+ sshKey1 := "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICV0MGX/W9IvLA4FXpIuUcdDcbj5KX4syHgsTy7soVgf"
+ sshKey2 := "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIE7kM1R02+4ertDKGKEDcKG0s+2vyDDcIvceJ0Gqv5f1AAAABHNzaDo="
+ sshKey3 := "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEHjnNEfE88W1pvBLdV3otv28x760gdmPao3lVD5uAt9"
+ cases := []struct {
+ testName string
+ mockFullName string
+ mockRawData map[string]any
+ expectedSSHPubKeys []string
+ }{
+ {
+ testName: "Login1",
+ mockFullName: "FullName1",
+ mockRawData: map[string]any{"sshpubkey": []any{sshKey1 + " any-comment"}},
+ expectedSSHPubKeys: []string{sshKey1},
+ },
+ {
+ testName: "Login2",
+ mockFullName: "FullName2",
+ mockRawData: map[string]any{"sshpubkey": []any{sshKey2 + " any-comment", sshKey3}},
+ expectedSSHPubKeys: []string{sshKey2, sshKey3},
+ },
+ {
+ testName: "Login3",
+ mockFullName: "FullName3",
+ mockRawData: map[string]any{},
+ expectedSSHPubKeys: []string{},
+ },
+ }
+
+ session := emptyTestSession(t)
+ for _, c := range cases {
+ t.Run(c.testName, func(t *testing.T) {
+ defer test.MockVariableValue(&setting.OAuth2Client.Username, "")()
+ defer test.MockVariableValue(&setting.OAuth2Client.EnableAutoRegistration, true)()
+ defer test.MockVariableValue(&gothic.CompleteUserAuth, func(res http.ResponseWriter, req *http.Request) (goth.User, error) {
+ return goth.User{
+ Provider: authSource.Cfg.(*oauth2.Source).Provider,
+ UserID: "oidc-userid",
+ Email: "oidc-email@example.com",
+ RawData: c.mockRawData,
+ Name: c.mockFullName,
+ }, nil
+ })()
+ req := NewRequest(t, "GET", "/user/oauth2/test-oidc-source/callback?code=XYZ&state=XYZ")
+ session.MakeRequest(t, req, http.StatusSeeOther)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "oidc-userid"})
+ keys, _, err := db.FindAndCount[asymkey_model.PublicKey](ctx, asymkey_model.FindPublicKeyOptions{
+ ListOptions: db.ListOptionsAll,
+ OwnerID: user.ID,
+ LoginSourceID: authSource.ID,
+ })
+ require.NoError(t, err)
+ var sshPubKeys []string
+ for _, key := range keys {
+ sshPubKeys = append(sshPubKeys, key.Content)
+ }
+ assert.ElementsMatch(t, c.expectedSSHPubKeys, sshPubKeys)
+ assert.Equal(t, c.mockFullName, user.FullName)
+ })
+ }
+}
diff --git a/tests/integration/org_count_test.go b/tests/integration/org_count_test.go
index 8a33c218be..c48008e627 100644
--- a/tests/integration/org_count_test.go
+++ b/tests/integration/org_count_test.go
@@ -4,7 +4,6 @@
package integration
import (
- "net/url"
"strings"
"testing"
@@ -14,15 +13,17 @@ import (
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
)
func TestOrgCounts(t *testing.T) {
- onGiteaRun(t, testOrgCounts)
+ defer tests.PrepareTestEnv(t)()
+ testOrgCounts(t)
}
-func testOrgCounts(t *testing.T, u *url.URL) {
+func testOrgCounts(t *testing.T) {
orgOwner := "user2"
orgName := "testOrg"
orgCollaborator := "user4"
@@ -119,8 +120,8 @@ func doCheckOrgCounts(username string, orgCounts map[string]int, strict bool, ca
})
orgs, err := db.Find[organization.Organization](db.DefaultContext, organization.FindOrgOptions{
- UserID: user.ID,
- IncludePrivate: true,
+ UserID: user.ID,
+ IncludeVisibility: api.VisibleTypePrivate,
})
assert.NoError(t, err)
diff --git a/tests/integration/org_profile_test.go b/tests/integration/org_profile_test.go
new file mode 100644
index 0000000000..73cafd85c2
--- /dev/null
+++ b/tests/integration/org_profile_test.go
@@ -0,0 +1,132 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package integration
+
+import (
+ "encoding/base64"
+ "fmt"
+ "net/http"
+ "net/url"
+ "testing"
+ "time"
+
+ auth_model "code.gitea.io/gitea/models/auth"
+ api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/util"
+ "code.gitea.io/gitea/routers/web/shared/user"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func getCreateProfileReadmeFileOptions(content string) api.CreateFileOptions {
+ contentEncoded := base64.StdEncoding.EncodeToString([]byte(content))
+ return api.CreateFileOptions{
+ FileOptions: api.FileOptions{
+ BranchName: "main",
+ NewBranchName: "main",
+ Message: "create the profile README.md",
+ Dates: api.CommitDateOptions{
+ Author: time.Unix(946684810, 0),
+ Committer: time.Unix(978307190, 0),
+ },
+ },
+ ContentBase64: contentEncoded,
+ }
+}
+
+func createTestProfile(t *testing.T, orgName, profileRepoName, readmeContent string) {
+ isPrivate := profileRepoName == user.RepoNameProfilePrivate
+
+ ctx := NewAPITestContext(t, "user1", profileRepoName, auth_model.AccessTokenScopeAll)
+ session := loginUser(t, "user1")
+ tokenAdmin := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll)
+
+ // create repo
+ doAPICreateOrganizationRepository(ctx, orgName, &api.CreateRepoOption{Name: profileRepoName, Private: isPrivate})(t)
+
+ // create readme
+ createFileOptions := getCreateProfileReadmeFileOptions(readmeContent)
+ req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", orgName, profileRepoName, "README.md"), &createFileOptions).
+ AddTokenAuth(tokenAdmin)
+ MakeRequest(t, req, http.StatusCreated)
+}
+
+func TestOrgProfile(t *testing.T) {
+ onGiteaRun(t, testOrgProfile)
+}
+
+func testOrgProfile(t *testing.T, u *url.URL) {
+ const contentPublicReadme = "Public Readme Content"
+ const contentPrivateReadme = "Private Readme Content"
+ // HTML: "#org-home-view-as-dropdown" (indicate whether the view as dropdown menu is present)
+
+ // PART 1: Test Both Private and Public
+ createTestProfile(t, "org3", user.RepoNameProfile, contentPublicReadme)
+ createTestProfile(t, "org3", user.RepoNameProfilePrivate, contentPrivateReadme)
+
+ // Anonymous User
+ req := NewRequest(t, "GET", "org3")
+ resp := MakeRequest(t, req, http.StatusOK)
+ bodyString := util.UnsafeBytesToString(resp.Body.Bytes())
+ assert.Contains(t, bodyString, contentPublicReadme)
+ assert.NotContains(t, bodyString, `id="org-home-view-as-dropdown"`)
+
+ // Logged in but not member
+ session := loginUser(t, "user24")
+ req = NewRequest(t, "GET", "org3")
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ bodyString = util.UnsafeBytesToString(resp.Body.Bytes())
+ assert.Contains(t, bodyString, contentPublicReadme)
+ assert.NotContains(t, bodyString, `id="org-home-view-as-dropdown"`)
+
+ // Site Admin
+ session = loginUser(t, "user1")
+ req = NewRequest(t, "GET", "/org3")
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ bodyString = util.UnsafeBytesToString(resp.Body.Bytes())
+ assert.Contains(t, bodyString, contentPrivateReadme) // as an org member, default to show the private profile
+ assert.Contains(t, bodyString, `id="org-home-view-as-dropdown"`)
+
+ req = NewRequest(t, "GET", "/org3?view_as=member")
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ bodyString = util.UnsafeBytesToString(resp.Body.Bytes())
+ assert.Contains(t, bodyString, contentPrivateReadme)
+ assert.Contains(t, bodyString, `id="org-home-view-as-dropdown"`)
+
+ req = NewRequest(t, "GET", "/org3?view_as=public")
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ bodyString = util.UnsafeBytesToString(resp.Body.Bytes())
+ assert.Contains(t, bodyString, contentPublicReadme)
+ assert.Contains(t, bodyString, `id="org-home-view-as-dropdown"`)
+
+ // PART 2: Each org has either one of private pr public profile
+ createTestProfile(t, "org41", user.RepoNameProfile, contentPublicReadme)
+ createTestProfile(t, "org42", user.RepoNameProfilePrivate, contentPrivateReadme)
+
+ // Anonymous User
+ req = NewRequest(t, "GET", "/org41")
+ resp = MakeRequest(t, req, http.StatusOK)
+ bodyString = util.UnsafeBytesToString(resp.Body.Bytes())
+ assert.Contains(t, bodyString, contentPublicReadme)
+ assert.NotContains(t, bodyString, `id="org-home-view-as-dropdown"`)
+
+ req = NewRequest(t, "GET", "/org42")
+ resp = MakeRequest(t, req, http.StatusOK)
+ bodyString = util.UnsafeBytesToString(resp.Body.Bytes())
+ assert.NotContains(t, bodyString, contentPrivateReadme)
+ assert.NotContains(t, bodyString, `id="org-home-view-as-dropdown"`)
+
+ // Site Admin
+ req = NewRequest(t, "GET", "/org41")
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ bodyString = util.UnsafeBytesToString(resp.Body.Bytes())
+ assert.Contains(t, bodyString, contentPublicReadme)
+ assert.NotContains(t, bodyString, `id="org-home-view-as-dropdown"`)
+
+ req = NewRequest(t, "GET", "/org42")
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ bodyString = util.UnsafeBytesToString(resp.Body.Bytes())
+ assert.Contains(t, bodyString, contentPrivateReadme)
+ assert.NotContains(t, bodyString, `id="org-home-view-as-dropdown"`)
+}
diff --git a/tests/integration/org_team_invite_test.go b/tests/integration/org_team_invite_test.go
index 274fde4085..7444980ea8 100644
--- a/tests/integration/org_team_invite_test.go
+++ b/tests/integration/org_team_invite_test.go
@@ -58,7 +58,7 @@ func TestOrgTeamEmailInvite(t *testing.T) {
session = loginUser(t, user.Name)
// join the team
- inviteURL := fmt.Sprintf("/org/invite/%s", invites[0].Token)
+ inviteURL := "/org/invite/" + invites[0].Token
csrf = GetUserCSRFToken(t, session)
req = NewRequestWithValues(t, "POST", inviteURL, map[string]string{
"_csrf": csrf,
@@ -108,8 +108,8 @@ func TestOrgTeamEmailInviteRedirectsExistingUser(t *testing.T) {
assert.Len(t, invites, 1)
// accept the invite
- inviteURL := fmt.Sprintf("/org/invite/%s", invites[0].Token)
- req = NewRequest(t, "GET", fmt.Sprintf("/user/login?redirect_to=%s", url.QueryEscape(inviteURL)))
+ inviteURL := "/org/invite/" + invites[0].Token
+ req = NewRequest(t, "GET", "/user/login?redirect_to="+url.QueryEscape(inviteURL))
resp = MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
@@ -179,8 +179,8 @@ func TestOrgTeamEmailInviteRedirectsNewUser(t *testing.T) {
assert.Len(t, invites, 1)
// accept the invite
- inviteURL := fmt.Sprintf("/org/invite/%s", invites[0].Token)
- req = NewRequest(t, "GET", fmt.Sprintf("/user/sign_up?redirect_to=%s", url.QueryEscape(inviteURL)))
+ inviteURL := "/org/invite/" + invites[0].Token
+ req = NewRequest(t, "GET", "/user/sign_up?redirect_to="+url.QueryEscape(inviteURL))
resp = MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
@@ -260,8 +260,8 @@ func TestOrgTeamEmailInviteRedirectsNewUserWithActivation(t *testing.T) {
// new user: accept the invite
session = emptyTestSession(t)
- inviteURL := fmt.Sprintf("/org/invite/%s", invites[0].Token)
- req = NewRequest(t, "GET", fmt.Sprintf("/user/sign_up?redirect_to=%s", url.QueryEscape(inviteURL)))
+ inviteURL := "/org/invite/" + invites[0].Token
+ req = NewRequest(t, "GET", "/user/sign_up?redirect_to="+url.QueryEscape(inviteURL))
session.MakeRequest(t, req, http.StatusOK)
req = NewRequestWithValues(t, "POST", "/user/sign_up", map[string]string{
"user_name": "doesnotexist",
@@ -274,7 +274,8 @@ func TestOrgTeamEmailInviteRedirectsNewUserWithActivation(t *testing.T) {
user, err := user_model.GetUserByName(db.DefaultContext, "doesnotexist")
assert.NoError(t, err)
- activateURL := fmt.Sprintf("/user/activate?code=%s", user.GenerateEmailActivateCode("doesnotexist@example.com"))
+ activationCode := user_model.GenerateUserTimeLimitCode(&user_model.TimeLimitCodeOptions{Purpose: user_model.TimeLimitCodeActivateAccount}, user)
+ activateURL := "/user/activate?code=" + activationCode
req = NewRequestWithValues(t, "POST", activateURL, map[string]string{
"password": "examplePassword!1",
})
@@ -336,8 +337,8 @@ func TestOrgTeamEmailInviteRedirectsExistingUserWithLogin(t *testing.T) {
session = loginUser(t, "user5")
// accept the invite (note: this uses the sign_up url)
- inviteURL := fmt.Sprintf("/org/invite/%s", invites[0].Token)
- req = NewRequest(t, "GET", fmt.Sprintf("/user/sign_up?redirect_to=%s", url.QueryEscape(inviteURL)))
+ inviteURL := "/org/invite/" + invites[0].Token
+ req = NewRequest(t, "GET", "/user/sign_up?redirect_to="+url.QueryEscape(inviteURL))
resp = session.MakeRequest(t, req, http.StatusSeeOther)
assert.Equal(t, inviteURL, test.RedirectURL(resp))
diff --git a/tests/integration/org_test.go b/tests/integration/org_test.go
index ef4ef2bb9b..3ed7baa5ba 100644
--- a/tests/integration/org_test.go
+++ b/tests/integration/org_test.go
@@ -10,12 +10,17 @@ import (
"testing"
auth_model "code.gitea.io/gitea/models/auth"
+ "code.gitea.io/gitea/models/db"
+ "code.gitea.io/gitea/models/organization"
+ "code.gitea.io/gitea/models/perm"
+ "code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func TestOrgRepos(t *testing.T) {
@@ -40,8 +45,8 @@ func TestOrgRepos(t *testing.T) {
sel := htmlDoc.doc.Find("a.name")
assert.Len(t, repos, len(sel.Nodes))
- for i := 0; i < len(repos); i++ {
- assert.EqualValues(t, repos[i], strings.TrimSpace(sel.Eq(i).Text()))
+ for i := range repos {
+ assert.Equal(t, repos[i], strings.TrimSpace(sel.Eq(i).Text()))
}
}
})
@@ -151,7 +156,7 @@ func TestOrgRestrictedUser(t *testing.T) {
// assert restrictedUser cannot see the org or the public repo
restrictedSession := loginUser(t, restrictedUser)
- req := NewRequest(t, "GET", fmt.Sprintf("/%s", orgName))
+ req := NewRequest(t, "GET", "/"+orgName)
restrictedSession.MakeRequest(t, req, http.StatusNotFound)
req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s", orgName, repoName))
@@ -177,9 +182,9 @@ func TestOrgRestrictedUser(t *testing.T) {
resp := adminSession.MakeRequest(t, req, http.StatusCreated)
DecodeJSON(t, resp, &apiTeam)
checkTeamResponse(t, "CreateTeam_codereader", &apiTeam, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
- teamToCreate.Permission, teamToCreate.Units, nil)
+ "none", teamToCreate.Units, nil)
checkTeamBean(t, apiTeam.ID, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
- teamToCreate.Permission, teamToCreate.Units, nil)
+ "none", teamToCreate.Units, nil)
// teamID := apiTeam.ID
// Now we need to add the restricted user to the team
@@ -188,7 +193,7 @@ func TestOrgRestrictedUser(t *testing.T) {
_ = adminSession.MakeRequest(t, req, http.StatusNoContent)
// Now we need to check if the restrictedUser can access the repo
- req = NewRequest(t, "GET", fmt.Sprintf("/%s", orgName))
+ req = NewRequest(t, "GET", "/"+orgName)
restrictedSession.MakeRequest(t, req, http.StatusOK)
req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s", orgName, repoName))
@@ -217,4 +222,32 @@ func TestTeamSearch(t *testing.T) {
session = loginUser(t, user5.Name)
req = NewRequestf(t, "GET", "/org/%s/teams/-/search?q=%s", org.Name, "team")
session.MakeRequest(t, req, http.StatusNotFound)
+
+ t.Run("SearchWithPermission", func(t *testing.T) {
+ ctx := t.Context()
+ const testOrgID int64 = 500
+ const testRepoID int64 = 2000
+ testTeam := &organization.Team{OrgID: testOrgID, LowerName: "test_team", AccessMode: perm.AccessModeNone}
+ require.NoError(t, db.Insert(ctx, testTeam))
+ require.NoError(t, db.Insert(ctx, &organization.TeamRepo{OrgID: testOrgID, TeamID: testTeam.ID, RepoID: testRepoID}))
+ require.NoError(t, db.Insert(ctx, &organization.TeamUnit{OrgID: testOrgID, TeamID: testTeam.ID, Type: unit.TypeCode, AccessMode: perm.AccessModeRead}))
+ require.NoError(t, db.Insert(ctx, &organization.TeamUnit{OrgID: testOrgID, TeamID: testTeam.ID, Type: unit.TypeIssues, AccessMode: perm.AccessModeWrite}))
+
+ teams, err := organization.GetTeamsWithAccessToAnyRepoUnit(ctx, testOrgID, testRepoID, perm.AccessModeRead, unit.TypeCode, unit.TypeIssues)
+ require.NoError(t, err)
+ assert.Len(t, teams, 1) // can read "code" or "issues"
+
+ teams, err = organization.GetTeamsWithAccessToAnyRepoUnit(ctx, testOrgID, testRepoID, perm.AccessModeWrite, unit.TypeCode)
+ require.NoError(t, err)
+ assert.Empty(t, teams) // cannot write "code"
+
+ teams, err = organization.GetTeamsWithAccessToAnyRepoUnit(ctx, testOrgID, testRepoID, perm.AccessModeWrite, unit.TypeIssues)
+ require.NoError(t, err)
+ assert.Len(t, teams, 1) // can write "issues"
+
+ _, _ = db.GetEngine(ctx).ID(testTeam.ID).Update(&organization.Team{AccessMode: perm.AccessModeWrite})
+ teams, err = organization.GetTeamsWithAccessToAnyRepoUnit(ctx, testOrgID, testRepoID, perm.AccessModeWrite, unit.TypeCode)
+ require.NoError(t, err)
+ assert.Len(t, teams, 1) // team permission is "write", so can write "code"
+ })
}
diff --git a/tests/integration/org_worktime_test.go b/tests/integration/org_worktime_test.go
new file mode 100644
index 0000000000..fb5216be8d
--- /dev/null
+++ b/tests/integration/org_worktime_test.go
@@ -0,0 +1,293 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package integration_test
+
+import (
+ "testing"
+
+ "code.gitea.io/gitea/models/db"
+ "code.gitea.io/gitea/models/organization"
+ "code.gitea.io/gitea/models/unittest"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+// TestTimesByRepos tests TimesByRepos functionality
+func testTimesByRepos(t *testing.T) {
+ kases := []struct {
+ name string
+ unixfrom int64
+ unixto int64
+ orgname int64
+ expected []organization.WorktimeSumByRepos
+ }{
+ {
+ name: "Full sum for org 1",
+ unixfrom: 0,
+ unixto: 9223372036854775807,
+ orgname: 1,
+ expected: []organization.WorktimeSumByRepos(nil),
+ },
+ {
+ name: "Full sum for org 2",
+ unixfrom: 0,
+ unixto: 9223372036854775807,
+ orgname: 2,
+ expected: []organization.WorktimeSumByRepos{
+ {
+ RepoName: "repo1",
+ SumTime: 4083,
+ },
+ {
+ RepoName: "repo2",
+ SumTime: 75,
+ },
+ },
+ },
+ {
+ name: "Simple time bound",
+ unixfrom: 946684801,
+ unixto: 946684802,
+ orgname: 2,
+ expected: []organization.WorktimeSumByRepos{
+ {
+ RepoName: "repo1",
+ SumTime: 3662,
+ },
+ },
+ },
+ {
+ name: "Both times inclusive",
+ unixfrom: 946684801,
+ unixto: 946684801,
+ orgname: 2,
+ expected: []organization.WorktimeSumByRepos{
+ {
+ RepoName: "repo1",
+ SumTime: 3661,
+ },
+ },
+ },
+ {
+ name: "Should ignore deleted",
+ unixfrom: 947688814,
+ unixto: 947688815,
+ orgname: 2,
+ expected: []organization.WorktimeSumByRepos{
+ {
+ RepoName: "repo2",
+ SumTime: 71,
+ },
+ },
+ },
+ }
+
+ // Run test kases
+ for _, kase := range kases {
+ t.Run(kase.name, func(t *testing.T) {
+ org, err := organization.GetOrgByID(db.DefaultContext, kase.orgname)
+ assert.NoError(t, err)
+ results, err := organization.GetWorktimeByRepos(org, kase.unixfrom, kase.unixto)
+ assert.NoError(t, err)
+ assert.Equal(t, kase.expected, results)
+ })
+ }
+}
+
+// TestTimesByMilestones tests TimesByMilestones functionality
+func testTimesByMilestones(t *testing.T) {
+ kases := []struct {
+ name string
+ unixfrom int64
+ unixto int64
+ orgname int64
+ expected []organization.WorktimeSumByMilestones
+ }{
+ {
+ name: "Full sum for org 1",
+ unixfrom: 0,
+ unixto: 9223372036854775807,
+ orgname: 1,
+ expected: []organization.WorktimeSumByMilestones(nil),
+ },
+ {
+ name: "Full sum for org 2",
+ unixfrom: 0,
+ unixto: 9223372036854775807,
+ orgname: 2,
+ expected: []organization.WorktimeSumByMilestones{
+ {
+ RepoName: "repo1",
+ MilestoneName: "",
+ MilestoneID: 0,
+ SumTime: 401,
+ HideRepoName: false,
+ },
+ {
+ RepoName: "repo1",
+ MilestoneName: "milestone1",
+ MilestoneID: 1,
+ SumTime: 3682,
+ HideRepoName: true,
+ },
+ {
+ RepoName: "repo2",
+ MilestoneName: "",
+ MilestoneID: 0,
+ SumTime: 75,
+ HideRepoName: false,
+ },
+ },
+ },
+ {
+ name: "Simple time bound",
+ unixfrom: 946684801,
+ unixto: 946684802,
+ orgname: 2,
+ expected: []organization.WorktimeSumByMilestones{
+ {
+ RepoName: "repo1",
+ MilestoneName: "milestone1",
+ MilestoneID: 1,
+ SumTime: 3662,
+ HideRepoName: false,
+ },
+ },
+ },
+ {
+ name: "Both times inclusive",
+ unixfrom: 946684801,
+ unixto: 946684801,
+ orgname: 2,
+ expected: []organization.WorktimeSumByMilestones{
+ {
+ RepoName: "repo1",
+ MilestoneName: "milestone1",
+ MilestoneID: 1,
+ SumTime: 3661,
+ HideRepoName: false,
+ },
+ },
+ },
+ {
+ name: "Should ignore deleted",
+ unixfrom: 947688814,
+ unixto: 947688815,
+ orgname: 2,
+ expected: []organization.WorktimeSumByMilestones{
+ {
+ RepoName: "repo2",
+ MilestoneName: "",
+ MilestoneID: 0,
+ SumTime: 71,
+ HideRepoName: false,
+ },
+ },
+ },
+ }
+
+ // Run test kases
+ for _, kase := range kases {
+ t.Run(kase.name, func(t *testing.T) {
+ org, err := organization.GetOrgByID(db.DefaultContext, kase.orgname)
+ require.NoError(t, err)
+ results, err := organization.GetWorktimeByMilestones(org, kase.unixfrom, kase.unixto)
+ if assert.NoError(t, err) {
+ assert.Equal(t, kase.expected, results)
+ }
+ })
+ }
+}
+
+// TestTimesByMembers tests TimesByMembers functionality
+func testTimesByMembers(t *testing.T) {
+ kases := []struct {
+ name string
+ unixfrom int64
+ unixto int64
+ orgname int64
+ expected []organization.WorktimeSumByMembers
+ }{
+ {
+ name: "Full sum for org 1",
+ unixfrom: 0,
+ unixto: 9223372036854775807,
+ orgname: 1,
+ expected: []organization.WorktimeSumByMembers(nil),
+ },
+ {
+ // Test case: Sum of times forever in org no. 2
+ name: "Full sum for org 2",
+ unixfrom: 0,
+ unixto: 9223372036854775807,
+ orgname: 2,
+ expected: []organization.WorktimeSumByMembers{
+ {
+ UserName: "user2",
+ SumTime: 3666,
+ },
+ {
+ UserName: "user1",
+ SumTime: 491,
+ },
+ },
+ },
+ {
+ name: "Simple time bound",
+ unixfrom: 946684801,
+ unixto: 946684802,
+ orgname: 2,
+ expected: []organization.WorktimeSumByMembers{
+ {
+ UserName: "user2",
+ SumTime: 3662,
+ },
+ },
+ },
+ {
+ name: "Both times inclusive",
+ unixfrom: 946684801,
+ unixto: 946684801,
+ orgname: 2,
+ expected: []organization.WorktimeSumByMembers{
+ {
+ UserName: "user2",
+ SumTime: 3661,
+ },
+ },
+ },
+ {
+ name: "Should ignore deleted",
+ unixfrom: 947688814,
+ unixto: 947688815,
+ orgname: 2,
+ expected: []organization.WorktimeSumByMembers{
+ {
+ UserName: "user1",
+ SumTime: 71,
+ },
+ },
+ },
+ }
+
+ // Run test kases
+ for _, kase := range kases {
+ t.Run(kase.name, func(t *testing.T) {
+ org, err := organization.GetOrgByID(db.DefaultContext, kase.orgname)
+ assert.NoError(t, err)
+ results, err := organization.GetWorktimeByMembers(org, kase.unixfrom, kase.unixto)
+ assert.NoError(t, err)
+ assert.Equal(t, kase.expected, results)
+ })
+ }
+}
+
+func TestOrgWorktime(t *testing.T) {
+ // we need to run these tests in integration test because there are complex SQL queries
+ assert.NoError(t, unittest.PrepareTestDatabase())
+ t.Run("ByRepos", testTimesByRepos)
+ t.Run("ByMilestones", testTimesByMilestones)
+ t.Run("ByMembers", testTimesByMembers)
+}
diff --git a/tests/integration/project_test.go b/tests/integration/project_test.go
index cdff9aa2fd..43a489d4c4 100644
--- a/tests/integration/project_test.go
+++ b/tests/integration/project_test.go
@@ -47,7 +47,7 @@ func TestMoveRepoProjectColumns(t *testing.T) {
err := project_model.NewProject(db.DefaultContext, &project1)
assert.NoError(t, err)
- for i := 0; i < 3; i++ {
+ for i := range 3 {
err = project_model.NewColumn(db.DefaultContext, &project_model.Column{
Title: fmt.Sprintf("column %d", i+1),
ProjectID: project1.ID,
@@ -78,10 +78,10 @@ func TestMoveRepoProjectColumns(t *testing.T) {
columnsAfter, err := project1.GetColumns(db.DefaultContext)
assert.NoError(t, err)
- assert.Len(t, columns, 3)
- assert.EqualValues(t, columns[1].ID, columnsAfter[0].ID)
- assert.EqualValues(t, columns[2].ID, columnsAfter[1].ID)
- assert.EqualValues(t, columns[0].ID, columnsAfter[2].ID)
+ assert.Len(t, columnsAfter, 3)
+ assert.Equal(t, columns[1].ID, columnsAfter[0].ID)
+ assert.Equal(t, columns[2].ID, columnsAfter[1].ID)
+ assert.Equal(t, columns[0].ID, columnsAfter[2].ID)
assert.NoError(t, project_model.DeleteProjectByID(db.DefaultContext, project1.ID))
}
diff --git a/tests/integration/pull_commit_test.go b/tests/integration/pull_commit_test.go
index 8d98349fd3..9f3b1a9ef5 100644
--- a/tests/integration/pull_commit_test.go
+++ b/tests/integration/pull_commit_test.go
@@ -5,30 +5,37 @@ package integration
import (
"net/http"
- "net/url"
"testing"
pull_service "code.gitea.io/gitea/services/pull"
+ "code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func TestListPullCommits(t *testing.T) {
- onGiteaRun(t, func(t *testing.T, u *url.URL) {
- session := loginUser(t, "user5")
- req := NewRequest(t, "GET", "/user2/repo1/pulls/3/commits/list")
- resp := session.MakeRequest(t, req, http.StatusOK)
-
- var pullCommitList struct {
- Commits []pull_service.CommitInfo `json:"commits"`
- LastReviewCommitSha string `json:"last_review_commit_sha"`
- }
- DecodeJSON(t, resp, &pullCommitList)
-
- if assert.Len(t, pullCommitList.Commits, 2) {
- assert.Equal(t, "985f0301dba5e7b34be866819cd15ad3d8f508ee", pullCommitList.Commits[0].ID)
- assert.Equal(t, "5c050d3b6d2db231ab1f64e324f1b6b9a0b181c2", pullCommitList.Commits[1].ID)
- }
- assert.Equal(t, "4a357436d925b5c974181ff12a994538ddc5a269", pullCommitList.LastReviewCommitSha)
+ defer tests.PrepareTestEnv(t)()
+
+ session := loginUser(t, "user5")
+ req := NewRequest(t, "GET", "/user2/repo1/pulls/3/commits/list")
+ resp := session.MakeRequest(t, req, http.StatusOK)
+
+ var pullCommitList struct {
+ Commits []pull_service.CommitInfo `json:"commits"`
+ LastReviewCommitSha string `json:"last_review_commit_sha"`
+ }
+ DecodeJSON(t, resp, &pullCommitList)
+
+ require.Len(t, pullCommitList.Commits, 2)
+ assert.Equal(t, "985f0301dba5e7b34be866819cd15ad3d8f508ee", pullCommitList.Commits[0].ID)
+ assert.Equal(t, "5c050d3b6d2db231ab1f64e324f1b6b9a0b181c2", pullCommitList.Commits[1].ID)
+ assert.Equal(t, "4a357436d925b5c974181ff12a994538ddc5a269", pullCommitList.LastReviewCommitSha)
+
+ t.Run("CommitBlobExcerpt", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+ req = NewRequest(t, "GET", "/user2/repo1/blob_excerpt/985f0301dba5e7b34be866819cd15ad3d8f508ee?last_left=0&last_right=0&left=2&right=2&left_hunk_size=2&right_hunk_size=2&path=README.md&style=split&direction=up")
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ assert.Contains(t, resp.Body.String(), `<td class="lines-code lines-code-new"><code class="code-inner"># repo1</code>`)
})
}
diff --git a/tests/integration/pull_compare_test.go b/tests/integration/pull_compare_test.go
index 106774aa54..f95a2f1690 100644
--- a/tests/integration/pull_compare_test.go
+++ b/tests/integration/pull_compare_test.go
@@ -13,7 +13,6 @@ import (
issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
- user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/test"
repo_service "code.gitea.io/gitea/services/repository"
"code.gitea.io/gitea/tests"
@@ -24,23 +23,38 @@ import (
func TestPullCompare(t *testing.T) {
defer tests.PrepareTestEnv(t)()
- session := loginUser(t, "user2")
- req := NewRequest(t, "GET", "/user2/repo1/pulls")
- resp := session.MakeRequest(t, req, http.StatusOK)
- htmlDoc := NewHTMLParser(t, resp.Body)
- link, exists := htmlDoc.doc.Find(".new-pr-button").Attr("href")
- assert.True(t, exists, "The template has changed")
+ t.Run("PullsNewRedirect", func(t *testing.T) {
+ req := NewRequest(t, "GET", "/user2/repo1/pulls/new/foo")
+ resp := MakeRequest(t, req, http.StatusSeeOther)
+ redirect := test.RedirectURL(resp)
+ assert.Equal(t, "/user2/repo1/compare/master...foo?expand=1", redirect)
- req = NewRequest(t, "GET", link)
- resp = session.MakeRequest(t, req, http.StatusOK)
- assert.EqualValues(t, http.StatusOK, resp.Code)
+ req = NewRequest(t, "GET", "/user13/repo11/pulls/new/foo")
+ resp = MakeRequest(t, req, http.StatusSeeOther)
+ redirect = test.RedirectURL(resp)
+ assert.Equal(t, "/user12/repo10/compare/master...user13:foo?expand=1", redirect)
+ })
+
+ t.Run("ButtonsExist", func(t *testing.T) {
+ session := loginUser(t, "user2")
+
+ // test the "New PR" button
+ req := NewRequest(t, "GET", "/user2/repo1/pulls")
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ htmlDoc := NewHTMLParser(t, resp.Body)
+ link, exists := htmlDoc.doc.Find(".new-pr-button").Attr("href")
+ assert.True(t, exists, "The template has changed")
+ req = NewRequest(t, "GET", link)
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ assert.Equal(t, http.StatusOK, resp.Code)
- // test the edit button in the PR diff view
- req = NewRequest(t, "GET", "/user2/repo1/pulls/3/files")
- resp = session.MakeRequest(t, req, http.StatusOK)
- doc := NewHTMLParser(t, resp.Body)
- editButtonCount := doc.doc.Find(".diff-file-header-actions a[href*='/_edit/']").Length()
- assert.Positive(t, editButtonCount, "Expected to find a button to edit a file in the PR diff view but there were none")
+ // test the edit button in the PR diff view
+ req = NewRequest(t, "GET", "/user2/repo1/pulls/3/files")
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ doc := NewHTMLParser(t, resp.Body)
+ editButtonCount := doc.doc.Find(".diff-file-header-actions a[href*='/_edit/']").Length()
+ assert.Positive(t, editButtonCount, "Expected to find a button to edit a file in the PR diff view but there were none")
+ })
onGiteaRun(t, func(t *testing.T, u *url.URL) {
defer tests.PrepareTestEnv(t)()
@@ -54,24 +68,23 @@ func TestPullCompare(t *testing.T) {
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"})
issueIndex := unittest.AssertExistsAndLoadBean(t, &issues_model.IssueIndex{GroupID: repo1.ID}, unittest.OrderBy("group_id ASC"))
prFilesURL := fmt.Sprintf("/user2/repo1/pulls/%d/files", issueIndex.MaxIndex)
- req = NewRequest(t, "GET", prFilesURL)
- resp = session.MakeRequest(t, req, http.StatusOK)
+ req := NewRequest(t, "GET", prFilesURL)
+ resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
editButtonCount := doc.doc.Find(".diff-file-header-actions a[href*='/_edit/']").Length()
assert.Positive(t, editButtonCount, "Expected to find a button to edit a file in the PR diff view but there were none")
repoForked := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user1", Name: "repo1"})
- user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
// delete the head repository and revisit the PR diff view
- err := repo_service.DeleteRepositoryDirectly(db.DefaultContext, user2, repoForked.ID)
+ err := repo_service.DeleteRepositoryDirectly(db.DefaultContext, repoForked.ID)
assert.NoError(t, err)
req = NewRequest(t, "GET", prFilesURL)
resp = session.MakeRequest(t, req, http.StatusOK)
doc = NewHTMLParser(t, resp.Body)
editButtonCount = doc.doc.Find(".diff-file-header-actions a[href*='/_edit/']").Length()
- assert.EqualValues(t, 0, editButtonCount, "Expected not to find a button to edit a file in the PR diff view because head repository has been deleted")
+ assert.Equal(t, 0, editButtonCount, "Expected not to find a button to edit a file in the PR diff view because head repository has been deleted")
})
}
@@ -95,7 +108,7 @@ func TestPullCompare_EnableAllowEditsFromMaintainer(t *testing.T) {
// user2 (admin of repo3) goes to the PR files page
user2Session := loginUser(t, "user2")
- resp = user2Session.MakeRequest(t, NewRequest(t, "GET", fmt.Sprintf("%s/files", prURL)), http.StatusOK)
+ resp = user2Session.MakeRequest(t, NewRequest(t, "GET", prURL+"/files"), http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
nodes := htmlDoc.doc.Find(".diff-file-box[data-new-filename=\"README.md\"] .diff-file-header-actions .tippy-target a")
if assert.Equal(t, 1, nodes.Length()) {
@@ -112,14 +125,14 @@ func TestPullCompare_EnableAllowEditsFromMaintainer(t *testing.T) {
htmlDoc = NewHTMLParser(t, resp.Body)
dataURL, exists := htmlDoc.doc.Find("#allow-edits-from-maintainers").Attr("data-url")
assert.True(t, exists)
- req := NewRequestWithValues(t, "POST", fmt.Sprintf("%s/set_allow_maintainer_edit", dataURL), map[string]string{
+ req := NewRequestWithValues(t, "POST", dataURL+"/set_allow_maintainer_edit", map[string]string{
"_csrf": htmlDoc.GetCSRF(),
"allow_maintainer_edit": "true",
})
user4Session.MakeRequest(t, req, http.StatusOK)
// user2 (admin of repo3) goes to the PR files page again
- resp = user2Session.MakeRequest(t, NewRequest(t, "GET", fmt.Sprintf("%s/files", prURL)), http.StatusOK)
+ resp = user2Session.MakeRequest(t, NewRequest(t, "GET", prURL+"/files"), http.StatusOK)
htmlDoc = NewHTMLParser(t, resp.Body)
nodes = htmlDoc.doc.Find(".diff-file-box[data-new-filename=\"README.md\"] .diff-file-header-actions .tippy-target a")
if assert.Equal(t, 2, nodes.Length()) {
@@ -146,7 +159,8 @@ func TestPullCompare_EnableAllowEditsFromMaintainer(t *testing.T) {
"commit_summary": "user2 updated the file",
"commit_choice": "direct",
})
- user2Session.MakeRequest(t, req, http.StatusSeeOther)
+ resp = user2Session.MakeRequest(t, req, http.StatusOK)
+ assert.NotEmpty(t, test.RedirectURL(resp))
}
}
})
diff --git a/tests/integration/pull_create_test.go b/tests/integration/pull_create_test.go
index 9812d2073d..44ef501961 100644
--- a/tests/integration/pull_create_test.go
+++ b/tests/integration/pull_create_test.go
@@ -12,6 +12,8 @@ import (
"strings"
"testing"
+ auth_model "code.gitea.io/gitea/models/auth"
+ "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/tests"
@@ -82,6 +84,30 @@ func testPullCreateDirectly(t *testing.T, session *TestSession, baseRepoOwner, b
return resp
}
+func testPullCreateFailure(t *testing.T, session *TestSession, baseRepoOwner, baseRepoName, baseBranch, headRepoOwner, headRepoName, headBranch, title string) *httptest.ResponseRecorder {
+ headCompare := headBranch
+ if headRepoOwner != "" {
+ if headRepoName != "" {
+ headCompare = fmt.Sprintf("%s/%s:%s", headRepoOwner, headRepoName, headBranch)
+ } else {
+ headCompare = fmt.Sprintf("%s:%s", headRepoOwner, headBranch)
+ }
+ }
+ req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/compare/%s...%s", baseRepoOwner, baseRepoName, baseBranch, headCompare))
+ resp := session.MakeRequest(t, req, http.StatusOK)
+
+ // Submit the form for creating the pull
+ htmlDoc := NewHTMLParser(t, resp.Body)
+ link, exists := htmlDoc.doc.Find("form.ui.form").Attr("action")
+ assert.True(t, exists, "The template has changed")
+ req = NewRequestWithValues(t, "POST", link, map[string]string{
+ "_csrf": htmlDoc.GetCSRF(),
+ "title": title,
+ })
+ resp = session.MakeRequest(t, req, http.StatusBadRequest)
+ return resp
+}
+
func TestPullCreate(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) {
session := loginUser(t, "user1")
@@ -137,10 +163,10 @@ func TestPullCreate_TitleEscape(t *testing.T) {
req = NewRequest(t, "GET", url)
resp = session.MakeRequest(t, req, http.StatusOK)
htmlDoc = NewHTMLParser(t, resp.Body)
- titleHTML, err := htmlDoc.doc.Find(".comment-list .timeline-item.event .text b").First().Html()
+ titleHTML, err := htmlDoc.doc.Find(".comment-list .timeline-item.event .comment-text-line b").First().Html()
assert.NoError(t, err)
assert.Equal(t, "<strike>&lt;i&gt;XSS PR&lt;/i&gt;</strike>", titleHTML)
- titleHTML, err = htmlDoc.doc.Find(".comment-list .timeline-item.event .text b").Next().Html()
+ titleHTML, err = htmlDoc.doc.Find(".comment-list .timeline-item.event .comment-text-line b").Next().Html()
assert.NoError(t, err)
assert.Equal(t, "&lt;u&gt;XSS PR&lt;/u&gt;", titleHTML)
})
@@ -226,3 +252,64 @@ func TestPullCreatePrFromBaseToFork(t *testing.T) {
assert.Regexp(t, "^/user1/repo1/pulls/[0-9]*$", url)
})
}
+
+func TestCreateAgitPullWithReadPermission(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ dstPath := t.TempDir()
+
+ u.Path = "user2/repo1.git"
+ u.User = url.UserPassword("user4", userPassword)
+
+ t.Run("Clone", doGitClone(dstPath, u))
+
+ t.Run("add commit", doGitAddSomeCommits(dstPath, "master"))
+
+ t.Run("do agit pull create", func(t *testing.T) {
+ err := git.NewCommand("push", "origin", "HEAD:refs/for/master", "-o").AddDynamicArguments("topic="+"test-topic").Run(git.DefaultContext, &git.RunOpts{Dir: dstPath})
+ assert.NoError(t, err)
+ })
+ })
+}
+
+/*
+Setup: user2 has repository, user1 forks it
+---
+
+1. User2 blocks User1
+2. User1 adds changes to fork
+3. User1 attempts to create a pull request
+4. User1 sees alert that the action is not allowed because of the block
+*/
+func TestCreatePullWhenBlocked(t *testing.T) {
+ RepoOwner := "user2"
+ ForkOwner := "user16"
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ // Setup
+ // User1 forks repo1 from User2
+ sessionFork := loginUser(t, ForkOwner)
+ testRepoFork(t, sessionFork, RepoOwner, "repo1", ForkOwner, "forkrepo1", "")
+
+ // 1. User2 blocks user1
+ // sessionBase := loginUser(t, "user2")
+ token := getUserToken(t, RepoOwner, auth_model.AccessTokenScopeWriteUser)
+
+ req := NewRequest(t, "GET", "/api/v1/user/blocks/"+ForkOwner).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNotFound)
+ req = NewRequest(t, "PUT", "/api/v1/user/blocks/"+ForkOwner).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNoContent)
+
+ // 2. User1 adds changes to fork
+ testEditFile(t, sessionFork, ForkOwner, "forkrepo1", "master", "README.md", "Hello, World (Edited)\n")
+
+ // 3. User1 attempts to create a pull request
+ testPullCreateFailure(t, sessionFork, RepoOwner, "repo1", "master", ForkOwner, "forkrepo1", "master", "This is a pull title")
+
+ // Teardown
+ // Unblock user
+ req = NewRequest(t, "DELETE", "/api/v1/user/blocks/"+ForkOwner).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusNoContent)
+ })
+}
diff --git a/tests/integration/pull_diff_test.go b/tests/integration/pull_diff_test.go
index 5411250935..0b286fd2b2 100644
--- a/tests/integration/pull_diff_test.go
+++ b/tests/integration/pull_diff_test.go
@@ -25,10 +25,6 @@ func TestPullDiff_CommitRangePRDiff(t *testing.T) {
doTestPRDiff(t, "/user2/commitsonpr/pulls/1/files/4ca8bcaf27e28504df7bf996819665986b01c847..23576dd018294e476c06e569b6b0f170d0558705", true, []string{"test2.txt", "test3.txt", "test4.txt"})
}
-func TestPullDiff_StartingFromBaseToCommitPRDiff(t *testing.T) {
- doTestPRDiff(t, "/user2/commitsonpr/pulls/1/files/c5626fc9eff57eb1bb7b796b01d4d0f2f3f792a2", true, []string{"test1.txt", "test2.txt", "test3.txt"})
-}
-
func doTestPRDiff(t *testing.T, prDiffURL string, reviewBtnDisabled bool, expectedFilenames []string) {
defer tests.PrepareTestEnv(t)()
diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go
index 2edc95d4c8..3afa5f10f1 100644
--- a/tests/integration/pull_merge_test.go
+++ b/tests/integration/pull_merge_test.go
@@ -5,7 +5,6 @@ package integration
import (
"bytes"
- "context"
"fmt"
"net/http"
"net/http/httptest"
@@ -27,6 +26,7 @@ import (
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/models/webhook"
+ "code.gitea.io/gitea/modules/commitstatus"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/queue"
@@ -35,6 +35,7 @@ import (
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/translation"
"code.gitea.io/gitea/services/automerge"
+ "code.gitea.io/gitea/services/automergequeue"
pull_service "code.gitea.io/gitea/services/pull"
repo_service "code.gitea.io/gitea/services/repository"
commitstatus_service "code.gitea.io/gitea/services/repository/commitstatus"
@@ -67,7 +68,7 @@ func testPullMerge(t *testing.T, session *TestSession, user, repo, pullnum strin
}{}
DecodeJSON(t, resp, &respJSON)
- assert.EqualValues(t, fmt.Sprintf("/%s/%s/pulls/%s", user, repo, pullnum), respJSON.Redirect)
+ assert.Equal(t, fmt.Sprintf("/%s/%s/pulls/%s", user, repo, pullnum), respJSON.Redirect)
return resp
}
@@ -101,7 +102,7 @@ func TestPullMerge(t *testing.T) {
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title")
elem := strings.Split(test.RedirectURL(resp), "/")
- assert.EqualValues(t, "pulls", elem[3])
+ assert.Equal(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleMerge, false)
hookTasks, err = webhook.HookTasks(db.DefaultContext, 1, 1)
@@ -123,7 +124,7 @@ func TestPullRebase(t *testing.T) {
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title")
elem := strings.Split(test.RedirectURL(resp), "/")
- assert.EqualValues(t, "pulls", elem[3])
+ assert.Equal(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleRebase, false)
hookTasks, err = webhook.HookTasks(db.DefaultContext, 1, 1)
@@ -145,7 +146,7 @@ func TestPullRebaseMerge(t *testing.T) {
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title")
elem := strings.Split(test.RedirectURL(resp), "/")
- assert.EqualValues(t, "pulls", elem[3])
+ assert.Equal(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleRebaseMerge, false)
hookTasks, err = webhook.HookTasks(db.DefaultContext, 1, 1)
@@ -168,7 +169,7 @@ func TestPullSquash(t *testing.T) {
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title")
elem := strings.Split(test.RedirectURL(resp), "/")
- assert.EqualValues(t, "pulls", elem[3])
+ assert.Equal(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleSquash, false)
hookTasks, err = webhook.HookTasks(db.DefaultContext, 1, 1)
@@ -186,7 +187,7 @@ func TestPullCleanUpAfterMerge(t *testing.T) {
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "feature/test", "This is a pull title")
elem := strings.Split(test.RedirectURL(resp), "/")
- assert.EqualValues(t, "pulls", elem[3])
+ assert.Equal(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleMerge, false)
// Check PR branch deletion
@@ -199,7 +200,7 @@ func TestPullCleanUpAfterMerge(t *testing.T) {
assert.NotEmpty(t, respJSON.Redirect, "Redirected URL is not found")
elem = strings.Split(respJSON.Redirect, "/")
- assert.EqualValues(t, "pulls", elem[3])
+ assert.Equal(t, "pulls", elem[3])
// Check branch deletion result
req := NewRequest(t, "GET", respJSON.Redirect)
@@ -208,7 +209,7 @@ func TestPullCleanUpAfterMerge(t *testing.T) {
htmlDoc := NewHTMLParser(t, resp.Body)
resultMsg := htmlDoc.doc.Find(".ui.message>p").Text()
- assert.EqualValues(t, "Branch \"user1/repo1:feature/test\" has been deleted.", resultMsg)
+ assert.Equal(t, "Branch \"user1/repo1:feature/test\" has been deleted.", resultMsg)
})
}
@@ -266,11 +267,11 @@ func TestCantMergeConflict(t *testing.T) {
gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo1)
assert.NoError(t, err)
- err = pull_service.Merge(context.Background(), pr, user1, gitRepo, repo_model.MergeStyleMerge, "", "CONFLICT", false)
+ err = pull_service.Merge(t.Context(), pr, user1, gitRepo, repo_model.MergeStyleMerge, "", "CONFLICT", false)
assert.Error(t, err, "Merge should return an error due to conflict")
assert.True(t, pull_service.IsErrMergeConflicts(err), "Merge error is not a conflict error")
- err = pull_service.Merge(context.Background(), pr, user1, gitRepo, repo_model.MergeStyleRebase, "", "CONFLICT", false)
+ err = pull_service.Merge(t.Context(), pr, user1, gitRepo, repo_model.MergeStyleRebase, "", "CONFLICT", false)
assert.Error(t, err, "Merge should return an error due to conflict")
assert.True(t, pull_service.IsErrRebaseConflicts(err), "Merge error is not a conflict error")
gitRepo.Close()
@@ -294,12 +295,12 @@ func TestCantMergeUnrelated(t *testing.T) {
})
path := repo_model.RepoPath(user1.Name, repo1.Name)
- err := git.NewCommand(git.DefaultContext, "read-tree", "--empty").Run(&git.RunOpts{Dir: path})
+ err := git.NewCommand("read-tree", "--empty").Run(git.DefaultContext, &git.RunOpts{Dir: path})
assert.NoError(t, err)
- stdin := bytes.NewBufferString("Unrelated File")
+ stdin := strings.NewReader("Unrelated File")
var stdout strings.Builder
- err = git.NewCommand(git.DefaultContext, "hash-object", "-w", "--stdin").Run(&git.RunOpts{
+ err = git.NewCommand("hash-object", "-w", "--stdin").Run(git.DefaultContext, &git.RunOpts{
Dir: path,
Stdin: stdin,
Stdout: &stdout,
@@ -308,10 +309,10 @@ func TestCantMergeUnrelated(t *testing.T) {
assert.NoError(t, err)
sha := strings.TrimSpace(stdout.String())
- _, _, err = git.NewCommand(git.DefaultContext, "update-index", "--add", "--replace", "--cacheinfo").AddDynamicArguments("100644", sha, "somewher-over-the-rainbow").RunStdString(&git.RunOpts{Dir: path})
+ _, _, err = git.NewCommand("update-index", "--add", "--replace", "--cacheinfo").AddDynamicArguments("100644", sha, "somewher-over-the-rainbow").RunStdString(git.DefaultContext, &git.RunOpts{Dir: path})
assert.NoError(t, err)
- treeSha, _, err := git.NewCommand(git.DefaultContext, "write-tree").RunStdString(&git.RunOpts{Dir: path})
+ treeSha, _, err := git.NewCommand("write-tree").RunStdString(git.DefaultContext, &git.RunOpts{Dir: path})
assert.NoError(t, err)
treeSha = strings.TrimSpace(treeSha)
@@ -331,8 +332,8 @@ func TestCantMergeUnrelated(t *testing.T) {
_, _ = messageBytes.WriteString("\n")
stdout.Reset()
- err = git.NewCommand(git.DefaultContext, "commit-tree").AddDynamicArguments(treeSha).
- Run(&git.RunOpts{
+ err = git.NewCommand("commit-tree").AddDynamicArguments(treeSha).
+ Run(git.DefaultContext, &git.RunOpts{
Env: env,
Dir: path,
Stdin: messageBytes,
@@ -341,7 +342,7 @@ func TestCantMergeUnrelated(t *testing.T) {
assert.NoError(t, err)
commitSha := strings.TrimSpace(stdout.String())
- _, _, err = git.NewCommand(git.DefaultContext, "branch", "unrelated").AddDynamicArguments(commitSha).RunStdString(&git.RunOpts{Dir: path})
+ _, _, err = git.NewCommand("branch", "unrelated").AddDynamicArguments(commitSha).RunStdString(git.DefaultContext, &git.RunOpts{Dir: path})
assert.NoError(t, err)
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "conflict", "README.md", "Hello, World (Edited Once)\n")
@@ -365,7 +366,7 @@ func TestCantMergeUnrelated(t *testing.T) {
BaseBranch: "base",
})
- err = pull_service.Merge(context.Background(), pr, user1, gitRepo, repo_model.MergeStyleMerge, "", "UNRELATED", false)
+ err = pull_service.Merge(t.Context(), pr, user1, gitRepo, repo_model.MergeStyleMerge, "", "UNRELATED", false)
assert.Error(t, err, "Merge should return an error due to unrelated")
assert.True(t, pull_service.IsErrMergeUnrelatedHistories(err), "Merge error is not a unrelated histories error")
gitRepo.Close()
@@ -405,7 +406,7 @@ func TestFastForwardOnlyMerge(t *testing.T) {
gitRepo, err := git.OpenRepository(git.DefaultContext, repo_model.RepoPath(user1.Name, repo1.Name))
assert.NoError(t, err)
- err = pull_service.Merge(context.Background(), pr, user1, gitRepo, repo_model.MergeStyleFastForwardOnly, "", "FAST-FORWARD-ONLY", false)
+ err = pull_service.Merge(t.Context(), pr, user1, gitRepo, repo_model.MergeStyleFastForwardOnly, "", "FAST-FORWARD-ONLY", false)
assert.NoError(t, err)
@@ -447,7 +448,7 @@ func TestCantFastForwardOnlyMergeDiverging(t *testing.T) {
gitRepo, err := git.OpenRepository(git.DefaultContext, repo_model.RepoPath(user1.Name, repo1.Name))
assert.NoError(t, err)
- err = pull_service.Merge(context.Background(), pr, user1, gitRepo, repo_model.MergeStyleFastForwardOnly, "", "DIVERGING", false)
+ err = pull_service.Merge(t.Context(), pr, user1, gitRepo, repo_model.MergeStyleFastForwardOnly, "", "DIVERGING", false)
assert.Error(t, err, "Merge should return an error due to being for a diverging branch")
assert.True(t, pull_service.IsErrMergeDivergingFastForwardOnly(err), "Merge error is not a diverging fast-forward-only error")
@@ -545,11 +546,11 @@ func TestPullRetargetChildOnBranchDelete(t *testing.T) {
respBasePR := testPullCreate(t, session, "user2", "repo1", true, "master", "base-pr", "Base Pull Request")
elemBasePR := strings.Split(test.RedirectURL(respBasePR), "/")
- assert.EqualValues(t, "pulls", elemBasePR[3])
+ assert.Equal(t, "pulls", elemBasePR[3])
respChildPR := testPullCreate(t, session, "user1", "repo1", false, "base-pr", "child-pr", "Child Pull Request")
elemChildPR := strings.Split(test.RedirectURL(respChildPR), "/")
- assert.EqualValues(t, "pulls", elemChildPR[3])
+ assert.Equal(t, "pulls", elemChildPR[3])
testPullMerge(t, session, elemBasePR[1], elemBasePR[2], elemBasePR[4], repo_model.MergeStyleMerge, true)
@@ -565,8 +566,8 @@ func TestPullRetargetChildOnBranchDelete(t *testing.T) {
targetBranch := htmlDoc.doc.Find("#branch_target>a").Text()
prStatus := strings.TrimSpace(htmlDoc.doc.Find(".issue-title-meta>.issue-state-label").Text())
- assert.EqualValues(t, "master", targetBranch)
- assert.EqualValues(t, "Open", prStatus)
+ assert.Equal(t, "master", targetBranch)
+ assert.Equal(t, "Open", prStatus)
})
}
@@ -579,11 +580,13 @@ func TestPullDontRetargetChildOnWrongRepo(t *testing.T) {
respBasePR := testPullCreate(t, session, "user1", "repo1", false, "master", "base-pr", "Base Pull Request")
elemBasePR := strings.Split(test.RedirectURL(respBasePR), "/")
- assert.EqualValues(t, "pulls", elemBasePR[3])
+ assert.Equal(t, "pulls", elemBasePR[3])
respChildPR := testPullCreate(t, session, "user1", "repo1", true, "base-pr", "child-pr", "Child Pull Request")
elemChildPR := strings.Split(test.RedirectURL(respChildPR), "/")
- assert.EqualValues(t, "pulls", elemChildPR[3])
+ assert.Equal(t, "pulls", elemChildPR[3])
+
+ defer test.MockVariableValue(&setting.Repository.PullRequest.RetargetChildrenOnMerge, false)()
testPullMerge(t, session, elemBasePR[1], elemBasePR[2], elemBasePR[4], repo_model.MergeStyleMerge, true)
@@ -600,8 +603,8 @@ func TestPullDontRetargetChildOnWrongRepo(t *testing.T) {
targetBranch := htmlDoc.doc.Find("#branch_target>span").Text()
prStatus := strings.TrimSpace(htmlDoc.doc.Find(".issue-title-meta>.issue-state-label").Text())
- assert.EqualValues(t, "base-pr", targetBranch)
- assert.EqualValues(t, "Closed", prStatus)
+ assert.Equal(t, "base-pr", targetBranch)
+ assert.Equal(t, "Closed", prStatus)
})
}
@@ -613,7 +616,7 @@ func TestPullRequestMergedWithNoPermissionDeleteBranch(t *testing.T) {
respBasePR := testPullCreate(t, session, "user4", "repo1", false, "master", "base-pr", "Base Pull Request")
elemBasePR := strings.Split(test.RedirectURL(respBasePR), "/")
- assert.EqualValues(t, "pulls", elemBasePR[3])
+ assert.Equal(t, "pulls", elemBasePR[3])
// user2 has no permission to delete branch of repo user1/repo1
session2 := loginUser(t, "user2")
@@ -634,7 +637,7 @@ func TestPullMergeIndexerNotifier(t *testing.T) {
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
createPullResp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "Indexer notifier test pull")
- assert.NoError(t, queue.GetManager().FlushAll(context.Background(), 0))
+ assert.NoError(t, queue.GetManager().FlushAll(t.Context(), 0))
time.Sleep(time.Second)
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{
@@ -664,7 +667,7 @@ func TestPullMergeIndexerNotifier(t *testing.T) {
// merge the pull request
elem := strings.Split(test.RedirectURL(createPullResp), "/")
- assert.EqualValues(t, "pulls", elem[3])
+ assert.Equal(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleMerge, false)
// check if the issue is closed
@@ -673,7 +676,7 @@ func TestPullMergeIndexerNotifier(t *testing.T) {
})
assert.True(t, issue.IsClosed)
- assert.NoError(t, queue.GetManager().FlushAll(context.Background(), 0))
+ assert.NoError(t, queue.GetManager().FlushAll(t.Context(), 0))
time.Sleep(time.Second)
// search issues again
@@ -693,12 +696,12 @@ func testResetRepo(t *testing.T, repoPath, branch, commitID string) {
assert.NoError(t, err)
f.Close()
- repo, err := git.OpenRepository(context.Background(), repoPath)
+ repo, err := git.OpenRepository(t.Context(), repoPath)
assert.NoError(t, err)
defer repo.Close()
id, err := repo.GetBranchCommitID(branch)
assert.NoError(t, err)
- assert.EqualValues(t, commitID, id)
+ assert.Equal(t, commitID, id)
}
func TestPullAutoMergeAfterCommitStatusSucceed(t *testing.T) {
@@ -725,7 +728,7 @@ func TestPullAutoMergeAfterCommitStatusSucceed(t *testing.T) {
// add protected branch for commit status
csrf := GetUserCSRFToken(t, session)
- // Change master branch to protected
+ // Change the "master" branch to "protected"
req := NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/edit", map[string]string{
"_csrf": csrf,
"rule_name": "master",
@@ -735,13 +738,25 @@ func TestPullAutoMergeAfterCommitStatusSucceed(t *testing.T) {
})
session.MakeRequest(t, req, http.StatusSeeOther)
+ oldAutoMergeAddToQueue := automergequeue.AddToQueue
+ addToQueueShaChan := make(chan string, 1)
+ automergequeue.AddToQueue = func(pr *issues_model.PullRequest, sha string) {
+ addToQueueShaChan <- sha
+ }
// first time insert automerge record, return true
- scheduled, err := automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test")
+ scheduled, err := automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test", false)
assert.NoError(t, err)
assert.True(t, scheduled)
+ // and the pr should be added to automergequeue, in case it is already "mergeable"
+ select {
+ case <-addToQueueShaChan:
+ case <-time.After(time.Second):
+ assert.FailNow(t, "Timeout: nothing was added to automergequeue")
+ }
+ automergequeue.AddToQueue = oldAutoMergeAddToQueue
// second time insert automerge record, return false because it does exist
- scheduled, err = automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test")
+ scheduled, err = automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test", false)
assert.Error(t, err)
assert.False(t, scheduled)
@@ -753,7 +768,7 @@ func TestPullAutoMergeAfterCommitStatusSucceed(t *testing.T) {
// update commit status to success, then it should be merged automatically
baseGitRepo, err := gitrepo.OpenRepository(db.DefaultContext, baseRepo)
assert.NoError(t, err)
- sha, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
+ sha, err := baseGitRepo.GetRefCommitID(pr.GetGitHeadRefName())
assert.NoError(t, err)
masterCommitID, err := baseGitRepo.GetBranchCommitID("master")
assert.NoError(t, err)
@@ -767,19 +782,17 @@ func TestPullAutoMergeAfterCommitStatusSucceed(t *testing.T) {
}()
err = commitstatus_service.CreateCommitStatus(db.DefaultContext, baseRepo, user1, sha, &git_model.CommitStatus{
- State: api.CommitStatusSuccess,
+ State: commitstatus.CommitStatusSuccess,
TargetURL: "https://gitea.com",
Context: "gitea/actions",
})
assert.NoError(t, err)
- time.Sleep(2 * time.Second)
-
- // realod pr again
- pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID})
- assert.True(t, pr.HasMerged)
+ assert.Eventually(t, func() bool {
+ pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID})
+ return pr.HasMerged
+ }, 2*time.Second, 100*time.Millisecond)
assert.NotEmpty(t, pr.MergedCommitID)
-
unittest.AssertNotExistsBean(t, &pull_model.AutoMerge{PullID: pr.ID})
})
}
@@ -820,12 +833,12 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApproval(t *testing.T) {
session.MakeRequest(t, req, http.StatusSeeOther)
// first time insert automerge record, return true
- scheduled, err := automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test")
+ scheduled, err := automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test", false)
assert.NoError(t, err)
assert.True(t, scheduled)
// second time insert automerge record, return false because it does exist
- scheduled, err = automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test")
+ scheduled, err = automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test", false)
assert.Error(t, err)
assert.False(t, scheduled)
@@ -837,7 +850,7 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApproval(t *testing.T) {
// update commit status to success, then it should be merged automatically
baseGitRepo, err := gitrepo.OpenRepository(db.DefaultContext, baseRepo)
assert.NoError(t, err)
- sha, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
+ sha, err := baseGitRepo.GetRefCommitID(pr.GetGitHeadRefName())
assert.NoError(t, err)
masterCommitID, err := baseGitRepo.GetBranchCommitID("master")
assert.NoError(t, err)
@@ -847,7 +860,7 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApproval(t *testing.T) {
}()
err = commitstatus_service.CreateCommitStatus(db.DefaultContext, baseRepo, user1, sha, &git_model.CommitStatus{
- State: api.CommitStatusSuccess,
+ State: commitstatus.CommitStatusSuccess,
TargetURL: "https://gitea.com",
Context: "gitea/actions",
})
@@ -913,13 +926,13 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApprovalForAgitFlow(t *testing.
stderrBuf := &bytes.Buffer{}
- err = git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master", "-o").
+ err = git.NewCommand("push", "origin", "HEAD:refs/for/master", "-o").
AddDynamicArguments(`topic=test/head2`).
AddArguments("-o").
AddDynamicArguments(`title="create a test pull request with agit"`).
AddArguments("-o").
AddDynamicArguments(`description="This PR is a test pull request which created with agit"`).
- Run(&git.RunOpts{Dir: dstPath, Stderr: stderrBuf})
+ Run(git.DefaultContext, &git.RunOpts{Dir: dstPath, Stderr: stderrBuf})
assert.NoError(t, err)
assert.Contains(t, stderrBuf.String(), setting.AppURL+"user2/repo1/pulls/6")
@@ -949,12 +962,12 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApprovalForAgitFlow(t *testing.
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
// first time insert automerge record, return true
- scheduled, err := automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test")
+ scheduled, err := automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test", false)
assert.NoError(t, err)
assert.True(t, scheduled)
// second time insert automerge record, return false because it does exist
- scheduled, err = automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test")
+ scheduled, err = automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test", false)
assert.Error(t, err)
assert.False(t, scheduled)
@@ -966,7 +979,7 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApprovalForAgitFlow(t *testing.
// update commit status to success, then it should be merged automatically
baseGitRepo, err := gitrepo.OpenRepository(db.DefaultContext, baseRepo)
assert.NoError(t, err)
- sha, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
+ sha, err := baseGitRepo.GetRefCommitID(pr.GetGitHeadRefName())
assert.NoError(t, err)
masterCommitID, err := baseGitRepo.GetBranchCommitID("master")
assert.NoError(t, err)
@@ -976,14 +989,12 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApprovalForAgitFlow(t *testing.
}()
err = commitstatus_service.CreateCommitStatus(db.DefaultContext, baseRepo, user1, sha, &git_model.CommitStatus{
- State: api.CommitStatusSuccess,
+ State: commitstatus.CommitStatusSuccess,
TargetURL: "https://gitea.com",
Context: "gitea/actions",
})
assert.NoError(t, err)
- time.Sleep(2 * time.Second)
-
// reload pr again
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID})
assert.False(t, pr.HasMerged)
@@ -996,8 +1007,6 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApprovalForAgitFlow(t *testing.
htmlDoc := NewHTMLParser(t, resp.Body)
testSubmitReview(t, approveSession, htmlDoc.GetCSRF(), "user2", "repo1", strconv.Itoa(int(pr.Index)), sha, "approve", http.StatusOK)
- time.Sleep(2 * time.Second)
-
// realod pr again
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID})
assert.True(t, pr.HasMerged)
diff --git a/tests/integration/pull_review_test.go b/tests/integration/pull_review_test.go
index 5ecf3ef469..1121751c88 100644
--- a/tests/integration/pull_review_test.go
+++ b/tests/integration/pull_review_test.go
@@ -57,7 +57,7 @@ func TestPullView_CodeOwner(t *testing.T) {
AutoInit: true,
ObjectFormatName: git.Sha1ObjectFormat.Name(),
DefaultBranch: "master",
- })
+ }, true)
assert.NoError(t, err)
// add CODEOWNERS to default branch
@@ -67,7 +67,7 @@ func TestPullView_CodeOwner(t *testing.T) {
{
Operation: "create",
TreePath: "CODEOWNERS",
- ContentReader: strings.NewReader("README.md @user5\n"),
+ ContentReader: strings.NewReader("README.md @user5\nuser8-file.md @user8\n"),
},
},
})
@@ -75,7 +75,7 @@ func TestPullView_CodeOwner(t *testing.T) {
t.Run("First Pull Request", func(t *testing.T) {
// create a new branch to prepare for pull request
- _, err = files_service.ChangeRepoFiles(db.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{
+ _, err := files_service.ChangeRepoFiles(db.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{
NewBranch: "codeowner-basebranch",
Files: []*files_service.ChangeRepoFile{
{
@@ -92,20 +92,38 @@ func TestPullView_CodeOwner(t *testing.T) {
testPullCreate(t, session, "user2", "test_codeowner", false, repo.DefaultBranch, "codeowner-basebranch", "Test Pull Request")
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: repo.ID, HeadRepoID: repo.ID, HeadBranch: "codeowner-basebranch"})
- unittest.AssertExistsIf(t, true, &issues_model.Review{IssueID: pr.IssueID, Type: issues_model.ReviewTypeRequest, ReviewerID: 5})
+ unittest.AssertExistsAndLoadBean(t, &issues_model.Review{IssueID: pr.IssueID, Type: issues_model.ReviewTypeRequest, ReviewerID: 5})
assert.NoError(t, pr.LoadIssue(db.DefaultContext))
- err := issue_service.ChangeTitle(db.DefaultContext, pr.Issue, user2, "[WIP] Test Pull Request")
+ // update the file on the pr branch
+ _, err = files_service.ChangeRepoFiles(db.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{
+ OldBranch: "codeowner-basebranch",
+ Files: []*files_service.ChangeRepoFile{
+ {
+ Operation: "create",
+ TreePath: "user8-file.md",
+ ContentReader: strings.NewReader("# This is a new project2\n"),
+ },
+ },
+ })
+ assert.NoError(t, err)
+
+ reviewNotifiers, err := issue_service.PullRequestCodeOwnersReview(db.DefaultContext, pr)
+ assert.NoError(t, err)
+ assert.Len(t, reviewNotifiers, 1)
+ assert.EqualValues(t, 8, reviewNotifiers[0].Reviewer.ID)
+
+ err = issue_service.ChangeTitle(db.DefaultContext, pr.Issue, user2, "[WIP] Test Pull Request")
assert.NoError(t, err)
prUpdated1 := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID})
assert.NoError(t, prUpdated1.LoadIssue(db.DefaultContext))
- assert.EqualValues(t, "[WIP] Test Pull Request", prUpdated1.Issue.Title)
+ assert.Equal(t, "[WIP] Test Pull Request", prUpdated1.Issue.Title)
err = issue_service.ChangeTitle(db.DefaultContext, prUpdated1.Issue, user2, "Test Pull Request2")
assert.NoError(t, err)
prUpdated2 := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID})
assert.NoError(t, prUpdated2.LoadIssue(db.DefaultContext))
- assert.EqualValues(t, "Test Pull Request2", prUpdated2.Issue.Title)
+ assert.Equal(t, "Test Pull Request2", prUpdated2.Issue.Title)
})
// change the default branch CODEOWNERS file to change README.md's codeowner
@@ -139,7 +157,7 @@ func TestPullView_CodeOwner(t *testing.T) {
testPullCreate(t, session, "user2", "test_codeowner", false, repo.DefaultBranch, "codeowner-basebranch2", "Test Pull Request2")
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: repo.ID, HeadBranch: "codeowner-basebranch2"})
- unittest.AssertExistsIf(t, true, &issues_model.Review{IssueID: pr.IssueID, Type: issues_model.ReviewTypeRequest, ReviewerID: 8})
+ unittest.AssertExistsAndLoadBean(t, &issues_model.Review{IssueID: pr.IssueID, Type: issues_model.ReviewTypeRequest, ReviewerID: 8})
})
t.Run("Forked Repo Pull Request", func(t *testing.T) {
@@ -169,13 +187,13 @@ func TestPullView_CodeOwner(t *testing.T) {
testPullCreateDirectly(t, session, "user5", "test_codeowner", forkedRepo.DefaultBranch, "", "", "codeowner-basebranch-forked", "Test Pull Request on Forked Repository")
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: forkedRepo.ID, HeadBranch: "codeowner-basebranch-forked"})
- unittest.AssertExistsIf(t, false, &issues_model.Review{IssueID: pr.IssueID, Type: issues_model.ReviewTypeRequest, ReviewerID: 8})
+ unittest.AssertNotExistsBean(t, &issues_model.Review{IssueID: pr.IssueID, Type: issues_model.ReviewTypeRequest, ReviewerID: 8})
// create a pull request to base repository, code reviewers should be mentioned
testPullCreateDirectly(t, session, repo.OwnerName, repo.Name, repo.DefaultBranch, forkedRepo.OwnerName, forkedRepo.Name, "codeowner-basebranch-forked", "Test Pull Request3")
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: repo.ID, HeadRepoID: forkedRepo.ID, HeadBranch: "codeowner-basebranch-forked"})
- unittest.AssertExistsIf(t, true, &issues_model.Review{IssueID: pr.IssueID, Type: issues_model.ReviewTypeRequest, ReviewerID: 8})
+ unittest.AssertExistsAndLoadBean(t, &issues_model.Review{IssueID: pr.IssueID, Type: issues_model.ReviewTypeRequest, ReviewerID: 8})
})
})
}
@@ -193,7 +211,7 @@ func TestPullView_GivenApproveOrRejectReviewOnClosedPR(t *testing.T) {
testEditFile(t, user1Session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
resp := testPullCreate(t, user1Session, "user1", "repo1", false, "master", "master", "This is a pull title")
elem := strings.Split(test.RedirectURL(resp), "/")
- assert.EqualValues(t, "pulls", elem[3])
+ assert.Equal(t, "pulls", elem[3])
testPullMerge(t, user1Session, elem[1], elem[2], elem[4], repo_model.MergeStyleMerge, false)
// Grab the CSRF token.
@@ -213,7 +231,7 @@ func TestPullView_GivenApproveOrRejectReviewOnClosedPR(t *testing.T) {
testEditFileToNewBranch(t, user1Session, "user1", "repo1", "master", "a-test-branch", "README.md", "Hello, World (Editied...again)\n")
resp := testPullCreate(t, user1Session, "user1", "repo1", false, "master", "a-test-branch", "This is a pull title")
elem := strings.Split(test.RedirectURL(resp), "/")
- assert.EqualValues(t, "pulls", elem[3])
+ assert.Equal(t, "pulls", elem[3])
testIssueClose(t, user1Session, elem[1], elem[2], elem[4])
// Grab the CSRF token.
diff --git a/tests/integration/pull_status_test.go b/tests/integration/pull_status_test.go
index ac9036ca96..49326a594a 100644
--- a/tests/integration/pull_status_test.go
+++ b/tests/integration/pull_status_test.go
@@ -13,9 +13,14 @@ import (
auth_model "code.gitea.io/gitea/models/auth"
git_model "code.gitea.io/gitea/models/git"
+ "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
+ "code.gitea.io/gitea/modules/commitstatus"
+ "code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/test"
+ "code.gitea.io/gitea/services/pull"
"github.com/stretchr/testify/assert"
)
@@ -51,20 +56,20 @@ func TestPullCreate_CommitStatus(t *testing.T) {
commitID := path.Base(commitURL)
- statusList := []api.CommitStatusState{
- api.CommitStatusPending,
- api.CommitStatusError,
- api.CommitStatusFailure,
- api.CommitStatusSuccess,
- api.CommitStatusWarning,
+ statusList := []commitstatus.CommitStatusState{
+ commitstatus.CommitStatusPending,
+ commitstatus.CommitStatusError,
+ commitstatus.CommitStatusFailure,
+ commitstatus.CommitStatusSuccess,
+ commitstatus.CommitStatusWarning,
}
- statesIcons := map[api.CommitStatusState]string{
- api.CommitStatusPending: "octicon-dot-fill",
- api.CommitStatusSuccess: "octicon-check",
- api.CommitStatusError: "gitea-exclamation",
- api.CommitStatusFailure: "octicon-x",
- api.CommitStatusWarning: "gitea-exclamation",
+ statesIcons := map[commitstatus.CommitStatusState]string{
+ commitstatus.CommitStatusPending: "octicon-dot-fill",
+ commitstatus.CommitStatusSuccess: "octicon-check",
+ commitstatus.CommitStatusError: "gitea-exclamation",
+ commitstatus.CommitStatusFailure: "octicon-x",
+ commitstatus.CommitStatusWarning: "gitea-exclamation",
}
testCtx := NewAPITestContext(t, "user1", "repo1", auth_model.AccessTokenScopeWriteRepository)
@@ -86,7 +91,7 @@ func TestPullCreate_CommitStatus(t *testing.T) {
commitURL, exists = doc.doc.Find("#commits-table tbody tr td.sha a").Last().Attr("href")
assert.True(t, exists)
assert.NotEmpty(t, commitURL)
- assert.EqualValues(t, commitID, path.Base(commitURL))
+ assert.Equal(t, commitID, path.Base(commitURL))
cls, ok := doc.doc.Find("#commits-table tbody tr td.message .commit-status").Last().Attr("class")
assert.True(t, ok)
@@ -95,7 +100,7 @@ func TestPullCreate_CommitStatus(t *testing.T) {
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user1", Name: "repo1"})
css := unittest.AssertExistsAndLoadBean(t, &git_model.CommitStatusSummary{RepoID: repo1.ID, SHA: commitID})
- assert.EqualValues(t, api.CommitStatusWarning, css.State)
+ assert.Equal(t, commitstatus.CommitStatusSuccess, css.State)
})
}
@@ -124,7 +129,7 @@ func TestPullCreate_EmptyChangesWithDifferentCommits(t *testing.T) {
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "status1", "README.md", "status1")
- testEditFileToNewBranch(t, session, "user1", "repo1", "status1", "status1", "README.md", "# repo1\n\nDescription for repo1")
+ testEditFile(t, session, "user1", "repo1", "status1", "README.md", "# repo1\n\nDescription for repo1")
url := path.Join("user1", "repo1", "compare", "master...status1")
req := NewRequestWithValues(t, "POST", url,
@@ -165,3 +170,74 @@ func TestPullCreate_EmptyChangesWithSameCommits(t *testing.T) {
assert.Contains(t, text, "This branch is already included in the target branch. There is nothing to merge.")
})
}
+
+func TestPullStatusDelayCheck(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ defer test.MockVariableValue(&setting.Repository.PullRequest.DelayCheckForInactiveDays, 1)()
+ defer test.MockVariableValue(&pull.AddPullRequestToCheckQueue)()
+
+ session := loginUser(t, "user2")
+
+ run := func(t *testing.T, fn func(*testing.T)) (issue3 *issues.Issue, checkedPrID int64) {
+ pull.AddPullRequestToCheckQueue = func(prID int64) {
+ checkedPrID = prID
+ }
+ fn(t)
+ issue3 = unittest.AssertExistsAndLoadBean(t, &issues.Issue{RepoID: 1, Index: 3})
+ _ = issue3.LoadPullRequest(t.Context())
+ return issue3, checkedPrID
+ }
+
+ assertReloadingInterval := func(t *testing.T, interval string) {
+ req := NewRequest(t, "GET", "/user2/repo1/pulls/3")
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ attr := "data-pull-merge-box-reloading-interval"
+ if interval == "" {
+ assert.NotContains(t, resp.Body.String(), attr)
+ } else {
+ assert.Contains(t, resp.Body.String(), fmt.Sprintf(`%s="%v"`, attr, interval))
+ }
+ }
+
+ // PR issue3 is merageable at the beginning
+ issue3, checkedPrID := run(t, func(t *testing.T) {})
+ assert.Equal(t, issues.PullRequestStatusMergeable, issue3.PullRequest.Status)
+ assert.Zero(t, checkedPrID)
+ assertReloadingInterval(t, "") // the PR is mergeable, so no need to reload the merge box
+
+ // setting.IsProd = false // it would cause data-race because the queue handlers might be running and reading its value
+ // assertReloadingInterval(t, "1") // make sure dev mode always do merge box reloading, to make sure the UI logic won't break
+ // setting.IsProd = true
+
+ // when base branch changes, PR status should be updated, but it is inactive for long time, so no real check
+ issue3, checkedPrID = run(t, func(t *testing.T) {
+ testEditFile(t, session, "user2", "repo1", "master", "README.md", "new content 1")
+ })
+ assert.Equal(t, issues.PullRequestStatusChecking, issue3.PullRequest.Status)
+ assert.Zero(t, checkedPrID)
+ assertReloadingInterval(t, "2000") // the PR status is "checking", so try to reload the merge box
+
+ // view a PR with status=checking, it starts the real check
+ issue3, checkedPrID = run(t, func(t *testing.T) {
+ req := NewRequest(t, "GET", "/user2/repo1/pulls/3")
+ session.MakeRequest(t, req, http.StatusOK)
+ })
+ assert.Equal(t, issues.PullRequestStatusChecking, issue3.PullRequest.Status)
+ assert.Equal(t, issue3.PullRequest.ID, checkedPrID)
+
+ // when base branch changes, still so no real check
+ issue3, checkedPrID = run(t, func(t *testing.T) {
+ testEditFile(t, session, "user2", "repo1", "master", "README.md", "new content 2")
+ })
+ assert.Equal(t, issues.PullRequestStatusChecking, issue3.PullRequest.Status)
+ assert.Zero(t, checkedPrID)
+
+ // then allow to check PRs without delay, when base branch changes, the PRs will be checked
+ setting.Repository.PullRequest.DelayCheckForInactiveDays = -1
+ issue3, checkedPrID = run(t, func(t *testing.T) {
+ testEditFile(t, session, "user2", "repo1", "master", "README.md", "new content 3")
+ })
+ assert.Equal(t, issues.PullRequestStatusChecking, issue3.PullRequest.Status)
+ assert.Equal(t, issue3.PullRequest.ID, checkedPrID)
+ })
+}
diff --git a/tests/integration/pull_update_test.go b/tests/integration/pull_update_test.go
index dfe47c1053..d28537112d 100644
--- a/tests/integration/pull_update_test.go
+++ b/tests/integration/pull_update_test.go
@@ -33,8 +33,8 @@ func TestAPIPullUpdate(t *testing.T) {
// Test GetDiverging
diffCount, err := pull_service.GetDiverging(git.DefaultContext, pr)
assert.NoError(t, err)
- assert.EqualValues(t, 1, diffCount.Behind)
- assert.EqualValues(t, 1, diffCount.Ahead)
+ assert.Equal(t, 1, diffCount.Behind)
+ assert.Equal(t, 1, diffCount.Ahead)
assert.NoError(t, pr.LoadBaseRepo(db.DefaultContext))
assert.NoError(t, pr.LoadIssue(db.DefaultContext))
@@ -47,8 +47,8 @@ func TestAPIPullUpdate(t *testing.T) {
// Test GetDiverging after update
diffCount, err = pull_service.GetDiverging(git.DefaultContext, pr)
assert.NoError(t, err)
- assert.EqualValues(t, 0, diffCount.Behind)
- assert.EqualValues(t, 2, diffCount.Ahead)
+ assert.Equal(t, 0, diffCount.Behind)
+ assert.Equal(t, 2, diffCount.Ahead)
})
}
@@ -62,8 +62,8 @@ func TestAPIPullUpdateByRebase(t *testing.T) {
// Test GetDiverging
diffCount, err := pull_service.GetDiverging(git.DefaultContext, pr)
assert.NoError(t, err)
- assert.EqualValues(t, 1, diffCount.Behind)
- assert.EqualValues(t, 1, diffCount.Ahead)
+ assert.Equal(t, 1, diffCount.Behind)
+ assert.Equal(t, 1, diffCount.Ahead)
assert.NoError(t, pr.LoadBaseRepo(db.DefaultContext))
assert.NoError(t, pr.LoadIssue(db.DefaultContext))
@@ -76,8 +76,8 @@ func TestAPIPullUpdateByRebase(t *testing.T) {
// Test GetDiverging after update
diffCount, err = pull_service.GetDiverging(git.DefaultContext, pr)
assert.NoError(t, err)
- assert.EqualValues(t, 0, diffCount.Behind)
- assert.EqualValues(t, 1, diffCount.Ahead)
+ assert.Equal(t, 0, diffCount.Behind)
+ assert.Equal(t, 1, diffCount.Ahead)
})
}
@@ -115,12 +115,12 @@ func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *issues_mod
OldBranch: "master",
NewBranch: "master",
Author: &files_service.IdentityOptions{
- Name: actor.Name,
- Email: actor.Email,
+ GitUserName: actor.Name,
+ GitUserEmail: actor.Email,
},
Committer: &files_service.IdentityOptions{
- Name: actor.Name,
- Email: actor.Email,
+ GitUserName: actor.Name,
+ GitUserEmail: actor.Email,
},
Dates: &files_service.CommitDateOptions{
Author: time.Now(),
@@ -142,12 +142,12 @@ func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *issues_mod
OldBranch: "master",
NewBranch: "newBranch",
Author: &files_service.IdentityOptions{
- Name: actor.Name,
- Email: actor.Email,
+ GitUserName: actor.Name,
+ GitUserEmail: actor.Email,
},
Committer: &files_service.IdentityOptions{
- Name: actor.Name,
- Email: actor.Email,
+ GitUserName: actor.Name,
+ GitUserEmail: actor.Email,
},
Dates: &files_service.CommitDateOptions{
Author: time.Now(),
diff --git a/tests/integration/release_test.go b/tests/integration/release_test.go
index 40bd798d16..88a58787af 100644
--- a/tests/integration/release_test.go
+++ b/tests/integration/release_test.go
@@ -7,7 +7,6 @@ import (
"fmt"
"net/http"
"testing"
- "time"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
@@ -39,7 +38,7 @@ func createNewRelease(t *testing.T, session *TestSession, repoURL, tag, title st
postData["prerelease"] = "on"
}
if draft {
- postData["draft"] = "Save Draft"
+ postData["draft"] = "1"
}
req = NewRequestWithValues(t, "POST", link, postData)
@@ -54,12 +53,12 @@ func checkLatestReleaseAndCount(t *testing.T, session *TestSession, repoURL, ver
htmlDoc := NewHTMLParser(t, resp.Body)
labelText := htmlDoc.doc.Find("#release-list > li .detail .label").First().Text()
- assert.EqualValues(t, label, labelText)
+ assert.Equal(t, label, labelText)
titleText := htmlDoc.doc.Find("#release-list > li .detail h4 a").First().Text()
- assert.EqualValues(t, version, titleText)
+ assert.Equal(t, version, titleText)
releaseList := htmlDoc.doc.Find("#release-list > li")
- assert.EqualValues(t, count, releaseList.Length())
+ assert.Equal(t, count, releaseList.Length())
}
func TestViewReleases(t *testing.T) {
@@ -68,9 +67,6 @@ func TestViewReleases(t *testing.T) {
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user2/repo1/releases")
session.MakeRequest(t, req, http.StatusOK)
-
- // if CI is to slow this test fail, so lets wait a bit
- time.Sleep(time.Millisecond * 100)
}
func TestViewReleasesNoLogin(t *testing.T) {
@@ -118,7 +114,7 @@ func TestCreateReleasePaging(t *testing.T) {
session := loginUser(t, "user2")
// Create enough releases to have paging
- for i := 0; i < 12; i++ {
+ for i := range 12 {
version := fmt.Sprintf("v0.0.%d", i)
createNewRelease(t, session, "/user2/repo1", version, version, false, false)
}
@@ -157,14 +153,14 @@ func TestViewReleaseListNoLogin(t *testing.T) {
commitsToMain = append(commitsToMain, s.Find(".ahead > a").Text())
})
- assert.EqualValues(t, []string{
+ assert.Equal(t, []string{
"/user2/repo-release/releases/tag/empty-target-branch",
"/user2/repo-release/releases/tag/non-existing-target-branch",
"/user2/repo-release/releases/tag/v2.0",
"/user2/repo-release/releases/tag/v1.1",
"/user2/repo-release/releases/tag/v1.0",
}, links)
- assert.EqualValues(t, []string{
+ assert.Equal(t, []string{
"1 commits", // like v1.1
"1 commits", // like v1.1
"0 commits",
@@ -173,17 +169,25 @@ func TestViewReleaseListNoLogin(t *testing.T) {
}, commitsToMain)
}
-func TestViewSingleReleaseNoLogin(t *testing.T) {
+func TestViewSingleRelease(t *testing.T) {
defer tests.PrepareTestEnv(t)()
- req := NewRequest(t, "GET", "/user2/repo-release/releases/tag/v1.0")
- resp := MakeRequest(t, req, http.StatusOK)
-
- htmlDoc := NewHTMLParser(t, resp.Body)
- // check the "number of commits to main since this release"
- releaseList := htmlDoc.doc.Find("#release-list .ahead > a")
- assert.EqualValues(t, 1, releaseList.Length())
- assert.EqualValues(t, "3 commits", releaseList.First().Text())
+ t.Run("NoLogin", func(t *testing.T) {
+ req := NewRequest(t, "GET", "/user2/repo-release/releases/tag/v1.0")
+ resp := MakeRequest(t, req, http.StatusOK)
+ htmlDoc := NewHTMLParser(t, resp.Body)
+ // check the "number of commits to main since this release"
+ releaseList := htmlDoc.doc.Find("#release-list .ahead > a")
+ assert.Equal(t, 1, releaseList.Length())
+ assert.Equal(t, "3 commits", releaseList.First().Text())
+ })
+ t.Run("Login", func(t *testing.T) {
+ session := loginUser(t, "user1")
+ req := NewRequest(t, "GET", "/user2/repo1/releases/tag/delete-tag") // "delete-tag" is the only one with is_tag=true (although strange name)
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ // the New Release button should contain the tag name
+ assert.Contains(t, resp.Body.String(), `<a class="ui small primary button" href="/user2/repo1/releases/new?tag=delete-tag">`)
+ })
}
func TestViewReleaseListLogin(t *testing.T) {
@@ -210,7 +214,7 @@ func TestViewReleaseListLogin(t *testing.T) {
links = append(links, link)
})
- assert.EqualValues(t, []string{
+ assert.Equal(t, []string{
"/user2/repo1/releases/tag/draft-release",
"/user2/repo1/releases/tag/v1.0",
"/user2/repo1/releases/tag/v1.1",
@@ -237,7 +241,7 @@ func TestViewTagsList(t *testing.T) {
tagNames = append(tagNames, s.Text())
})
- assert.EqualValues(t, []string{"v1.0", "delete-tag", "v1.1"}, tagNames)
+ assert.Equal(t, []string{"v1.0", "delete-tag", "v1.1"}, tagNames)
}
func TestDownloadReleaseAttachment(t *testing.T) {
diff --git a/tests/integration/rename_branch_test.go b/tests/integration/rename_branch_test.go
index 576264ba95..492fdf781b 100644
--- a/tests/integration/rename_branch_test.go
+++ b/tests/integration/rename_branch_test.go
@@ -11,7 +11,6 @@ import (
git_model "code.gitea.io/gitea/models/git"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
- gitea_context "code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
@@ -82,9 +81,8 @@ func testRenameBranch(t *testing.T, u *url.URL) {
"to": "branch1",
})
session.MakeRequest(t, req, http.StatusSeeOther)
- flashCookie := session.GetCookie(gitea_context.CookieNameFlash)
- assert.NotNil(t, flashCookie)
- assert.Contains(t, flashCookie.Value, "error")
+ flashMsg := session.GetCookieFlashMessage()
+ assert.NotEmpty(t, flashMsg.ErrorMsg)
branch2 = unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "branch2"})
assert.Equal(t, "branch2", branch2.Name)
@@ -110,9 +108,8 @@ func testRenameBranch(t *testing.T, u *url.URL) {
})
session.MakeRequest(t, req, http.StatusSeeOther)
- flashCookie = session.GetCookie(gitea_context.CookieNameFlash)
- assert.NotNil(t, flashCookie)
- assert.Contains(t, flashCookie.Value, "success")
+ flashMsg = session.GetCookieFlashMessage()
+ assert.NotEmpty(t, flashMsg.SuccessMsg)
unittest.AssertNotExistsBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "branch2"})
branch1 = unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "branch1"})
diff --git a/tests/integration/repo_activity_test.go b/tests/integration/repo_activity_test.go
index b04560379d..d5025decba 100644
--- a/tests/integration/repo_activity_test.go
+++ b/tests/integration/repo_activity_test.go
@@ -9,7 +9,9 @@ import (
"strings"
"testing"
+ "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/test"
"github.com/stretchr/testify/assert"
@@ -24,7 +26,7 @@ func TestRepoActivity(t *testing.T) {
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title")
elem := strings.Split(test.RedirectURL(resp), "/")
- assert.EqualValues(t, "pulls", elem[3])
+ assert.Equal(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleMerge, false)
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feat/better_readme", "README.md", "Hello, World (Edited Again)\n")
@@ -61,5 +63,14 @@ func TestRepoActivity(t *testing.T) {
// Should be 3 new issues
list = htmlDoc.doc.Find("#new-issues").Next().Find("p.desc")
assert.Len(t, list.Nodes, 3)
+
+ // Non-existing default branch
+ repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: "repo1"})
+ repo1.DefaultBranch = "no-such-branch"
+ _, _ = db.GetEngine(t.Context()).Cols("default_branch").Update(repo1)
+ req = NewRequest(t, "GET", "/user2/repo1/activity")
+ req.Header.Add("Accept", "text/html")
+ resp = session.MakeRequest(t, req, http.StatusNotFound)
+ assert.Contains(t, resp.Body.String(), `Default branch "no-such-branch" does not exist.`)
})
}
diff --git a/tests/integration/repo_branch_test.go b/tests/integration/repo_branch_test.go
index 2b4c417334..50ceb65330 100644
--- a/tests/integration/repo_branch_test.go
+++ b/tests/integration/repo_branch_test.go
@@ -11,13 +11,8 @@ import (
"strings"
"testing"
- auth_model "code.gitea.io/gitea/models/auth"
- org_model "code.gitea.io/gitea/models/organization"
- "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
- "code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/models/unittest"
- api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/translation"
"code.gitea.io/gitea/tests"
@@ -142,19 +137,51 @@ func TestCreateBranchInvalidCSRF(t *testing.T) {
assert.Contains(t, resp.Body.String(), "Invalid CSRF token")
}
-func prepareBranch(t *testing.T, session *TestSession, repo *repo_model.Repository) {
- baseRefSubURL := fmt.Sprintf("branch/%s", repo.DefaultBranch)
-
+func prepareRecentlyPushedBranchTest(t *testing.T, headSession *TestSession, baseRepo, headRepo *repo_model.Repository) {
+ refSubURL := "branch/" + headRepo.DefaultBranch
+ baseRepoPath := baseRepo.OwnerName + "/" + baseRepo.Name
+ headRepoPath := headRepo.OwnerName + "/" + headRepo.Name
+ // Case 1: Normal branch changeset to display pushed message
// create branch with no new commit
- testCreateBranch(t, session, repo.OwnerName, repo.Name, baseRefSubURL, "no-commit", http.StatusSeeOther)
+ testCreateBranch(t, headSession, headRepo.OwnerName, headRepo.Name, refSubURL, "no-commit", http.StatusSeeOther)
// create branch with commit
- testCreateBranch(t, session, repo.OwnerName, repo.Name, baseRefSubURL, "new-commit", http.StatusSeeOther)
- testAPINewFile(t, session, repo.OwnerName, repo.Name, "new-commit", "new-commit.txt", "new-commit")
+ testAPINewFile(t, headSession, headRepo.OwnerName, headRepo.Name, "new-commit", fmt.Sprintf("new-file-%s.txt", headRepo.Name), "new-commit")
+
+ // create a branch then delete it
+ testCreateBranch(t, headSession, headRepo.OwnerName, headRepo.Name, "branch/new-commit", "deleted-branch", http.StatusSeeOther)
+ testUIDeleteBranch(t, headSession, headRepo.OwnerName, headRepo.Name, "deleted-branch")
+
+ // only `new-commit` branch has commits ahead the base branch
+ checkRecentlyPushedNewBranches(t, headSession, headRepoPath, []string{"new-commit"})
+ if baseRepo.RepoPath() != headRepo.RepoPath() {
+ checkRecentlyPushedNewBranches(t, headSession, baseRepoPath, []string{fmt.Sprintf("%v:new-commit", headRepo.FullName())})
+ }
+
+ // Case 2: Create PR so that `new-commit` branch will not show
+ testCreatePullToDefaultBranch(t, headSession, baseRepo, headRepo, "new-commit", "merge new-commit to default branch")
+ // No push message show because of active PR
+ checkRecentlyPushedNewBranches(t, headSession, headRepoPath, []string{})
+ if baseRepo.RepoPath() != headRepo.RepoPath() {
+ checkRecentlyPushedNewBranches(t, headSession, baseRepoPath, []string{})
+ }
+}
+
+func prepareRecentlyPushedBranchSpecialTest(t *testing.T, session *TestSession, baseRepo, headRepo *repo_model.Repository) {
+ refSubURL := "branch/" + headRepo.DefaultBranch
+ baseRepoPath := baseRepo.OwnerName + "/" + baseRepo.Name
+ headRepoPath := headRepo.OwnerName + "/" + headRepo.Name
+ // create branch with no new commit
+ testCreateBranch(t, session, headRepo.OwnerName, headRepo.Name, refSubURL, "no-commit-special", http.StatusSeeOther)
+
+ // update base (default) branch before head branch is updated
+ testAPINewFile(t, session, baseRepo.OwnerName, baseRepo.Name, baseRepo.DefaultBranch, fmt.Sprintf("new-file-special-%s.txt", headRepo.Name), "new-commit")
- // create deleted branch
- testCreateBranch(t, session, repo.OwnerName, repo.Name, "branch/new-commit", "deleted-branch", http.StatusSeeOther)
- testUIDeleteBranch(t, session, repo.OwnerName, repo.Name, "deleted-branch")
+ // Though we have new `no-commit` branch, but the headBranch is not newer or commits ahead baseBranch. No message show.
+ checkRecentlyPushedNewBranches(t, session, headRepoPath, []string{})
+ if baseRepo.RepoPath() != headRepo.RepoPath() {
+ checkRecentlyPushedNewBranches(t, session, baseRepoPath, []string{})
+ }
}
func testCreatePullToDefaultBranch(t *testing.T, session *TestSession, baseRepo, headRepo *repo_model.Repository, headBranch, title string) string {
@@ -169,6 +196,9 @@ func testCreatePullToDefaultBranch(t *testing.T, session *TestSession, baseRepo,
}
func prepareRepoPR(t *testing.T, baseSession, headSession *TestSession, baseRepo, headRepo *repo_model.Repository) {
+ refSubURL := "branch/" + headRepo.DefaultBranch
+ testCreateBranch(t, headSession, headRepo.OwnerName, headRepo.Name, refSubURL, "new-commit", http.StatusSeeOther)
+
// create opening PR
testCreateBranch(t, headSession, headRepo.OwnerName, headRepo.Name, "branch/new-commit", "opening-pr", http.StatusSeeOther)
testCreatePullToDefaultBranch(t, baseSession, baseRepo, headRepo, "opening-pr", "opening pr")
@@ -210,65 +240,19 @@ func checkRecentlyPushedNewBranches(t *testing.T, session *TestSession, repoPath
func TestRecentlyPushedNewBranches(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) {
- user1Session := loginUser(t, "user1")
- user2Session := loginUser(t, "user2")
user12Session := loginUser(t, "user12")
- user13Session := loginUser(t, "user13")
- // prepare branch and PRs in original repo
+ // Same reposioty check
repo10 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10})
- prepareBranch(t, user12Session, repo10)
prepareRepoPR(t, user12Session, user12Session, repo10, repo10)
-
- // outdated new branch should not be displayed
- checkRecentlyPushedNewBranches(t, user12Session, "user12/repo10", []string{"new-commit"})
+ prepareRecentlyPushedBranchTest(t, user12Session, repo10, repo10)
+ prepareRecentlyPushedBranchSpecialTest(t, user12Session, repo10, repo10)
// create a fork repo in public org
- testRepoFork(t, user12Session, repo10.OwnerName, repo10.Name, "org25", "org25_fork_repo10", "new-commit")
+ testRepoFork(t, user12Session, repo10.OwnerName, repo10.Name, "org25", "org25_fork_repo10", repo10.DefaultBranch)
orgPublicForkRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: 25, Name: "org25_fork_repo10"})
prepareRepoPR(t, user12Session, user12Session, repo10, orgPublicForkRepo)
-
- // user12 is the owner of the repo10 and the organization org25
- // in repo10, user12 has opening/closed/merged pr and closed/merged pr with deleted branch
- checkRecentlyPushedNewBranches(t, user12Session, "user12/repo10", []string{"org25/org25_fork_repo10:new-commit", "new-commit"})
-
- userForkRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 11})
- testCtx := NewAPITestContext(t, repo10.OwnerName, repo10.Name, auth_model.AccessTokenScopeWriteRepository)
- t.Run("AddUser13AsCollaborator", doAPIAddCollaborator(testCtx, "user13", perm.AccessModeWrite))
- prepareBranch(t, user13Session, userForkRepo)
- prepareRepoPR(t, user13Session, user13Session, repo10, userForkRepo)
-
- // create branch with same name in different repo by user13
- testCreateBranch(t, user13Session, repo10.OwnerName, repo10.Name, "branch/new-commit", "same-name-branch", http.StatusSeeOther)
- testCreateBranch(t, user13Session, userForkRepo.OwnerName, userForkRepo.Name, "branch/new-commit", "same-name-branch", http.StatusSeeOther)
- testCreatePullToDefaultBranch(t, user13Session, repo10, userForkRepo, "same-name-branch", "same name branch pr")
-
- // user13 pushed 2 branches with the same name in repo10 and repo11
- // and repo11's branch has a pr, but repo10's branch doesn't
- // in this case, we should get repo10's branch but not repo11's branch
- checkRecentlyPushedNewBranches(t, user13Session, "user12/repo10", []string{"same-name-branch", "user13/repo11:new-commit"})
-
- // create a fork repo in private org
- testRepoFork(t, user1Session, repo10.OwnerName, repo10.Name, "private_org35", "org35_fork_repo10", "new-commit")
- orgPrivateForkRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: 35, Name: "org35_fork_repo10"})
- prepareRepoPR(t, user1Session, user1Session, repo10, orgPrivateForkRepo)
-
- // user1 is the owner of private_org35 and no write permission to repo10
- // so user1 can only see the branch in org35_fork_repo10
- checkRecentlyPushedNewBranches(t, user1Session, "user12/repo10", []string{"private_org35/org35_fork_repo10:new-commit"})
-
- // user2 push a branch in private_org35
- testCreateBranch(t, user2Session, orgPrivateForkRepo.OwnerName, orgPrivateForkRepo.Name, "branch/new-commit", "user-read-permission", http.StatusSeeOther)
- // convert write permission to read permission for code unit
- token := getTokenForLoggedInUser(t, user1Session, auth_model.AccessTokenScopeWriteOrganization)
- req := NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d", 24), &api.EditTeamOption{
- Name: "team24",
- UnitsMap: map[string]string{"repo.code": "read"},
- }).AddTokenAuth(token)
- MakeRequest(t, req, http.StatusOK)
- teamUnit := unittest.AssertExistsAndLoadBean(t, &org_model.TeamUnit{TeamID: 24, Type: unit.TypeCode})
- assert.Equal(t, perm.AccessModeRead, teamUnit.AccessMode)
- // user2 can see the branch as it is created by user2
- checkRecentlyPushedNewBranches(t, user2Session, "user12/repo10", []string{"private_org35/org35_fork_repo10:user-read-permission"})
+ prepareRecentlyPushedBranchTest(t, user12Session, repo10, orgPublicForkRepo)
+ prepareRecentlyPushedBranchSpecialTest(t, user12Session, repo10, orgPublicForkRepo)
})
}
diff --git a/tests/integration/repo_commits_search_test.go b/tests/integration/repo_commits_search_test.go
index 74ac25c0f5..9b05e36399 100644
--- a/tests/integration/repo_commits_search_test.go
+++ b/tests/integration/repo_commits_search_test.go
@@ -23,7 +23,7 @@ func testRepoCommitsSearch(t *testing.T, query, commit string) {
doc := NewHTMLParser(t, resp.Body)
sel := doc.doc.Find("#commits-table tbody tr td.sha a")
- assert.EqualValues(t, commit, strings.TrimSpace(sel.Text()))
+ assert.Equal(t, commit, strings.TrimSpace(sel.Text()))
}
func TestRepoCommitsSearch(t *testing.T) {
diff --git a/tests/integration/repo_commits_test.go b/tests/integration/repo_commits_test.go
index bb65d9e04a..b8f086e2b1 100644
--- a/tests/integration/repo_commits_test.go
+++ b/tests/integration/repo_commits_test.go
@@ -12,27 +12,71 @@ import (
"testing"
auth_model "code.gitea.io/gitea/models/auth"
+ "code.gitea.io/gitea/modules/commitstatus"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/tests"
+ "github.com/PuerkitoBio/goquery"
"github.com/stretchr/testify/assert"
)
func TestRepoCommits(t *testing.T) {
defer tests.PrepareTestEnv(t)()
-
session := loginUser(t, "user2")
- // Request repository commits page
- req := NewRequest(t, "GET", "/user2/repo1/commits/branch/master")
- resp := session.MakeRequest(t, req, http.StatusOK)
-
- doc := NewHTMLParser(t, resp.Body)
- commitURL, exists := doc.doc.Find("#commits-table tbody tr td.sha a").Attr("href")
- assert.True(t, exists)
- assert.NotEmpty(t, commitURL)
+ t.Run("CommitList", func(t *testing.T) {
+ req := NewRequest(t, "GET", "/user2/repo16/commits/branch/master")
+ resp := session.MakeRequest(t, req, http.StatusOK)
+
+ var commits, userHrefs []string
+ doc := NewHTMLParser(t, resp.Body)
+ doc.doc.Find("#commits-table .commit-id-short").Each(func(i int, s *goquery.Selection) {
+ commits = append(commits, path.Base(s.AttrOr("href", "")))
+ })
+ doc.doc.Find("#commits-table .author-wrapper").Each(func(i int, s *goquery.Selection) {
+ userHrefs = append(userHrefs, s.AttrOr("href", ""))
+ })
+ assert.Equal(t, []string{"69554a64c1e6030f051e5c3f94bfbd773cd6a324", "27566bd5738fc8b4e3fef3c5e72cce608537bd95", "5099b81332712fe655e34e8dd63574f503f61811"}, commits)
+ assert.Equal(t, []string{"/user2", "/user21", "/user2"}, userHrefs)
+ })
+
+ t.Run("LastCommit", func(t *testing.T) {
+ req := NewRequest(t, "GET", "/user2/repo16")
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ doc := NewHTMLParser(t, resp.Body)
+ commitHref := doc.doc.Find(".latest-commit .commit-id-short").AttrOr("href", "")
+ authorHref := doc.doc.Find(".latest-commit .author-wrapper").AttrOr("href", "")
+ assert.Equal(t, "/user2/repo16/commit/69554a64c1e6030f051e5c3f94bfbd773cd6a324", commitHref)
+ assert.Equal(t, "/user2", authorHref)
+ })
+
+ t.Run("CommitListNonExistingCommiter", func(t *testing.T) {
+ // check the commit list for a repository with no gitea user
+ // * commit 985f0301dba5e7b34be866819cd15ad3d8f508ee (branch2)
+ // * Author: 6543 <6543@obermui.de>
+ req := NewRequest(t, "GET", "/user2/repo1/commits/branch/branch2")
+ resp := session.MakeRequest(t, req, http.StatusOK)
+
+ doc := NewHTMLParser(t, resp.Body)
+ commitHref := doc.doc.Find("#commits-table tr:first-child .commit-id-short").AttrOr("href", "")
+ assert.Equal(t, "/user2/repo1/commit/985f0301dba5e7b34be866819cd15ad3d8f508ee", commitHref)
+ authorElem := doc.doc.Find("#commits-table tr:first-child .author-wrapper")
+ assert.Equal(t, "6543", authorElem.Text())
+ assert.Equal(t, "span", authorElem.Nodes[0].Data)
+ })
+
+ t.Run("LastCommitNonExistingCommiter", func(t *testing.T) {
+ req := NewRequest(t, "GET", "/user2/repo1/src/branch/branch2")
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ doc := NewHTMLParser(t, resp.Body)
+ commitHref := doc.doc.Find(".latest-commit .commit-id-short").AttrOr("href", "")
+ assert.Equal(t, "/user2/repo1/commit/985f0301dba5e7b34be866819cd15ad3d8f508ee", commitHref)
+ authorElem := doc.doc.Find(".latest-commit .author-wrapper")
+ assert.Equal(t, "6543", authorElem.Text())
+ assert.Equal(t, "span", authorElem.Nodes[0].Data)
+ })
}
func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
@@ -46,14 +90,14 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
doc := NewHTMLParser(t, resp.Body)
// Get first commit URL
- commitURL, exists := doc.doc.Find("#commits-table tbody tr td.sha a").Attr("href")
+ commitURL, exists := doc.doc.Find("#commits-table .commit-id-short").Attr("href")
assert.True(t, exists)
assert.NotEmpty(t, commitURL)
// Call API to add status for commit
ctx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository)
t.Run("CreateStatus", doAPICreateCommitStatus(ctx, path.Base(commitURL), api.CreateStatusOption{
- State: api.CommitStatusState(state),
+ State: commitstatus.CommitStatusState(state),
TargetURL: "http://test.ci/",
Description: "",
Context: "testci",
@@ -64,7 +108,7 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
doc = NewHTMLParser(t, resp.Body)
// Check if commit status is displayed in message column (.tippy-target to ignore the tippy trigger)
- sel := doc.doc.Find("#commits-table tbody tr td.message .tippy-target .commit-status")
+ sel := doc.doc.Find("#commits-table .message .tippy-target .commit-status")
assert.Equal(t, 1, sel.Length())
for _, class := range classes {
assert.True(t, sel.HasClass(class))
@@ -97,10 +141,10 @@ func testRepoCommitsWithStatus(t *testing.T, resp, respOne *httptest.ResponseRec
assert.NotNil(t, status)
if assert.Len(t, statuses, 1) {
- assert.Equal(t, api.CommitStatusState(state), statuses[0].State)
+ assert.Equal(t, commitstatus.CommitStatusState(state), statuses[0].State)
assert.Equal(t, setting.AppURL+"api/v1/repos/user2/repo1/statuses/65f1bf27bc3bf70f64657658635e66094edbcb4d", statuses[0].URL)
assert.Equal(t, "http://test.ci/", statuses[0].TargetURL)
- assert.Equal(t, "", statuses[0].Description)
+ assert.Empty(t, statuses[0].Description)
assert.Equal(t, "testci", statuses[0].Context)
assert.Len(t, status.Statuses, 1)
@@ -140,18 +184,18 @@ func TestRepoCommitsStatusParallel(t *testing.T) {
doc := NewHTMLParser(t, resp.Body)
// Get first commit URL
- commitURL, exists := doc.doc.Find("#commits-table tbody tr td.sha a").Attr("href")
+ commitURL, exists := doc.doc.Find("#commits-table .commit-id-short").Attr("href")
assert.True(t, exists)
assert.NotEmpty(t, commitURL)
var wg sync.WaitGroup
- for i := 0; i < 10; i++ {
+ for i := range 10 {
wg.Add(1)
go func(parentT *testing.T, i int) {
parentT.Run(fmt.Sprintf("ParallelCreateStatus_%d", i), func(t *testing.T) {
ctx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository)
runBody := doAPICreateCommitStatus(ctx, path.Base(commitURL), api.CreateStatusOption{
- State: api.CommitStatusPending,
+ State: commitstatus.CommitStatusPending,
TargetURL: "http://test.ci/",
Description: "",
Context: "testci",
@@ -175,21 +219,21 @@ func TestRepoCommitsStatusMultiple(t *testing.T) {
doc := NewHTMLParser(t, resp.Body)
// Get first commit URL
- commitURL, exists := doc.doc.Find("#commits-table tbody tr td.sha a").Attr("href")
+ commitURL, exists := doc.doc.Find("#commits-table .commit-id-short").Attr("href")
assert.True(t, exists)
assert.NotEmpty(t, commitURL)
// Call API to add status for commit
ctx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository)
t.Run("CreateStatus", doAPICreateCommitStatus(ctx, path.Base(commitURL), api.CreateStatusOption{
- State: api.CommitStatusSuccess,
+ State: commitstatus.CommitStatusSuccess,
TargetURL: "http://test.ci/",
Description: "",
Context: "testci",
}))
t.Run("CreateStatus", doAPICreateCommitStatus(ctx, path.Base(commitURL), api.CreateStatusOption{
- State: api.CommitStatusSuccess,
+ State: commitstatus.CommitStatusSuccess,
TargetURL: "http://test.ci/",
Description: "",
Context: "other_context",
@@ -199,7 +243,7 @@ func TestRepoCommitsStatusMultiple(t *testing.T) {
resp = session.MakeRequest(t, req, http.StatusOK)
doc = NewHTMLParser(t, resp.Body)
- // Check that the data-tippy="commit-statuses" (for trigger) and commit-status (svg) are present
- sel := doc.doc.Find("#commits-table tbody tr td.message [data-tippy=\"commit-statuses\"] .commit-status")
+ // Check that the data-global-init="initCommitStatuses" (for trigger) and commit-status (svg) are present
+ sel := doc.doc.Find(`#commits-table .message [data-global-init="initCommitStatuses"] .commit-status`)
assert.Equal(t, 1, sel.Length())
}
diff --git a/tests/integration/repo_fork_test.go b/tests/integration/repo_fork_test.go
index 267fd0d56e..95325eefeb 100644
--- a/tests/integration/repo_fork_test.go
+++ b/tests/integration/repo_fork_test.go
@@ -7,6 +7,7 @@ import (
"fmt"
"net/http"
"net/http/httptest"
+ "strconv"
"testing"
"code.gitea.io/gitea/models/db"
@@ -14,6 +15,7 @@ import (
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/test"
org_service "code.gitea.io/gitea/services/org"
"code.gitea.io/gitea/tests"
@@ -46,11 +48,12 @@ func testRepoFork(t *testing.T, session *TestSession, ownerName, repoName, forkO
assert.True(t, exists, "Fork owner '%s' is not present in select box", forkOwnerName)
req = NewRequestWithValues(t, "POST", link, map[string]string{
"_csrf": htmlDoc.GetCSRF(),
- "uid": fmt.Sprintf("%d", forkOwner.ID),
+ "uid": strconv.FormatInt(forkOwner.ID, 10),
"repo_name": forkRepoName,
"fork_single_branch": forkBranch,
})
- session.MakeRequest(t, req, http.StatusSeeOther)
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ assert.Equal(t, fmt.Sprintf("/%s/%s", forkOwnerName, forkRepoName), test.RedirectURL(resp))
// Step4: check the existence of the forked repo
req = NewRequestf(t, "GET", "/%s/%s", forkOwnerName, forkRepoName)
@@ -81,14 +84,14 @@ func TestRepoForkToOrg(t *testing.T) {
func TestForkListLimitedAndPrivateRepos(t *testing.T) {
defer tests.PrepareTestEnv(t)()
- forkItemSelector := ".repo-fork-item"
+ forkItemSelector := ".fork-list .flex-item"
user1Sess := loginUser(t, "user1")
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user1"})
// fork to a limited org
limitedOrg := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 22})
- assert.EqualValues(t, structs.VisibleTypeLimited, limitedOrg.Visibility)
+ assert.Equal(t, structs.VisibleTypeLimited, limitedOrg.Visibility)
ownerTeam1, err := org_model.OrgFromUser(limitedOrg).GetOwnerTeam(db.DefaultContext)
assert.NoError(t, err)
assert.NoError(t, org_service.AddTeamMember(db.DefaultContext, ownerTeam1, user1))
@@ -98,7 +101,7 @@ func TestForkListLimitedAndPrivateRepos(t *testing.T) {
user4Sess := loginUser(t, "user4")
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user4"})
privateOrg := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 23})
- assert.EqualValues(t, structs.VisibleTypePrivate, privateOrg.Visibility)
+ assert.Equal(t, structs.VisibleTypePrivate, privateOrg.Visibility)
ownerTeam2, err := org_model.OrgFromUser(privateOrg).GetOwnerTeam(db.DefaultContext)
assert.NoError(t, err)
assert.NoError(t, org_service.AddTeamMember(db.DefaultContext, ownerTeam2, user4))
@@ -109,7 +112,7 @@ func TestForkListLimitedAndPrivateRepos(t *testing.T) {
req := NewRequest(t, "GET", "/user2/repo1/forks")
resp := MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
- assert.EqualValues(t, 0, htmlDoc.Find(forkItemSelector).Length())
+ assert.Equal(t, 0, htmlDoc.Find(forkItemSelector).Length())
})
t.Run("Logged in", func(t *testing.T) {
@@ -118,11 +121,12 @@ func TestForkListLimitedAndPrivateRepos(t *testing.T) {
req := NewRequest(t, "GET", "/user2/repo1/forks")
resp := user1Sess.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
- assert.EqualValues(t, 1, htmlDoc.Find(forkItemSelector).Length())
+ // since user1 is an admin, he can get both of the forked repositories
+ assert.Equal(t, 2, htmlDoc.Find(forkItemSelector).Length())
assert.NoError(t, org_service.AddTeamMember(db.DefaultContext, ownerTeam2, user1))
resp = user1Sess.MakeRequest(t, req, http.StatusOK)
htmlDoc = NewHTMLParser(t, resp.Body)
- assert.EqualValues(t, 2, htmlDoc.Find(forkItemSelector).Length())
+ assert.Equal(t, 2, htmlDoc.Find(forkItemSelector).Length())
})
}
diff --git a/tests/integration/repo_generate_test.go b/tests/integration/repo_generate_test.go
index ff2aa220d3..fca4e92982 100644
--- a/tests/integration/repo_generate_test.go
+++ b/tests/integration/repo_generate_test.go
@@ -7,6 +7,7 @@ import (
"fmt"
"net/http"
"net/http/httptest"
+ "strconv"
"strings"
"testing"
@@ -31,20 +32,20 @@ func testRepoGenerate(t *testing.T, session *TestSession, templateID, templateOw
// Step2: click the "Use this template" button
htmlDoc := NewHTMLParser(t, resp.Body)
- link, exists := htmlDoc.doc.Find("a.ui.button[href^=\"/repo/create\"]").Attr("href")
+ link, exists := htmlDoc.doc.Find(`a.ui.button[href^="/repo/create"]`).Attr("href")
assert.True(t, exists, "The template has changed")
req = NewRequest(t, "GET", link)
resp = session.MakeRequest(t, req, http.StatusOK)
- // Step3: fill the form of the create
+ // Step3: fill the form on the "create" page
htmlDoc = NewHTMLParser(t, resp.Body)
- link, exists = htmlDoc.doc.Find("form.ui.form[action^=\"/repo/create\"]").Attr("action")
+ link, exists = htmlDoc.doc.Find(`form.ui.form[action^="/repo/create"]`).Attr("action")
assert.True(t, exists, "The template has changed")
- _, exists = htmlDoc.doc.Find(fmt.Sprintf(".owner.dropdown .item[data-value=\"%d\"]", generateOwner.ID)).Attr("data-value")
+ _, exists = htmlDoc.doc.Find(fmt.Sprintf(`#repo_owner_dropdown .item[data-value="%d"]`, generateOwner.ID)).Attr("data-value")
assert.True(t, exists, "Generate owner '%s' is not present in select box", generateOwnerName)
req = NewRequestWithValues(t, "POST", link, map[string]string{
"_csrf": htmlDoc.GetCSRF(),
- "uid": fmt.Sprintf("%d", generateOwner.ID),
+ "uid": strconv.FormatInt(generateOwner.ID, 10),
"repo_name": generateRepoName,
"repo_template": templateID,
"git_content": "true",
diff --git a/tests/integration/repo_merge_upstream_test.go b/tests/integration/repo_merge_upstream_test.go
new file mode 100644
index 0000000000..d33d31c646
--- /dev/null
+++ b/tests/integration/repo_merge_upstream_test.go
@@ -0,0 +1,183 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package integration
+
+import (
+ "fmt"
+ "net/http"
+ "net/url"
+ "strings"
+ "testing"
+ "time"
+
+ auth_model "code.gitea.io/gitea/models/auth"
+ "code.gitea.io/gitea/models/db"
+ git_model "code.gitea.io/gitea/models/git"
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
+ api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/util"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestRepoMergeUpstream(t *testing.T) {
+ onGiteaRun(t, func(*testing.T, *url.URL) {
+ forkUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
+
+ baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+ baseUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: baseRepo.OwnerID})
+
+ checkFileContent := func(branch, exp string) {
+ req := NewRequest(t, "GET", fmt.Sprintf("/%s/test-repo-fork/raw/branch/%s/new-file.txt", forkUser.Name, branch))
+ resp := MakeRequest(t, req, http.StatusOK)
+ require.Equal(t, exp, resp.Body.String())
+ }
+
+ session := loginUser(t, forkUser.Name)
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+
+ // create a fork
+ req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/forks", baseUser.Name, baseRepo.Name), &api.CreateForkOption{
+ Name: util.ToPointer("test-repo-fork"),
+ }).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusAccepted)
+ forkRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: forkUser.ID, Name: "test-repo-fork"})
+
+ // create fork-branch
+ req = NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/test-repo-fork/branches/_new/branch/master", forkUser.Name), map[string]string{
+ "_csrf": GetUserCSRFToken(t, session),
+ "new_branch_name": "fork-branch",
+ })
+ session.MakeRequest(t, req, http.StatusSeeOther)
+
+ queryMergeUpstreamButtonLink := func(htmlDoc *HTMLDoc) string {
+ return htmlDoc.Find(`button[data-url*="merge-upstream"]`).AttrOr("data-url", "")
+ }
+
+ t.Run("HeadBeforeBase", func(t *testing.T) {
+ // add a file in base repo
+ sessionBaseUser := loginUser(t, baseUser.Name)
+ require.NoError(t, createOrReplaceFileInBranch(baseUser, baseRepo, "new-file.txt", "master", "test-content-1"))
+
+ var mergeUpstreamLink string
+ t.Run("DetectDefaultBranch", func(t *testing.T) {
+ // the repo shows a prompt to "sync fork" (defaults to the default branch)
+ require.Eventually(t, func() bool {
+ resp := session.MakeRequest(t, NewRequestf(t, "GET", "/%s/test-repo-fork/src/branch/fork-branch", forkUser.Name), http.StatusOK)
+ htmlDoc := NewHTMLParser(t, resp.Body)
+ mergeUpstreamLink = queryMergeUpstreamButtonLink(htmlDoc)
+ if mergeUpstreamLink == "" {
+ return false
+ }
+ respMsg, _ := htmlDoc.Find(".ui.message:not(.positive)").Html()
+ return strings.Contains(respMsg, `This branch is 1 commit behind <a href="/user2/repo1/src/branch/master">user2/repo1:master</a>`)
+ }, 5*time.Second, 100*time.Millisecond)
+ })
+
+ t.Run("DetectSameBranch", func(t *testing.T) {
+ // if the fork-branch name also exists in the base repo, then use that branch instead
+ req = NewRequestWithValues(t, "POST", "/user2/repo1/branches/_new/branch/master", map[string]string{
+ "_csrf": GetUserCSRFToken(t, sessionBaseUser),
+ "new_branch_name": "fork-branch",
+ })
+ sessionBaseUser.MakeRequest(t, req, http.StatusSeeOther)
+
+ require.Eventually(t, func() bool {
+ resp := session.MakeRequest(t, NewRequestf(t, "GET", "/%s/test-repo-fork/src/branch/fork-branch", forkUser.Name), http.StatusOK)
+ htmlDoc := NewHTMLParser(t, resp.Body)
+ mergeUpstreamLink = queryMergeUpstreamButtonLink(htmlDoc)
+ if mergeUpstreamLink == "" {
+ return false
+ }
+ respMsg, _ := htmlDoc.Find(".ui.message:not(.positive)").Html()
+ return strings.Contains(respMsg, `This branch is 1 commit behind <a href="/user2/repo1/src/branch/fork-branch">user2/repo1:fork-branch</a>`)
+ }, 5*time.Second, 100*time.Millisecond)
+ })
+
+ // click the "sync fork" button
+ req = NewRequestWithValues(t, "POST", mergeUpstreamLink, map[string]string{"_csrf": GetUserCSRFToken(t, session)})
+ session.MakeRequest(t, req, http.StatusOK)
+ checkFileContent("fork-branch", "test-content-1")
+
+ // delete the "fork-branch" from the base repo
+ req = NewRequestWithValues(t, "POST", "/user2/repo1/branches/delete?name=fork-branch", map[string]string{
+ "_csrf": GetUserCSRFToken(t, sessionBaseUser),
+ })
+ sessionBaseUser.MakeRequest(t, req, http.StatusOK)
+ })
+
+ t.Run("BaseChangeAfterHeadChange", func(t *testing.T) {
+ // update the files: base first, head later, and check the prompt
+ require.NoError(t, createOrReplaceFileInBranch(baseUser, baseRepo, "new-file.txt", "master", "test-content-2"))
+ require.NoError(t, createOrReplaceFileInBranch(forkUser, forkRepo, "new-file-other.txt", "fork-branch", "test-content-other"))
+
+ // make sure the base branch's update time is before the fork, to make it test the complete logic
+ baseBranch := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: baseRepo.ID, Name: "master"})
+ forkBranch := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: forkRepo.ID, Name: "fork-branch"})
+ _, err := db.GetEngine(db.DefaultContext).ID(forkBranch.ID).Update(&git_model.Branch{UpdatedUnix: baseBranch.UpdatedUnix + 1})
+ require.NoError(t, err)
+
+ // the repo shows a prompt to "sync fork"
+ require.Eventually(t, func() bool {
+ resp := session.MakeRequest(t, NewRequestf(t, "GET", "/%s/test-repo-fork/src/branch/fork-branch", forkUser.Name), http.StatusOK)
+ htmlDoc := NewHTMLParser(t, resp.Body)
+ respMsg, _ := htmlDoc.Find(".ui.message:not(.positive)").Html()
+ return strings.Contains(respMsg, `The base branch <a href="/user2/repo1/src/branch/master">user2/repo1:master</a> has new changes`)
+ }, 5*time.Second, 100*time.Millisecond)
+
+ // and do the merge-upstream by API
+ req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/test-repo-fork/merge-upstream", forkUser.Name), &api.MergeUpstreamRequest{
+ Branch: "fork-branch",
+ }).AddTokenAuth(token)
+ resp := MakeRequest(t, req, http.StatusOK)
+ checkFileContent("fork-branch", "test-content-2")
+
+ var mergeResp api.MergeUpstreamResponse
+ DecodeJSON(t, resp, &mergeResp)
+ assert.Equal(t, "merge", mergeResp.MergeStyle)
+
+ // after merge, there should be no "sync fork" button anymore
+ require.Eventually(t, func() bool {
+ resp := session.MakeRequest(t, NewRequestf(t, "GET", "/%s/test-repo-fork/src/branch/fork-branch", forkUser.Name), http.StatusOK)
+ htmlDoc := NewHTMLParser(t, resp.Body)
+ return queryMergeUpstreamButtonLink(htmlDoc) == ""
+ }, 5*time.Second, 100*time.Millisecond)
+ })
+
+ t.Run("FastForwardOnly", func(t *testing.T) {
+ // Create a clean branch for fast-forward testing
+ req = NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/test-repo-fork/branches/_new/branch/master", forkUser.Name), map[string]string{
+ "_csrf": GetUserCSRFToken(t, session),
+ "new_branch_name": "ff-test-branch",
+ })
+ session.MakeRequest(t, req, http.StatusSeeOther)
+
+ // Add content to base repository that can be fast-forwarded
+ require.NoError(t, createOrReplaceFileInBranch(baseUser, baseRepo, "ff-test.txt", "master", "ff-content-1"))
+
+ // ff_only=true with fast-forward possible (should succeed)
+ req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/test-repo-fork/merge-upstream", forkUser.Name), &api.MergeUpstreamRequest{
+ Branch: "ff-test-branch",
+ FfOnly: true,
+ }).AddTokenAuth(token)
+ resp := MakeRequest(t, req, http.StatusOK)
+
+ var mergeResp api.MergeUpstreamResponse
+ DecodeJSON(t, resp, &mergeResp)
+ assert.Equal(t, "fast-forward", mergeResp.MergeStyle)
+
+ // ff_only=true when fast-forward is not possible (should fail)
+ require.NoError(t, createOrReplaceFileInBranch(baseUser, baseRepo, "another-file.txt", "master", "more-content"))
+
+ req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/test-repo-fork/merge-upstream", forkUser.Name), &api.MergeUpstreamRequest{
+ Branch: "fork-branch",
+ FfOnly: true,
+ }).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusBadRequest)
+ })
+ })
+}
diff --git a/tests/integration/repo_mergecommit_revert_test.go b/tests/integration/repo_mergecommit_revert_test.go
deleted file mode 100644
index 103fb47e2b..0000000000
--- a/tests/integration/repo_mergecommit_revert_test.go
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2024 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package integration
-
-import (
- "net/http"
- "testing"
-
- "code.gitea.io/gitea/tests"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestRepoMergeCommitRevert(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
- session := loginUser(t, "user2")
-
- req := NewRequest(t, "GET", "/user2/test_commit_revert/_cherrypick/deebcbc752e540bab4ce3ee713d3fc8fdc35b2f7/main?ref=main&refType=branch&cherry-pick-type=revert")
- resp := session.MakeRequest(t, req, http.StatusOK)
-
- htmlDoc := NewHTMLParser(t, resp.Body)
- req = NewRequestWithValues(t, "POST", "/user2/test_commit_revert/_cherrypick/deebcbc752e540bab4ce3ee713d3fc8fdc35b2f7/main", map[string]string{
- "_csrf": htmlDoc.GetCSRF(),
- "last_commit": "deebcbc752e540bab4ce3ee713d3fc8fdc35b2f7",
- "page_has_posted": "true",
- "revert": "true",
- "commit_summary": "reverting test commit",
- "commit_message": "test message",
- "commit_choice": "direct",
- "new_branch_name": "test-revert-branch-1",
- })
- resp = session.MakeRequest(t, req, http.StatusSeeOther)
-
- // A successful revert redirects to the main branch
- assert.EqualValues(t, "/user2/test_commit_revert/src/branch/main", resp.Header().Get("Location"))
-}
diff --git a/tests/integration/repo_search_test.go b/tests/integration/repo_search_test.go
index 29d1517f4e..36a2e81f3b 100644
--- a/tests/integration/repo_search_test.go
+++ b/tests/integration/repo_search_test.go
@@ -57,5 +57,5 @@ func testSearch(t *testing.T, url string, expected []string) {
resp := MakeRequest(t, req, http.StatusOK)
filenames := resultFilenames(NewHTMLParser(t, resp.Body))
- assert.EqualValues(t, expected, filenames)
+ assert.Equal(t, expected, filenames)
}
diff --git a/tests/integration/repo_tag_test.go b/tests/integration/repo_tag_test.go
index 5638826ea0..8ea7508559 100644
--- a/tests/integration/repo_tag_test.go
+++ b/tests/integration/repo_tag_test.go
@@ -55,10 +55,10 @@ func TestCreateNewTagProtected(t *testing.T) {
doGitClone(dstPath, u)(t)
- _, _, err := git.NewCommand(git.DefaultContext, "tag", "v-2").RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, err := git.NewCommand("tag", "v-2").RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
- _, _, err = git.NewCommand(git.DefaultContext, "push", "--tags").RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, err = git.NewCommand("push", "--tags").RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.Error(t, err)
assert.Contains(t, err.Error(), "Tag v-2 is protected")
})
@@ -75,20 +75,20 @@ func TestCreateNewTagProtected(t *testing.T) {
doGitClone(dstPath, u)(t)
- _, _, err := git.NewCommand(git.DefaultContext, "tag", "v-1.1", "-m", "force update", "--force").RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, err := git.NewCommand("tag", "v-1.1", "-m", "force update", "--force").RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
require.NoError(t, err)
- _, _, err = git.NewCommand(git.DefaultContext, "push", "--tags").RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, err = git.NewCommand("push", "--tags").RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
require.NoError(t, err)
- _, _, err = git.NewCommand(git.DefaultContext, "tag", "v-1.1", "-m", "force update v2", "--force").RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, err = git.NewCommand("tag", "v-1.1", "-m", "force update v2", "--force").RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
require.NoError(t, err)
- _, _, err = git.NewCommand(git.DefaultContext, "push", "--tags").RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, err = git.NewCommand("push", "--tags").RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
require.Error(t, err)
assert.Contains(t, err.Error(), "the tag already exists in the remote")
- _, _, err = git.NewCommand(git.DefaultContext, "push", "--tags", "--force").RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, err = git.NewCommand("push", "--tags", "--force").RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
require.NoError(t, err)
req := NewRequestf(t, "GET", "/%s/releases/tag/v-1.1", repo.FullName())
resp := MakeRequest(t, req, http.StatusOK)
@@ -137,15 +137,15 @@ func TestRepushTag(t *testing.T) {
doGitClone(dstPath, u)(t)
// create and push a tag
- _, _, err := git.NewCommand(git.DefaultContext, "tag", "v2.0").RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, err := git.NewCommand("tag", "v2.0").RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
- _, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "--tags", "v2.0").RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, err = git.NewCommand("push", "origin", "--tags", "v2.0").RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
// create a release for the tag
createdRelease := createNewReleaseUsingAPI(t, token, owner, repo, "v2.0", "", "Release of v2.0", "desc")
assert.False(t, createdRelease.IsDraft)
// delete the tag
- _, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "--delete", "v2.0").RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, err = git.NewCommand("push", "origin", "--delete", "v2.0").RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
// query the release by API and it should be a draft
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/releases/tags/%s", owner.Name, repo.Name, "v2.0"))
@@ -154,7 +154,7 @@ func TestRepushTag(t *testing.T) {
DecodeJSON(t, resp, &respRelease)
assert.True(t, respRelease.IsDraft)
// re-push the tag
- _, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "--tags", "v2.0").RunStdString(&git.RunOpts{Dir: dstPath})
+ _, _, err = git.NewCommand("push", "origin", "--tags", "v2.0").RunStdString(git.DefaultContext, &git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
// query the release by API and it should not be a draft
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/releases/tags/%s", owner.Name, repo.Name, "v2.0"))
diff --git a/tests/integration/repo_test.go b/tests/integration/repo_test.go
index 8c568a1272..adfe07519f 100644
--- a/tests/integration/repo_test.go
+++ b/tests/integration/repo_test.go
@@ -6,21 +6,51 @@ package integration
import (
"fmt"
"net/http"
+ "os"
"path"
+ "strconv"
"strings"
"testing"
"time"
+ "code.gitea.io/gitea/models/db"
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unit"
+ "code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
+ "code.gitea.io/gitea/modules/util"
+ repo_service "code.gitea.io/gitea/services/repository"
"code.gitea.io/gitea/tests"
"github.com/PuerkitoBio/goquery"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
-func TestViewRepo(t *testing.T) {
+func TestRepoView(t *testing.T) {
defer tests.PrepareTestEnv(t)()
+ t.Run("ViewRepoPublic", testViewRepoPublic)
+ t.Run("ViewRepoWithCache", testViewRepoWithCache)
+ t.Run("ViewRepoPrivate", testViewRepoPrivate)
+ t.Run("ViewRepo1CloneLinkAnonymous", testViewRepo1CloneLinkAnonymous)
+ t.Run("ViewRepo1CloneLinkAuthorized", testViewRepo1CloneLinkAuthorized)
+ t.Run("ViewRepoWithSymlinks", testViewRepoWithSymlinks)
+ t.Run("ViewFileInRepo", testViewFileInRepo)
+ t.Run("BlameFileInRepo", testBlameFileInRepo)
+ t.Run("ViewRepoDirectory", testViewRepoDirectory)
+ t.Run("ViewRepoDirectoryReadme", testViewRepoDirectoryReadme)
+ t.Run("ViewRepoSymlink", testViewRepoSymlink)
+ t.Run("MarkDownReadmeImage", testMarkDownReadmeImage)
+ t.Run("MarkDownReadmeImageSubfolder", testMarkDownReadmeImageSubfolder)
+ t.Run("GeneratedSourceLink", testGeneratedSourceLink)
+ t.Run("ViewCommit", testViewCommit)
+}
+
+func testViewRepoPublic(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
session := loginUser(t, "user2")
@@ -41,87 +71,118 @@ func TestViewRepo(t *testing.T) {
session.MakeRequest(t, req, http.StatusNotFound)
}
-func testViewRepo(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
-
- req := NewRequest(t, "GET", "/org3/repo3")
- session := loginUser(t, "user2")
- resp := session.MakeRequest(t, req, http.StatusOK)
-
- htmlDoc := NewHTMLParser(t, resp.Body)
- files := htmlDoc.doc.Find("#repo-files-table .repo-file-item")
-
- type file struct {
- fileName string
- commitID string
- commitMsg string
- commitTime string
- }
+func testViewRepoWithCache(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+ testView := func(t *testing.T) {
+ req := NewRequest(t, "GET", "/org3/repo3")
+ session := loginUser(t, "user2")
+ resp := session.MakeRequest(t, req, http.StatusOK)
- var items []file
-
- files.Each(func(i int, s *goquery.Selection) {
- tds := s.Find(".repo-file-cell")
- var f file
- tds.Each(func(i int, s *goquery.Selection) {
- if i == 0 {
- f.fileName = strings.TrimSpace(s.Text())
- } else if i == 1 {
- a := s.Find("a")
- f.commitMsg = strings.TrimSpace(a.Text())
- l, _ := a.Attr("href")
- f.commitID = path.Base(l)
- }
+ htmlDoc := NewHTMLParser(t, resp.Body)
+ files := htmlDoc.doc.Find("#repo-files-table .repo-file-item")
+
+ type file struct {
+ fileName string
+ commitID string
+ commitMsg string
+ commitTime string
+ }
+
+ var items []file
+
+ files.Each(func(i int, s *goquery.Selection) {
+ tds := s.Find(".repo-file-cell")
+ var f file
+ tds.Each(func(i int, s *goquery.Selection) {
+ if i == 0 {
+ f.fileName = strings.TrimSpace(s.Text())
+ } else if i == 1 {
+ a := s.Find("a")
+ f.commitMsg = strings.TrimSpace(a.Text())
+ l, _ := a.Attr("href")
+ f.commitID = path.Base(l)
+ }
+ })
+
+ // convert "2017-06-14 21:54:21 +0800" to "Wed, 14 Jun 2017 13:54:21 UTC"
+ htmlTimeString, _ := s.Find("relative-time").Attr("datetime")
+ htmlTime, _ := time.Parse(time.RFC3339, htmlTimeString)
+ f.commitTime = htmlTime.In(time.Local).Format(time.RFC1123)
+ items = append(items, f)
})
- // convert "2017-06-14 21:54:21 +0800" to "Wed, 14 Jun 2017 13:54:21 UTC"
- htmlTimeString, _ := s.Find("relative-time").Attr("datetime")
- htmlTime, _ := time.Parse(time.RFC3339, htmlTimeString)
- f.commitTime = htmlTime.In(time.Local).Format(time.RFC1123)
- items = append(items, f)
- })
-
- commitT := time.Date(2017, time.June, 14, 13, 54, 21, 0, time.UTC).In(time.Local).Format(time.RFC1123)
- assert.EqualValues(t, []file{
- {
- fileName: "doc",
- commitID: "2a47ca4b614a9f5a43abbd5ad851a54a616ffee6",
- commitMsg: "init project",
- commitTime: commitT,
- },
- {
- fileName: "README.md",
- commitID: "2a47ca4b614a9f5a43abbd5ad851a54a616ffee6",
- commitMsg: "init project",
- commitTime: commitT,
- },
- }, items)
-}
+ commitT := time.Date(2017, time.June, 14, 13, 54, 21, 0, time.UTC).In(time.Local).Format(time.RFC1123)
+ assert.Equal(t, []file{
+ {
+ fileName: "doc",
+ commitID: "2a47ca4b614a9f5a43abbd5ad851a54a616ffee6",
+ commitMsg: "init project",
+ commitTime: commitT,
+ },
+ {
+ fileName: "README.md",
+ commitID: "2a47ca4b614a9f5a43abbd5ad851a54a616ffee6",
+ commitMsg: "init project",
+ commitTime: commitT,
+ },
+ }, items)
+ }
-func TestViewRepo2(t *testing.T) {
+ // FIXME: these test don't seem quite right, no enough assert
// no last commit cache
- testViewRepo(t)
-
+ testView(t)
// enable last commit cache for all repositories
oldCommitsCount := setting.CacheService.LastCommit.CommitsCount
setting.CacheService.LastCommit.CommitsCount = 0
// first view will not hit the cache
- testViewRepo(t)
+ testView(t)
// second view will hit the cache
- testViewRepo(t)
+ testView(t)
setting.CacheService.LastCommit.CommitsCount = oldCommitsCount
}
-func TestViewRepo3(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
+func testViewRepoPrivate(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
req := NewRequest(t, "GET", "/org3/repo3")
- session := loginUser(t, "user4")
- session.MakeRequest(t, req, http.StatusOK)
+ MakeRequest(t, req, http.StatusNotFound)
+
+ t.Run("OrgMemberAccess", func(t *testing.T) {
+ req = NewRequest(t, "GET", "/org3/repo3")
+ session := loginUser(t, "user4")
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ assert.Contains(t, resp.Body.String(), `<div id="repo-files-table"`)
+ })
+
+ t.Run("PublicAccess-AnonymousAccess", func(t *testing.T) {
+ session := loginUser(t, "user1")
+
+ // set unit code to "anonymous read"
+ req = NewRequestWithValues(t, "POST", "/org3/repo3/settings/public_access", map[string]string{
+ "_csrf": GetUserCSRFToken(t, session),
+ "repo-unit-access-" + strconv.Itoa(int(unit.TypeCode)): "anonymous-read",
+ })
+ session.MakeRequest(t, req, http.StatusSeeOther)
+
+ // try to "anonymous read" (ok)
+ req = NewRequest(t, "GET", "/org3/repo3")
+ resp := MakeRequest(t, req, http.StatusOK)
+ assert.Contains(t, resp.Body.String(), `<span class="ui basic orange label">Public Access</span>`)
+
+ // remove "anonymous read"
+ req = NewRequestWithValues(t, "POST", "/org3/repo3/settings/public_access", map[string]string{
+ "_csrf": GetUserCSRFToken(t, session),
+ })
+ session.MakeRequest(t, req, http.StatusSeeOther)
+
+ // try to "anonymous read" (not found)
+ req = NewRequest(t, "GET", "/org3/repo3")
+ MakeRequest(t, req, http.StatusNotFound)
+ })
}
-func TestViewRepo1CloneLinkAnonymous(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
+func testViewRepo1CloneLinkAnonymous(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
req := NewRequest(t, "GET", "/user2/repo1")
resp := MakeRequest(t, req, http.StatusOK)
@@ -130,12 +191,17 @@ func TestViewRepo1CloneLinkAnonymous(t *testing.T) {
link, exists := htmlDoc.doc.Find(".repo-clone-https").Attr("data-link")
assert.True(t, exists, "The template has changed")
assert.Equal(t, setting.AppURL+"user2/repo1.git", link)
+
_, exists = htmlDoc.doc.Find(".repo-clone-ssh").Attr("data-link")
assert.False(t, exists)
+
+ link, exists = htmlDoc.doc.Find(".repo-clone-tea").Attr("data-link")
+ assert.True(t, exists, "The template has changed")
+ assert.Equal(t, "tea clone user2/repo1", link)
}
-func TestViewRepo1CloneLinkAuthorized(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
+func testViewRepo1CloneLinkAuthorized(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
session := loginUser(t, "user2")
@@ -146,15 +212,20 @@ func TestViewRepo1CloneLinkAuthorized(t *testing.T) {
link, exists := htmlDoc.doc.Find(".repo-clone-https").Attr("data-link")
assert.True(t, exists, "The template has changed")
assert.Equal(t, setting.AppURL+"user2/repo1.git", link)
+
link, exists = htmlDoc.doc.Find(".repo-clone-ssh").Attr("data-link")
assert.True(t, exists, "The template has changed")
sshURL := fmt.Sprintf("ssh://%s@%s:%d/user2/repo1.git", setting.SSH.User, setting.SSH.Domain, setting.SSH.Port)
assert.Equal(t, sshURL, link)
-}
-func TestViewRepoWithSymlinks(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
+ link, exists = htmlDoc.doc.Find(".repo-clone-tea").Attr("data-link")
+ assert.True(t, exists, "The template has changed")
+ assert.Equal(t, "tea clone user2/repo1", link)
+}
+func testViewRepoWithSymlinks(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+ defer test.MockVariableValue(&setting.UI.FileIconTheme, "basic")()
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user2/repo20.git")
@@ -176,8 +247,8 @@ func TestViewRepoWithSymlinks(t *testing.T) {
}
// TestViewFileInRepo repo description, topics and summary should not be displayed when viewing a file
-func TestViewFileInRepo(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
+func testViewFileInRepo(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
session := loginUser(t, "user2")
@@ -189,14 +260,14 @@ func TestViewFileInRepo(t *testing.T) {
repoTopics := htmlDoc.doc.Find("#repo-topics")
repoSummary := htmlDoc.doc.Find(".repository-summary")
- assert.EqualValues(t, 0, description.Length())
- assert.EqualValues(t, 0, repoTopics.Length())
- assert.EqualValues(t, 0, repoSummary.Length())
+ assert.Equal(t, 0, description.Length())
+ assert.Equal(t, 0, repoTopics.Length())
+ assert.Equal(t, 0, repoSummary.Length())
}
// TestBlameFileInRepo repo description, topics and summary should not be displayed when running blame on a file
-func TestBlameFileInRepo(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
+func testBlameFileInRepo(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
session := loginUser(t, "user2")
@@ -208,14 +279,14 @@ func TestBlameFileInRepo(t *testing.T) {
repoTopics := htmlDoc.doc.Find("#repo-topics")
repoSummary := htmlDoc.doc.Find(".repository-summary")
- assert.EqualValues(t, 0, description.Length())
- assert.EqualValues(t, 0, repoTopics.Length())
- assert.EqualValues(t, 0, repoSummary.Length())
+ assert.Equal(t, 0, description.Length())
+ assert.Equal(t, 0, repoTopics.Length())
+ assert.Equal(t, 0, repoSummary.Length())
}
// TestViewRepoDirectory repo description, topics and summary should not be displayed when within a directory
-func TestViewRepoDirectory(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
+func testViewRepoDirectory(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
session := loginUser(t, "user2")
@@ -236,8 +307,8 @@ func TestViewRepoDirectory(t *testing.T) {
}
// ensure that the all the different ways to find and render a README work
-func TestViewRepoDirectoryReadme(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
+func testViewRepoDirectoryReadme(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
// there are many combinations:
// - READMEs can be .md, .txt, or have no extension
@@ -343,8 +414,23 @@ func TestViewRepoDirectoryReadme(t *testing.T) {
missing("symlink-loop", "/user2/readme-test/src/branch/symlink-loop/")
}
-func TestMarkDownReadmeImage(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
+func testViewRepoSymlink(t *testing.T) {
+ session := loginUser(t, "user2")
+ req := NewRequest(t, "GET", "/user2/readme-test/src/branch/symlink")
+ resp := session.MakeRequest(t, req, http.StatusOK)
+
+ htmlDoc := NewHTMLParser(t, resp.Body)
+ AssertHTMLElement(t, htmlDoc, ".entry-symbol-link", true)
+ followSymbolLinkHref := htmlDoc.Find(".entry-symbol-link").AttrOr("href", "")
+ require.Equal(t, "/user2/readme-test/src/branch/symlink/README.md?follow_symlink=1", followSymbolLinkHref)
+
+ req = NewRequest(t, "GET", followSymbolLinkHref)
+ resp = session.MakeRequest(t, req, http.StatusSeeOther)
+ assert.Equal(t, "/user2/readme-test/src/branch/symlink/some/other/path/awefulcake.txt?follow_symlink=1", resp.Header().Get("Location"))
+}
+
+func testMarkDownReadmeImage(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
session := loginUser(t, "user2")
@@ -365,8 +451,8 @@ func TestMarkDownReadmeImage(t *testing.T) {
assert.Equal(t, "/user2/repo1/media/branch/home-md-img-check/test-fake-img.jpg", src)
}
-func TestMarkDownReadmeImageSubfolder(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
+func testMarkDownReadmeImageSubfolder(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
session := loginUser(t, "user2")
@@ -388,8 +474,8 @@ func TestMarkDownReadmeImageSubfolder(t *testing.T) {
assert.Equal(t, "/user2/repo1/media/branch/sub-home-md-img-check/docs/test-fake-img.jpg", src)
}
-func TestGeneratedSourceLink(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
+func testGeneratedSourceLink(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
t.Run("Rendered file", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
@@ -424,11 +510,54 @@ func TestGeneratedSourceLink(t *testing.T) {
})
}
-func TestViewCommit(t *testing.T) {
- defer tests.PrepareTestEnv(t)()
+func testViewCommit(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
req := NewRequest(t, "GET", "/user2/repo1/commit/0123456789012345678901234567890123456789")
req.Header.Add("Accept", "text/html")
resp := MakeRequest(t, req, http.StatusNotFound)
assert.True(t, test.IsNormalPageCompleted(resp.Body.String()), "non-existing commit should render 404 page")
}
+
+// TestGenerateRepository the test cannot succeed when moved as a unit test
+func TestGenerateRepository(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+
+ // a successful generate from template
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ repo44 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 44})
+
+ generatedRepo, err := repo_service.GenerateRepository(git.DefaultContext, user2, user2, repo44, repo_service.GenerateRepoOptions{
+ Name: "generated-from-template-44",
+ GitContent: true,
+ })
+ assert.NoError(t, err)
+ assert.NotNil(t, generatedRepo)
+
+ exist, err := util.IsExist(repo_model.RepoPath(user2.Name, generatedRepo.Name))
+ assert.NoError(t, err)
+ assert.True(t, exist)
+
+ unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: user2.Name, Name: generatedRepo.Name})
+
+ err = repo_service.DeleteRepositoryDirectly(db.DefaultContext, generatedRepo.ID)
+ assert.NoError(t, err)
+
+ // a failed creating because some mock data
+ // create the repository directory so that the creation will fail after database record created.
+ assert.NoError(t, os.MkdirAll(repo_model.RepoPath(user2.Name, "generated-from-template-44"), os.ModePerm))
+
+ generatedRepo2, err := repo_service.GenerateRepository(db.DefaultContext, user2, user2, repo44, repo_service.GenerateRepoOptions{
+ Name: "generated-from-template-44",
+ GitContent: true,
+ })
+ assert.Nil(t, generatedRepo2)
+ assert.Error(t, err)
+
+ // assert the cleanup is successful
+ unittest.AssertNotExistsBean(t, &repo_model.Repository{OwnerName: user2.Name, Name: generatedRepo.Name})
+
+ exist, err = util.IsExist(repo_model.RepoPath(user2.Name, generatedRepo.Name))
+ assert.NoError(t, err)
+ assert.False(t, exist)
+}
diff --git a/tests/integration/repo_topic_test.go b/tests/integration/repo_topic_test.go
index f198397007..7f9594b9fd 100644
--- a/tests/integration/repo_topic_test.go
+++ b/tests/integration/repo_topic_test.go
@@ -25,7 +25,7 @@ func TestTopicSearch(t *testing.T) {
res := MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK)
DecodeJSON(t, res, &topics)
assert.Len(t, topics.TopicNames, 6)
- assert.EqualValues(t, "6", res.Header().Get("x-total-count"))
+ assert.Equal(t, "6", res.Header().Get("x-total-count"))
// pagination search topics
topics.TopicNames = nil
@@ -35,7 +35,7 @@ func TestTopicSearch(t *testing.T) {
res = MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK)
DecodeJSON(t, res, &topics)
assert.Len(t, topics.TopicNames, 4)
- assert.EqualValues(t, "6", res.Header().Get("x-total-count"))
+ assert.Equal(t, "6", res.Header().Get("x-total-count"))
// second page
topics.TopicNames = nil
@@ -45,7 +45,7 @@ func TestTopicSearch(t *testing.T) {
res = MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK)
DecodeJSON(t, res, &topics)
assert.Len(t, topics.TopicNames, 2)
- assert.EqualValues(t, "6", res.Header().Get("x-total-count"))
+ assert.Equal(t, "6", res.Header().Get("x-total-count"))
// add keyword search
topics.TopicNames = nil
@@ -63,7 +63,7 @@ func TestTopicSearch(t *testing.T) {
DecodeJSON(t, res, &topics)
if assert.Len(t, topics.TopicNames, 1) {
assert.EqualValues(t, 2, topics.TopicNames[0].ID)
- assert.EqualValues(t, "database", topics.TopicNames[0].Name)
- assert.EqualValues(t, 1, topics.TopicNames[0].RepoCount)
+ assert.Equal(t, "database", topics.TopicNames[0].Name)
+ assert.Equal(t, 1, topics.TopicNames[0].RepoCount)
}
}
diff --git a/tests/integration/repo_webhook_test.go b/tests/integration/repo_webhook_test.go
index ef44a9e2d0..f1abac8cfa 100644
--- a/tests/integration/repo_webhook_test.go
+++ b/tests/integration/repo_webhook_test.go
@@ -4,14 +4,33 @@
package integration
import (
+ "fmt"
+ "io"
"net/http"
+ "net/http/httptest"
+ "net/url"
+ "path"
"strings"
"testing"
+ auth_model "code.gitea.io/gitea/models/auth"
+ "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/models/webhook"
+ "code.gitea.io/gitea/modules/commitstatus"
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/gitrepo"
+ "code.gitea.io/gitea/modules/json"
+ "code.gitea.io/gitea/modules/setting"
+ api "code.gitea.io/gitea/modules/structs"
+ webhook_module "code.gitea.io/gitea/modules/webhook"
"code.gitea.io/gitea/tests"
+ runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
"github.com/PuerkitoBio/goquery"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func TestNewWebHookLink(t *testing.T) {
@@ -39,3 +58,1238 @@ func TestNewWebHookLink(t *testing.T) {
})
}
}
+
+func testAPICreateWebhookForRepo(t *testing.T, session *TestSession, userName, repoName, url, event string, branchFilter ...string) {
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll)
+ var branchFilterString string
+ if len(branchFilter) > 0 {
+ branchFilterString = branchFilter[0]
+ }
+ req := NewRequestWithJSON(t, "POST", "/api/v1/repos/"+userName+"/"+repoName+"/hooks", api.CreateHookOption{
+ Type: "gitea",
+ Config: api.CreateHookOptionConfig{
+ "content_type": "json",
+ "url": url,
+ },
+ Events: []string{event},
+ Active: true,
+ BranchFilter: branchFilterString,
+ }).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusCreated)
+}
+
+func testCreateWebhookForRepo(t *testing.T, session *TestSession, webhookType, userName, repoName, url, eventKind string) {
+ csrf := GetUserCSRFToken(t, session)
+ req := NewRequestWithValues(t, "POST", "/"+userName+"/"+repoName+"/settings/hooks/"+webhookType+"/new", map[string]string{
+ "_csrf": csrf,
+ "payload_url": url,
+ "events": eventKind,
+ "active": "true",
+ "content_type": fmt.Sprintf("%d", webhook.ContentTypeJSON),
+ "http_method": "POST",
+ })
+ session.MakeRequest(t, req, http.StatusSeeOther)
+}
+
+func testAPICreateWebhookForOrg(t *testing.T, session *TestSession, userName, url, event string) {
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll)
+ req := NewRequestWithJSON(t, "POST", "/api/v1/orgs/"+userName+"/hooks", api.CreateHookOption{
+ Type: "gitea",
+ Config: api.CreateHookOptionConfig{
+ "content_type": "json",
+ "url": url,
+ },
+ Events: []string{event},
+ Active: true,
+ }).AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusCreated)
+}
+
+type mockWebhookProvider struct {
+ server *httptest.Server
+}
+
+func newMockWebhookProvider(callback func(r *http.Request), status int) *mockWebhookProvider {
+ m := &mockWebhookProvider{}
+ m.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ callback(r)
+ w.WriteHeader(status)
+ }))
+ return m
+}
+
+func (m *mockWebhookProvider) URL() string {
+ if m.server == nil {
+ return ""
+ }
+ return m.server.URL
+}
+
+// Close closes the mock webhook http server
+func (m *mockWebhookProvider) Close() {
+ if m.server != nil {
+ m.server.Close()
+ m.server = nil
+ }
+}
+
+func Test_WebhookCreate(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ var payloads []api.CreatePayload
+ var triggeredEvent string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ content, _ := io.ReadAll(r.Body)
+ var payload api.CreatePayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ payloads = append(payloads, payload)
+ triggeredEvent = string(webhook_module.HookEventCreate)
+ }, http.StatusOK)
+ defer provider.Close()
+
+ // 1. create a new webhook with special webhook for repo1
+ session := loginUser(t, "user2")
+
+ testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "create")
+
+ // 2. trigger the webhook
+ testAPICreateBranch(t, session, "user2", "repo1", "master", "master2", http.StatusCreated)
+
+ // 3. validate the webhook is triggered
+ assert.Len(t, payloads, 1)
+ assert.Equal(t, string(webhook_module.HookEventCreate), triggeredEvent)
+ assert.Equal(t, "repo1", payloads[0].Repo.Name)
+ assert.Equal(t, "user2/repo1", payloads[0].Repo.FullName)
+ assert.Equal(t, "master2", payloads[0].Ref)
+ assert.Equal(t, "branch", payloads[0].RefType)
+ })
+}
+
+func Test_WebhookDelete(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ var payloads []api.DeletePayload
+ var triggeredEvent string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ content, _ := io.ReadAll(r.Body)
+ var payload api.DeletePayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ payloads = append(payloads, payload)
+ triggeredEvent = "delete"
+ }, http.StatusOK)
+ defer provider.Close()
+
+ // 1. create a new webhook with special webhook for repo1
+ session := loginUser(t, "user2")
+
+ testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "delete")
+
+ // 2. trigger the webhook
+ testAPICreateBranch(t, session, "user2", "repo1", "master", "master2", http.StatusCreated)
+ testAPIDeleteBranch(t, "master2", http.StatusNoContent)
+
+ // 3. validate the webhook is triggered
+ assert.Equal(t, "delete", triggeredEvent)
+ assert.Len(t, payloads, 1)
+ assert.Equal(t, "repo1", payloads[0].Repo.Name)
+ assert.Equal(t, "user2/repo1", payloads[0].Repo.FullName)
+ assert.Equal(t, "master2", payloads[0].Ref)
+ assert.Equal(t, "branch", payloads[0].RefType)
+ })
+}
+
+func Test_WebhookFork(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ var payloads []api.ForkPayload
+ var triggeredEvent string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ content, _ := io.ReadAll(r.Body)
+ var payload api.ForkPayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ payloads = append(payloads, payload)
+ triggeredEvent = "fork"
+ }, http.StatusOK)
+ defer provider.Close()
+
+ // 1. create a new webhook with special webhook for repo1
+ session := loginUser(t, "user1")
+
+ testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "fork")
+
+ // 2. trigger the webhook
+ testRepoFork(t, session, "user2", "repo1", "user1", "repo1-fork", "master")
+
+ // 3. validate the webhook is triggered
+ assert.Equal(t, "fork", triggeredEvent)
+ assert.Len(t, payloads, 1)
+ assert.Equal(t, "repo1-fork", payloads[0].Repo.Name)
+ assert.Equal(t, "user1/repo1-fork", payloads[0].Repo.FullName)
+ assert.Equal(t, "repo1", payloads[0].Forkee.Name)
+ assert.Equal(t, "user2/repo1", payloads[0].Forkee.FullName)
+ })
+}
+
+func Test_WebhookIssueComment(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ var payloads []api.IssueCommentPayload
+ var triggeredEvent string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ content, _ := io.ReadAll(r.Body)
+ var payload api.IssueCommentPayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ payloads = append(payloads, payload)
+ triggeredEvent = "issue_comment"
+ }, http.StatusOK)
+ defer provider.Close()
+
+ // 1. create a new webhook with special webhook for repo1
+ session := loginUser(t, "user2")
+
+ testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "issue_comment")
+
+ t.Run("create comment", func(t *testing.T) {
+ // 2. trigger the webhook
+ issueURL := testNewIssue(t, session, "user2", "repo1", "Title2", "Description2")
+ testIssueAddComment(t, session, issueURL, "issue title2 comment1", "")
+
+ // 3. validate the webhook is triggered
+ assert.Equal(t, "issue_comment", triggeredEvent)
+ assert.Len(t, payloads, 1)
+ assert.EqualValues(t, "created", payloads[0].Action)
+ assert.Equal(t, "repo1", payloads[0].Issue.Repo.Name)
+ assert.Equal(t, "user2/repo1", payloads[0].Issue.Repo.FullName)
+ assert.Equal(t, "Title2", payloads[0].Issue.Title)
+ assert.Equal(t, "Description2", payloads[0].Issue.Body)
+ assert.Equal(t, "issue title2 comment1", payloads[0].Comment.Body)
+ })
+
+ t.Run("update comment", func(t *testing.T) {
+ payloads = make([]api.IssueCommentPayload, 0, 2)
+ triggeredEvent = ""
+
+ // 2. trigger the webhook
+ issueURL := testNewIssue(t, session, "user2", "repo1", "Title3", "Description3")
+ commentID := testIssueAddComment(t, session, issueURL, "issue title3 comment1", "")
+ modifiedContent := "issue title2 comment1 - modified"
+ req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/comments/%d", "user2", "repo1", commentID), map[string]string{
+ "_csrf": GetUserCSRFToken(t, session),
+ "content": modifiedContent,
+ })
+ session.MakeRequest(t, req, http.StatusOK)
+
+ // 3. validate the webhook is triggered
+ assert.Equal(t, "issue_comment", triggeredEvent)
+ assert.Len(t, payloads, 2)
+ assert.EqualValues(t, "edited", payloads[1].Action)
+ assert.Equal(t, "repo1", payloads[1].Issue.Repo.Name)
+ assert.Equal(t, "user2/repo1", payloads[1].Issue.Repo.FullName)
+ assert.Equal(t, "Title3", payloads[1].Issue.Title)
+ assert.Equal(t, "Description3", payloads[1].Issue.Body)
+ assert.Equal(t, modifiedContent, payloads[1].Comment.Body)
+ })
+
+ t.Run("Update comment with no content change", func(t *testing.T) {
+ payloads = make([]api.IssueCommentPayload, 0, 2)
+ triggeredEvent = ""
+ commentContent := "issue title3 comment1"
+
+ // 2. trigger the webhook
+ issueURL := testNewIssue(t, session, "user2", "repo1", "Title3", "Description3")
+ commentID := testIssueAddComment(t, session, issueURL, commentContent, "")
+
+ payloads = make([]api.IssueCommentPayload, 0, 2)
+ triggeredEvent = ""
+ req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/comments/%d", "user2", "repo1", commentID), map[string]string{
+ "_csrf": GetUserCSRFToken(t, session),
+ "content": commentContent,
+ })
+ session.MakeRequest(t, req, http.StatusOK)
+
+ // 3. validate the webhook is not triggered because no content change
+ assert.Empty(t, triggeredEvent)
+ assert.Empty(t, payloads)
+ })
+ })
+}
+
+func Test_WebhookRelease(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ var payloads []api.ReleasePayload
+ var triggeredEvent string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ content, _ := io.ReadAll(r.Body)
+ var payload api.ReleasePayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ payloads = append(payloads, payload)
+ triggeredEvent = "release"
+ }, http.StatusOK)
+ defer provider.Close()
+
+ // 1. create a new webhook with special webhook for repo1
+ session := loginUser(t, "user2")
+
+ testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "release")
+
+ // 2. trigger the webhook
+ createNewRelease(t, session, "/user2/repo1", "v0.0.99", "v0.0.99", false, false)
+
+ // 3. validate the webhook is triggered
+ assert.Equal(t, "release", triggeredEvent)
+ assert.Len(t, payloads, 1)
+ assert.Equal(t, "repo1", payloads[0].Repository.Name)
+ assert.Equal(t, "user2/repo1", payloads[0].Repository.FullName)
+ assert.Equal(t, "v0.0.99", payloads[0].Release.TagName)
+ assert.False(t, payloads[0].Release.IsDraft)
+ assert.False(t, payloads[0].Release.IsPrerelease)
+ })
+}
+
+func Test_WebhookPush(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ var payloads []api.PushPayload
+ var triggeredEvent string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ content, _ := io.ReadAll(r.Body)
+ var payload api.PushPayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ payloads = append(payloads, payload)
+ triggeredEvent = "push"
+ }, http.StatusOK)
+ defer provider.Close()
+
+ // 1. create a new webhook with special webhook for repo1
+ session := loginUser(t, "user2")
+
+ testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "push")
+
+ // 2. trigger the webhook
+ testCreateFile(t, session, "user2", "repo1", "master", "", "test_webhook_push.md", "# a test file for webhook push")
+
+ // 3. validate the webhook is triggered
+ assert.Equal(t, "push", triggeredEvent)
+ assert.Len(t, payloads, 1)
+ assert.Equal(t, "repo1", payloads[0].Repo.Name)
+ assert.Equal(t, "user2/repo1", payloads[0].Repo.FullName)
+ assert.Len(t, payloads[0].Commits, 1)
+ assert.Equal(t, []string{"test_webhook_push.md"}, payloads[0].Commits[0].Added)
+ })
+}
+
+func Test_WebhookPushDevBranch(t *testing.T) {
+ var payloads []api.PushPayload
+ var triggeredEvent string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ content, _ := io.ReadAll(r.Body)
+ var payload api.PushPayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ payloads = append(payloads, payload)
+ triggeredEvent = "push"
+ }, http.StatusOK)
+ defer provider.Close()
+
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ // 1. create a new webhook with special webhook for repo1
+ session := loginUser(t, "user2")
+
+ // only for dev branch
+ testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "push", "develop")
+
+ // 2. this should not trigger the webhook
+ testCreateFile(t, session, "user2", "repo1", "master", "", "test_webhook_push.md", "# a test file for webhook push")
+ assert.Empty(t, triggeredEvent)
+ assert.Empty(t, payloads)
+
+ repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1})
+ gitRepo, err := gitrepo.OpenRepository(t.Context(), repo1)
+ assert.NoError(t, err)
+ defer gitRepo.Close()
+
+ beforeCommitID, err := gitRepo.GetBranchCommitID("develop")
+ assert.NoError(t, err)
+
+ // 3. trigger the webhook
+ testCreateFile(t, session, "user2", "repo1", "develop", "", "test_webhook_push.md", "# a test file for webhook push")
+
+ afterCommitID, err := gitRepo.GetBranchCommitID("develop")
+ assert.NoError(t, err)
+
+ // 4. validate the webhook is triggered
+ assert.Equal(t, "push", triggeredEvent)
+ assert.Len(t, payloads, 1)
+ assert.Equal(t, "refs/heads/develop", payloads[0].Ref)
+ assert.Equal(t, beforeCommitID, payloads[0].Before)
+ assert.Equal(t, afterCommitID, payloads[0].After)
+ assert.Equal(t, "repo1", payloads[0].Repo.Name)
+ assert.Equal(t, "develop", payloads[0].Branch())
+ assert.Equal(t, "user2/repo1", payloads[0].Repo.FullName)
+ assert.Len(t, payloads[0].Commits, 1)
+ assert.Equal(t, afterCommitID, payloads[0].Commits[0].ID)
+ assert.Equal(t, setting.AppURL+"user2/repo1/compare/"+beforeCommitID+"..."+afterCommitID, payloads[0].CompareURL)
+ assert.Equal(t, []string{"test_webhook_push.md"}, payloads[0].Commits[0].Added)
+ assert.Empty(t, payloads[0].Commits[0].Removed)
+ })
+}
+
+func Test_WebhookPushToNewBranch(t *testing.T) {
+ var payloads []api.PushPayload
+ var triggeredEvent string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ content, _ := io.ReadAll(r.Body)
+ var payload api.PushPayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ payloads = append(payloads, payload)
+ triggeredEvent = "push"
+ }, http.StatusOK)
+ defer provider.Close()
+
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ // 1. create a new webhook with special webhook for repo1
+ session := loginUser(t, "user2")
+
+ // only for dev branch
+ testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "push", "new_branch")
+
+ repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1})
+ gitRepo, err := gitrepo.OpenRepository(t.Context(), repo1)
+ assert.NoError(t, err)
+ defer gitRepo.Close()
+
+ beforeCommitID, err := gitRepo.GetBranchCommitID("master")
+ assert.NoError(t, err)
+
+ // 2. trigger the webhook
+ testCreateFile(t, session, "user2", "repo1", "master", "new_branch", "test_webhook_push.md", "# a new push from new branch")
+
+ afterCommitID, err := gitRepo.GetBranchCommitID("new_branch")
+ assert.NoError(t, err)
+ emptyCommitID := git.Sha1ObjectFormat.EmptyObjectID().String()
+
+ // 4. validate the webhook is triggered
+ assert.Equal(t, "push", triggeredEvent)
+ assert.Len(t, payloads, 1)
+ assert.Equal(t, "refs/heads/new_branch", payloads[0].Ref)
+ assert.Equal(t, emptyCommitID, payloads[0].Before)
+ assert.Equal(t, afterCommitID, payloads[0].After)
+ assert.Equal(t, "repo1", payloads[0].Repo.Name)
+ assert.Equal(t, "new_branch", payloads[0].Branch())
+ assert.Equal(t, "user2/repo1", payloads[0].Repo.FullName)
+ assert.Len(t, payloads[0].Commits, 1)
+ assert.Equal(t, afterCommitID, payloads[0].Commits[0].ID)
+ assert.Equal(t, setting.AppURL+"user2/repo1/compare/"+beforeCommitID+"..."+afterCommitID, payloads[0].CompareURL)
+ assert.Equal(t, []string{"test_webhook_push.md"}, payloads[0].Commits[0].Added)
+ assert.Empty(t, payloads[0].Commits[0].Removed)
+ })
+}
+
+func Test_WebhookIssue(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ var payloads []api.IssuePayload
+ var triggeredEvent string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ content, _ := io.ReadAll(r.Body)
+ var payload api.IssuePayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ payloads = append(payloads, payload)
+ triggeredEvent = "issues"
+ }, http.StatusOK)
+ defer provider.Close()
+
+ // 1. create a new webhook with special webhook for repo1
+ session := loginUser(t, "user2")
+
+ testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "issues")
+
+ // 2. trigger the webhook
+ testNewIssue(t, session, "user2", "repo1", "Title1", "Description1")
+
+ // 3. validate the webhook is triggered
+ assert.Equal(t, "issues", triggeredEvent)
+ assert.Len(t, payloads, 1)
+ assert.EqualValues(t, "opened", payloads[0].Action)
+ assert.Equal(t, "repo1", payloads[0].Issue.Repo.Name)
+ assert.Equal(t, "user2/repo1", payloads[0].Issue.Repo.FullName)
+ assert.Equal(t, "Title1", payloads[0].Issue.Title)
+ assert.Equal(t, "Description1", payloads[0].Issue.Body)
+ assert.Positive(t, payloads[0].Issue.Created.Unix())
+ assert.Positive(t, payloads[0].Issue.Updated.Unix())
+ })
+}
+
+func Test_WebhookIssueDelete(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ var payloads []api.IssuePayload
+ var triggeredEvent string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ content, _ := io.ReadAll(r.Body)
+ var payload api.IssuePayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ payloads = append(payloads, payload)
+ triggeredEvent = "issue"
+ }, http.StatusOK)
+ defer provider.Close()
+
+ // 1. create a new webhook with special webhook for repo1
+ session := loginUser(t, "user2")
+ testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "issues")
+ issueURL := testNewIssue(t, session, "user2", "repo1", "Title1", "Description1")
+
+ // 2. trigger the webhook
+ testIssueDelete(t, session, issueURL)
+
+ // 3. validate the webhook is triggered
+ assert.Equal(t, "issue", triggeredEvent)
+ require.Len(t, payloads, 2)
+ assert.EqualValues(t, "deleted", payloads[1].Action)
+ assert.Equal(t, "repo1", payloads[1].Issue.Repo.Name)
+ assert.Equal(t, "user2/repo1", payloads[1].Issue.Repo.FullName)
+ assert.Equal(t, "Title1", payloads[1].Issue.Title)
+ assert.Equal(t, "Description1", payloads[1].Issue.Body)
+ })
+}
+
+func Test_WebhookIssueAssign(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ var payloads []api.PullRequestPayload
+ var triggeredEvent string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ content, _ := io.ReadAll(r.Body)
+ var payload api.PullRequestPayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ payloads = append(payloads, payload)
+ triggeredEvent = "pull_request_assign"
+ }, http.StatusOK)
+ defer provider.Close()
+
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1})
+
+ // 1. create a new webhook with special webhook for repo1
+ session := loginUser(t, "user2")
+
+ testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "pull_request_assign")
+
+ // 2. trigger the webhook, issue 2 is a pull request
+ testIssueAssign(t, session, repo1.Link(), 2, user2.ID)
+
+ // 3. validate the webhook is triggered
+ assert.Equal(t, "pull_request_assign", triggeredEvent)
+ assert.Len(t, payloads, 1)
+ assert.EqualValues(t, "assigned", payloads[0].Action)
+ assert.Equal(t, "repo1", payloads[0].PullRequest.Base.Repository.Name)
+ assert.Equal(t, "user2/repo1", payloads[0].PullRequest.Base.Repository.FullName)
+ assert.Equal(t, "issue2", payloads[0].PullRequest.Title)
+ assert.Equal(t, "content for the second issue", payloads[0].PullRequest.Body)
+ assert.Equal(t, user2.ID, payloads[0].PullRequest.Assignee.ID)
+ })
+}
+
+func Test_WebhookIssueMilestone(t *testing.T) {
+ var payloads []api.IssuePayload
+ var triggeredEvent string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ content, _ := io.ReadAll(r.Body)
+ var payload api.IssuePayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ payloads = append(payloads, payload)
+ triggeredEvent = "issues"
+ }, http.StatusOK)
+ defer provider.Close()
+
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ // create a new webhook with special webhook for repo1
+ session := loginUser(t, "user2")
+ repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1})
+ testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "issue_milestone")
+
+ t.Run("assign a milestone", func(t *testing.T) {
+ // trigger the webhook
+ testIssueChangeMilestone(t, session, repo1.Link(), 1, 1)
+
+ // validate the webhook is triggered
+ assert.Equal(t, "issues", triggeredEvent)
+ assert.Len(t, payloads, 1)
+ assert.Equal(t, "milestoned", string(payloads[0].Action))
+ assert.Equal(t, "repo1", payloads[0].Issue.Repo.Name)
+ assert.Equal(t, "user2/repo1", payloads[0].Issue.Repo.FullName)
+ assert.Equal(t, "issue1", payloads[0].Issue.Title)
+ assert.Equal(t, "content for the first issue", payloads[0].Issue.Body)
+ assert.EqualValues(t, 1, payloads[0].Issue.Milestone.ID)
+ })
+
+ t.Run("change a milestong", func(t *testing.T) {
+ // trigger the webhook again
+ triggeredEvent = ""
+ payloads = make([]api.IssuePayload, 0, 1)
+ // change milestone to 2
+ testIssueChangeMilestone(t, session, repo1.Link(), 1, 2)
+
+ // validate the webhook is triggered
+ assert.Equal(t, "issues", triggeredEvent)
+ assert.Len(t, payloads, 1)
+ assert.Equal(t, "milestoned", string(payloads[0].Action))
+ assert.Equal(t, "repo1", payloads[0].Issue.Repo.Name)
+ assert.Equal(t, "user2/repo1", payloads[0].Issue.Repo.FullName)
+ assert.Equal(t, "issue1", payloads[0].Issue.Title)
+ assert.Equal(t, "content for the first issue", payloads[0].Issue.Body)
+ assert.EqualValues(t, 2, payloads[0].Issue.Milestone.ID)
+ })
+
+ t.Run("remove a milestone", func(t *testing.T) {
+ // trigger the webhook again
+ triggeredEvent = ""
+ payloads = make([]api.IssuePayload, 0, 1)
+ // change milestone to 0
+ testIssueChangeMilestone(t, session, repo1.Link(), 1, 0)
+
+ // validate the webhook is triggered
+ assert.Equal(t, "issues", triggeredEvent)
+ assert.Len(t, payloads, 1)
+ assert.Equal(t, "demilestoned", string(payloads[0].Action))
+ assert.Equal(t, "repo1", payloads[0].Issue.Repo.Name)
+ assert.Equal(t, "user2/repo1", payloads[0].Issue.Repo.FullName)
+ assert.Equal(t, "issue1", payloads[0].Issue.Title)
+ assert.Equal(t, "content for the first issue", payloads[0].Issue.Body)
+ assert.Nil(t, payloads[0].Issue.Milestone)
+ })
+ })
+}
+
+func Test_WebhookPullRequest(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ var payloads []api.PullRequestPayload
+ var triggeredEvent string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ content, _ := io.ReadAll(r.Body)
+ var payload api.PullRequestPayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ payloads = append(payloads, payload)
+ triggeredEvent = "pull_request"
+ }, http.StatusOK)
+ defer provider.Close()
+
+ // 1. create a new webhook with special webhook for repo1
+ session := loginUser(t, "user2")
+
+ testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "pull_request")
+
+ testAPICreateBranch(t, session, "user2", "repo1", "master", "master2", http.StatusCreated)
+ // 2. trigger the webhook
+ repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1})
+ testCreatePullToDefaultBranch(t, session, repo1, repo1, "master2", "first pull request")
+
+ // 3. validate the webhook is triggered
+ assert.Equal(t, "pull_request", triggeredEvent)
+ require.Len(t, payloads, 1)
+ assert.Equal(t, "repo1", payloads[0].PullRequest.Base.Repository.Name)
+ assert.Equal(t, "user2/repo1", payloads[0].PullRequest.Base.Repository.FullName)
+ assert.Equal(t, "repo1", payloads[0].PullRequest.Head.Repository.Name)
+ assert.Equal(t, "user2/repo1", payloads[0].PullRequest.Head.Repository.FullName)
+ assert.Equal(t, 0, *payloads[0].PullRequest.Additions)
+ assert.Equal(t, 0, *payloads[0].PullRequest.ChangedFiles)
+ assert.Equal(t, 0, *payloads[0].PullRequest.Deletions)
+ })
+}
+
+func Test_WebhookPullRequestDelete(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ var payloads []api.PullRequestPayload
+ var triggeredEvent string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ content, _ := io.ReadAll(r.Body)
+ var payload api.PullRequestPayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ payloads = append(payloads, payload)
+ triggeredEvent = "pull_request"
+ }, http.StatusOK)
+ defer provider.Close()
+
+ // 1. create a new webhook with special webhook for repo1
+ session := loginUser(t, "user2")
+ testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "pull_request")
+
+ testAPICreateBranch(t, session, "user2", "repo1", "master", "master2", http.StatusCreated)
+
+ repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1})
+ issueURL := testCreatePullToDefaultBranch(t, session, repo1, repo1, "master2", "first pull request")
+
+ // 2. trigger the webhook
+ testIssueDelete(t, session, path.Join(repo1.Link(), "pulls", issueURL))
+
+ // 3. validate the webhook is triggered
+ assert.Equal(t, "pull_request", triggeredEvent)
+ require.Len(t, payloads, 2)
+ assert.EqualValues(t, "deleted", payloads[1].Action)
+ assert.Equal(t, "repo1", payloads[1].PullRequest.Base.Repository.Name)
+ assert.Equal(t, "user2/repo1", payloads[1].PullRequest.Base.Repository.FullName)
+ assert.Equal(t, 0, *payloads[1].PullRequest.Additions)
+ assert.Equal(t, 0, *payloads[1].PullRequest.ChangedFiles)
+ assert.Equal(t, 0, *payloads[1].PullRequest.Deletions)
+ })
+}
+
+func Test_WebhookPullRequestComment(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ var payloads []api.IssueCommentPayload
+ var triggeredEvent string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ content, _ := io.ReadAll(r.Body)
+ var payload api.IssueCommentPayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ payloads = append(payloads, payload)
+ triggeredEvent = "pull_request_comment"
+ }, http.StatusOK)
+ defer provider.Close()
+
+ // 1. create a new webhook with special webhook for repo1
+ session := loginUser(t, "user2")
+
+ testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "pull_request_comment")
+
+ // 2. trigger the webhook
+ testAPICreateBranch(t, session, "user2", "repo1", "master", "master2", http.StatusCreated)
+ repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1})
+ prID := testCreatePullToDefaultBranch(t, session, repo1, repo1, "master2", "first pull request")
+
+ testIssueAddComment(t, session, "/user2/repo1/pulls/"+prID, "pull title2 comment1", "")
+
+ // 3. validate the webhook is triggered
+ assert.Equal(t, "pull_request_comment", triggeredEvent)
+ assert.Len(t, payloads, 1)
+ assert.EqualValues(t, "created", payloads[0].Action)
+ assert.Equal(t, "repo1", payloads[0].Issue.Repo.Name)
+ assert.Equal(t, "user2/repo1", payloads[0].Issue.Repo.FullName)
+ assert.Equal(t, "first pull request", payloads[0].Issue.Title)
+ assert.Empty(t, payloads[0].Issue.Body)
+ assert.Equal(t, "pull title2 comment1", payloads[0].Comment.Body)
+ })
+}
+
+func Test_WebhookWiki(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ var payloads []api.WikiPayload
+ var triggeredEvent string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ content, _ := io.ReadAll(r.Body)
+ var payload api.WikiPayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ payloads = append(payloads, payload)
+ triggeredEvent = "wiki"
+ }, http.StatusOK)
+ defer provider.Close()
+
+ // 1. create a new webhook with special webhook for repo1
+ session := loginUser(t, "user2")
+
+ testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "wiki")
+
+ // 2. trigger the webhook
+ testAPICreateWikiPage(t, session, "user2", "repo1", "Test Wiki Page", http.StatusCreated)
+
+ // 3. validate the webhook is triggered
+ assert.Equal(t, "wiki", triggeredEvent)
+ assert.Len(t, payloads, 1)
+ assert.EqualValues(t, "created", payloads[0].Action)
+ assert.Equal(t, "repo1", payloads[0].Repository.Name)
+ assert.Equal(t, "user2/repo1", payloads[0].Repository.FullName)
+ assert.Equal(t, "Test-Wiki-Page", payloads[0].Page)
+ })
+}
+
+func Test_WebhookRepository(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ var payloads []api.RepositoryPayload
+ var triggeredEvent string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ content, _ := io.ReadAll(r.Body)
+ var payload api.RepositoryPayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ payloads = append(payloads, payload)
+ triggeredEvent = "repository"
+ }, http.StatusOK)
+ defer provider.Close()
+
+ // 1. create a new webhook with special webhook for repo1
+ session := loginUser(t, "user1")
+
+ testAPICreateWebhookForOrg(t, session, "org3", provider.URL(), "repository")
+
+ // 2. trigger the webhook
+ testAPIOrgCreateRepo(t, session, "org3", "repo_new", http.StatusCreated)
+
+ // 3. validate the webhook is triggered
+ assert.Equal(t, "repository", triggeredEvent)
+ assert.Len(t, payloads, 1)
+ assert.EqualValues(t, "created", payloads[0].Action)
+ assert.Equal(t, "org3", payloads[0].Organization.UserName)
+ assert.Equal(t, "repo_new", payloads[0].Repository.Name)
+ assert.Equal(t, "org3/repo_new", payloads[0].Repository.FullName)
+ })
+}
+
+func Test_WebhookPackage(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ var payloads []api.PackagePayload
+ var triggeredEvent string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ content, _ := io.ReadAll(r.Body)
+ var payload api.PackagePayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ payloads = append(payloads, payload)
+ triggeredEvent = "package"
+ }, http.StatusOK)
+ defer provider.Close()
+
+ // 1. create a new webhook with special webhook for repo1
+ session := loginUser(t, "user1")
+
+ testAPICreateWebhookForOrg(t, session, "org3", provider.URL(), "package")
+
+ // 2. trigger the webhook
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll)
+ url := fmt.Sprintf("/api/packages/%s/generic/%s/%s", "org3", "gitea", "v1.24.0")
+ req := NewRequestWithBody(t, "PUT", url+"/gitea", strings.NewReader("This is a dummy file")).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusCreated)
+
+ // 3. validate the webhook is triggered
+ assert.Equal(t, "package", triggeredEvent)
+ assert.Len(t, payloads, 1)
+ assert.EqualValues(t, "created", payloads[0].Action)
+ assert.Equal(t, "gitea", payloads[0].Package.Name)
+ assert.Equal(t, "generic", payloads[0].Package.Type)
+ assert.Equal(t, "org3", payloads[0].Organization.UserName)
+ assert.Equal(t, "v1.24.0", payloads[0].Package.Version)
+ })
+}
+
+func Test_WebhookStatus(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ var payloads []api.CommitStatusPayload
+ var triggeredEvent string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ assert.Contains(t, r.Header["X-Github-Event-Type"], "status", "X-GitHub-Event-Type should contain status")
+ assert.Contains(t, r.Header["X-Github-Hook-Installation-Target-Type"], "repository", "X-GitHub-Hook-Installation-Target-Type should contain repository")
+ assert.Contains(t, r.Header["X-Gitea-Event-Type"], "status", "X-Gitea-Event-Type should contain status")
+ assert.Contains(t, r.Header["X-Gitea-Hook-Installation-Target-Type"], "repository", "X-Gitea-Hook-Installation-Target-Type should contain repository")
+ assert.Contains(t, r.Header["X-Gogs-Event-Type"], "status", "X-Gogs-Event-Type should contain status")
+ content, _ := io.ReadAll(r.Body)
+ var payload api.CommitStatusPayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ payloads = append(payloads, payload)
+ triggeredEvent = "status"
+ }, http.StatusOK)
+ defer provider.Close()
+
+ // 1. create a new webhook with special webhook for repo1
+ session := loginUser(t, "user2")
+
+ testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "status")
+
+ repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1})
+
+ gitRepo1, err := gitrepo.OpenRepository(t.Context(), repo1)
+ assert.NoError(t, err)
+ commitID, err := gitRepo1.GetBranchCommitID(repo1.DefaultBranch)
+ assert.NoError(t, err)
+
+ // 2. trigger the webhook
+ testCtx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeAll)
+
+ // update a status for a commit via API
+ doAPICreateCommitStatus(testCtx, commitID, api.CreateStatusOption{
+ State: commitstatus.CommitStatusSuccess,
+ TargetURL: "http://test.ci/",
+ Description: "",
+ Context: "testci",
+ })(t)
+
+ // 3. validate the webhook is triggered
+ assert.Equal(t, "status", triggeredEvent)
+ assert.Len(t, payloads, 1)
+ assert.Equal(t, commitID, payloads[0].Commit.ID)
+ assert.Equal(t, "repo1", payloads[0].Repo.Name)
+ assert.Equal(t, "user2/repo1", payloads[0].Repo.FullName)
+ assert.Equal(t, "testci", payloads[0].Context)
+ assert.Equal(t, commitID, payloads[0].SHA)
+ })
+}
+
+func Test_WebhookStatus_NoWrongTrigger(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ var trigger string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ assert.NotContains(t, r.Header["X-Github-Event-Type"], "status", "X-GitHub-Event-Type should not contain status")
+ assert.NotContains(t, r.Header["X-Gitea-Event-Type"], "status", "X-Gitea-Event-Type should not contain status")
+ assert.NotContains(t, r.Header["X-Gogs-Event-Type"], "status", "X-Gogs-Event-Type should not contain status")
+ trigger = "push"
+ }, http.StatusOK)
+ defer provider.Close()
+
+ // 1. create a new webhook with special webhook for repo1
+ session := loginUser(t, "user2")
+
+ // create a push_only webhook from web UI
+ testCreateWebhookForRepo(t, session, "gitea", "user2", "repo1", provider.URL(), "push_only")
+
+ // 2. trigger the webhook with a push action
+ testCreateFile(t, session, "user2", "repo1", "master", "", "test_webhook_push.md", "# a test file for webhook push")
+
+ // 3. validate the webhook is triggered with right event
+ assert.Equal(t, "push", trigger)
+ })
+}
+
+func Test_WebhookWorkflowJob(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ var payloads []api.WorkflowJobPayload
+ var triggeredEvent string
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ assert.Contains(t, r.Header["X-Github-Event-Type"], "workflow_job", "X-GitHub-Event-Type should contain workflow_job")
+ assert.Contains(t, r.Header["X-Gitea-Event-Type"], "workflow_job", "X-Gitea-Event-Type should contain workflow_job")
+ assert.Contains(t, r.Header["X-Gogs-Event-Type"], "workflow_job", "X-Gogs-Event-Type should contain workflow_job")
+ content, _ := io.ReadAll(r.Body)
+ var payload api.WorkflowJobPayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ payloads = append(payloads, payload)
+ triggeredEvent = "workflow_job"
+ }, http.StatusOK)
+ defer provider.Close()
+
+ // 1. create a new webhook with special webhook for repo1
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ session := loginUser(t, "user2")
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
+
+ testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "workflow_job")
+
+ repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1})
+
+ gitRepo1, err := gitrepo.OpenRepository(t.Context(), repo1)
+ assert.NoError(t, err)
+
+ runner := newMockRunner()
+ runner.registerAsRepoRunner(t, "user2", "repo1", "mock-runner", []string{"ubuntu-latest"}, false)
+
+ // 2. trigger the webhooks
+
+ // add workflow file to the repo
+ // init the workflow
+ wfTreePath := ".gitea/workflows/push.yml"
+ wfFileContent := `name: Push
+on: push
+jobs:
+ wf1-job:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo 'test the webhook'
+ wf2-job:
+ runs-on: ubuntu-latest
+ needs: wf1-job
+ steps:
+ - run: echo 'cmd 1'
+ - run: echo 'cmd 2'
+`
+ opts := getWorkflowCreateFileOptions(user2, repo1.DefaultBranch, "create "+wfTreePath, wfFileContent)
+ createWorkflowFile(t, token, "user2", "repo1", wfTreePath, opts)
+
+ commitID, err := gitRepo1.GetBranchCommitID(repo1.DefaultBranch)
+ assert.NoError(t, err)
+
+ // 3. validate the webhook is triggered
+ assert.Equal(t, "workflow_job", triggeredEvent)
+ assert.Len(t, payloads, 2)
+ assert.Equal(t, "queued", payloads[0].Action)
+ assert.Equal(t, "queued", payloads[0].WorkflowJob.Status)
+ assert.Equal(t, []string{"ubuntu-latest"}, payloads[0].WorkflowJob.Labels)
+ assert.Equal(t, commitID, payloads[0].WorkflowJob.HeadSha)
+ assert.Equal(t, "repo1", payloads[0].Repo.Name)
+ assert.Equal(t, "user2/repo1", payloads[0].Repo.FullName)
+
+ assert.Equal(t, "waiting", payloads[1].Action)
+ assert.Equal(t, "waiting", payloads[1].WorkflowJob.Status)
+ assert.Equal(t, commitID, payloads[1].WorkflowJob.HeadSha)
+ assert.Equal(t, "repo1", payloads[1].Repo.Name)
+ assert.Equal(t, "user2/repo1", payloads[1].Repo.FullName)
+
+ // 4. Execute a single Job
+ task := runner.fetchTask(t)
+ outcome := &mockTaskOutcome{
+ result: runnerv1.Result_RESULT_SUCCESS,
+ }
+ runner.execTask(t, task, outcome)
+
+ // 5. validate the webhook is triggered
+ assert.Equal(t, "workflow_job", triggeredEvent)
+ assert.Len(t, payloads, 5)
+ assert.Equal(t, "in_progress", payloads[2].Action)
+ assert.Equal(t, "in_progress", payloads[2].WorkflowJob.Status)
+ assert.Equal(t, "mock-runner", payloads[2].WorkflowJob.RunnerName)
+ assert.Equal(t, commitID, payloads[2].WorkflowJob.HeadSha)
+ assert.Equal(t, "repo1", payloads[2].Repo.Name)
+ assert.Equal(t, "user2/repo1", payloads[2].Repo.FullName)
+
+ assert.Equal(t, "completed", payloads[3].Action)
+ assert.Equal(t, "completed", payloads[3].WorkflowJob.Status)
+ assert.Equal(t, "mock-runner", payloads[3].WorkflowJob.RunnerName)
+ assert.Equal(t, "success", payloads[3].WorkflowJob.Conclusion)
+ assert.Equal(t, commitID, payloads[3].WorkflowJob.HeadSha)
+ assert.Equal(t, "repo1", payloads[3].Repo.Name)
+ assert.Equal(t, "user2/repo1", payloads[3].Repo.FullName)
+ assert.Contains(t, payloads[3].WorkflowJob.URL, fmt.Sprintf("/actions/jobs/%d", payloads[3].WorkflowJob.ID))
+ assert.Contains(t, payloads[3].WorkflowJob.HTMLURL, fmt.Sprintf("/jobs/%d", 0))
+ assert.Len(t, payloads[3].WorkflowJob.Steps, 1)
+
+ assert.Equal(t, "queued", payloads[4].Action)
+ assert.Equal(t, "queued", payloads[4].WorkflowJob.Status)
+ assert.Equal(t, []string{"ubuntu-latest"}, payloads[4].WorkflowJob.Labels)
+ assert.Equal(t, commitID, payloads[4].WorkflowJob.HeadSha)
+ assert.Equal(t, "repo1", payloads[4].Repo.Name)
+ assert.Equal(t, "user2/repo1", payloads[4].Repo.FullName)
+
+ // 6. Execute a single Job
+ task = runner.fetchTask(t)
+ outcome = &mockTaskOutcome{
+ result: runnerv1.Result_RESULT_FAILURE,
+ }
+ runner.execTask(t, task, outcome)
+
+ // 7. validate the webhook is triggered
+ assert.Equal(t, "workflow_job", triggeredEvent)
+ assert.Len(t, payloads, 7)
+ assert.Equal(t, "in_progress", payloads[5].Action)
+ assert.Equal(t, "in_progress", payloads[5].WorkflowJob.Status)
+ assert.Equal(t, "mock-runner", payloads[5].WorkflowJob.RunnerName)
+
+ assert.Equal(t, commitID, payloads[5].WorkflowJob.HeadSha)
+ assert.Equal(t, "repo1", payloads[5].Repo.Name)
+ assert.Equal(t, "user2/repo1", payloads[5].Repo.FullName)
+
+ assert.Equal(t, "completed", payloads[6].Action)
+ assert.Equal(t, "completed", payloads[6].WorkflowJob.Status)
+ assert.Equal(t, "failure", payloads[6].WorkflowJob.Conclusion)
+ assert.Equal(t, "mock-runner", payloads[6].WorkflowJob.RunnerName)
+ assert.Equal(t, commitID, payloads[6].WorkflowJob.HeadSha)
+ assert.Equal(t, "repo1", payloads[6].Repo.Name)
+ assert.Equal(t, "user2/repo1", payloads[6].Repo.FullName)
+ assert.Contains(t, payloads[6].WorkflowJob.URL, fmt.Sprintf("/actions/jobs/%d", payloads[6].WorkflowJob.ID))
+ assert.Contains(t, payloads[6].WorkflowJob.HTMLURL, fmt.Sprintf("/jobs/%d", 1))
+ assert.Len(t, payloads[6].WorkflowJob.Steps, 2)
+ })
+}
+
+type workflowRunWebhook struct {
+ URL string
+ payloads []api.WorkflowRunPayload
+ triggeredEvent string
+}
+
+func Test_WebhookWorkflowRun(t *testing.T) {
+ webhookData := &workflowRunWebhook{}
+ provider := newMockWebhookProvider(func(r *http.Request) {
+ assert.Contains(t, r.Header["X-Github-Event-Type"], "workflow_run", "X-GitHub-Event-Type should contain workflow_run")
+ assert.Contains(t, r.Header["X-Gitea-Event-Type"], "workflow_run", "X-Gitea-Event-Type should contain workflow_run")
+ assert.Contains(t, r.Header["X-Gogs-Event-Type"], "workflow_run", "X-Gogs-Event-Type should contain workflow_run")
+ content, _ := io.ReadAll(r.Body)
+ var payload api.WorkflowRunPayload
+ err := json.Unmarshal(content, &payload)
+ assert.NoError(t, err)
+ webhookData.payloads = append(webhookData.payloads, payload)
+ webhookData.triggeredEvent = "workflow_run"
+ }, http.StatusOK)
+ defer provider.Close()
+ webhookData.URL = provider.URL()
+
+ tests := []struct {
+ name string
+ callback func(t *testing.T, webhookData *workflowRunWebhook)
+ }{
+ {
+ name: "WorkflowRun",
+ callback: testWebhookWorkflowRun,
+ },
+ {
+ name: "WorkflowRunDepthLimit",
+ callback: testWebhookWorkflowRunDepthLimit,
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ webhookData.payloads = nil
+ webhookData.triggeredEvent = ""
+ onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
+ test.callback(t, webhookData)
+ })
+ })
+ }
+}
+
+func testWebhookWorkflowRun(t *testing.T, webhookData *workflowRunWebhook) {
+ // 1. create a new webhook with special webhook for repo1
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ session := loginUser(t, "user2")
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
+
+ testAPICreateWebhookForRepo(t, session, "user2", "repo1", webhookData.URL, "workflow_run")
+
+ repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1})
+
+ gitRepo1, err := gitrepo.OpenRepository(t.Context(), repo1)
+ assert.NoError(t, err)
+
+ runner := newMockRunner()
+ runner.registerAsRepoRunner(t, "user2", "repo1", "mock-runner", []string{"ubuntu-latest"}, false)
+
+ // 2.1 add workflow_run workflow file to the repo
+
+ opts := getWorkflowCreateFileOptions(user2, repo1.DefaultBranch, "create "+"dispatch.yml", `
+on:
+ workflow_run:
+ workflows: ["Push"]
+ types:
+ - completed
+jobs:
+ dispatch:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo 'test the webhook'
+`)
+ createWorkflowFile(t, token, "user2", "repo1", ".gitea/workflows/dispatch.yml", opts)
+
+ // 2.2 trigger the webhooks
+
+ // add workflow file to the repo
+ // init the workflow
+ wfTreePath := ".gitea/workflows/push.yml"
+ wfFileContent := `name: Push
+on: push
+jobs:
+ wf1-job:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo 'test the webhook'
+ wf2-job:
+ runs-on: ubuntu-latest
+ needs: wf1-job
+ steps:
+ - run: echo 'cmd 1'
+ - run: echo 'cmd 2'
+`
+ opts = getWorkflowCreateFileOptions(user2, repo1.DefaultBranch, "create "+wfTreePath, wfFileContent)
+ createWorkflowFile(t, token, "user2", "repo1", wfTreePath, opts)
+
+ commitID, err := gitRepo1.GetBranchCommitID(repo1.DefaultBranch)
+ assert.NoError(t, err)
+
+ // 3. validate the webhook is triggered
+ assert.Equal(t, "workflow_run", webhookData.triggeredEvent)
+ assert.Len(t, webhookData.payloads, 1)
+ assert.Equal(t, "requested", webhookData.payloads[0].Action)
+ assert.Equal(t, "queued", webhookData.payloads[0].WorkflowRun.Status)
+ assert.Equal(t, repo1.DefaultBranch, webhookData.payloads[0].WorkflowRun.HeadBranch)
+ assert.Equal(t, commitID, webhookData.payloads[0].WorkflowRun.HeadSha)
+ assert.Equal(t, "repo1", webhookData.payloads[0].Repo.Name)
+ assert.Equal(t, "user2/repo1", webhookData.payloads[0].Repo.FullName)
+
+ // 4. Execute two Jobs
+ task := runner.fetchTask(t)
+ outcome := &mockTaskOutcome{
+ result: runnerv1.Result_RESULT_SUCCESS,
+ }
+ runner.execTask(t, task, outcome)
+
+ task = runner.fetchTask(t)
+ outcome = &mockTaskOutcome{
+ result: runnerv1.Result_RESULT_FAILURE,
+ }
+ runner.execTask(t, task, outcome)
+
+ // 7. validate the webhook is triggered
+ assert.Equal(t, "workflow_run", webhookData.triggeredEvent)
+ assert.Len(t, webhookData.payloads, 3)
+ assert.Equal(t, "completed", webhookData.payloads[1].Action)
+ assert.Equal(t, "push", webhookData.payloads[1].WorkflowRun.Event)
+
+ // 3. validate the webhook is triggered
+ assert.Equal(t, "workflow_run", webhookData.triggeredEvent)
+ assert.Len(t, webhookData.payloads, 3)
+ assert.Equal(t, "requested", webhookData.payloads[2].Action)
+ assert.Equal(t, "queued", webhookData.payloads[2].WorkflowRun.Status)
+ assert.Equal(t, "workflow_run", webhookData.payloads[2].WorkflowRun.Event)
+ assert.Equal(t, repo1.DefaultBranch, webhookData.payloads[2].WorkflowRun.HeadBranch)
+ assert.Equal(t, commitID, webhookData.payloads[2].WorkflowRun.HeadSha)
+ assert.Equal(t, "repo1", webhookData.payloads[2].Repo.Name)
+ assert.Equal(t, "user2/repo1", webhookData.payloads[2].Repo.FullName)
+}
+
+func testWebhookWorkflowRunDepthLimit(t *testing.T, webhookData *workflowRunWebhook) {
+ // 1. create a new webhook with special webhook for repo1
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ session := loginUser(t, "user2")
+ token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
+
+ testAPICreateWebhookForRepo(t, session, "user2", "repo1", webhookData.URL, "workflow_run")
+
+ repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1})
+
+ gitRepo1, err := gitrepo.OpenRepository(t.Context(), repo1)
+ assert.NoError(t, err)
+
+ // 2. trigger the webhooks
+
+ // add workflow file to the repo
+ // init the workflow
+ wfTreePath := ".gitea/workflows/push.yml"
+ wfFileContent := `name: Endless Loop
+on:
+ push:
+ workflow_run:
+ types:
+ - requested
+jobs:
+ dispatch:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo 'test the webhook'
+`
+ opts := getWorkflowCreateFileOptions(user2, repo1.DefaultBranch, "create "+wfTreePath, wfFileContent)
+ createWorkflowFile(t, token, "user2", "repo1", wfTreePath, opts)
+
+ commitID, err := gitRepo1.GetBranchCommitID(repo1.DefaultBranch)
+ assert.NoError(t, err)
+
+ // 3. validate the webhook is triggered
+ assert.Equal(t, "workflow_run", webhookData.triggeredEvent)
+ // 1x push + 5x workflow_run requested chain
+ assert.Len(t, webhookData.payloads, 6)
+ for i := range 6 {
+ assert.Equal(t, "requested", webhookData.payloads[i].Action)
+ assert.Equal(t, "queued", webhookData.payloads[i].WorkflowRun.Status)
+ assert.Equal(t, repo1.DefaultBranch, webhookData.payloads[i].WorkflowRun.HeadBranch)
+ assert.Equal(t, commitID, webhookData.payloads[i].WorkflowRun.HeadSha)
+ if i == 0 {
+ assert.Equal(t, "push", webhookData.payloads[i].WorkflowRun.Event)
+ } else {
+ assert.Equal(t, "workflow_run", webhookData.payloads[i].WorkflowRun.Event)
+ }
+ assert.Equal(t, "repo1", webhookData.payloads[i].Repo.Name)
+ assert.Equal(t, "user2/repo1", webhookData.payloads[i].Repo.FullName)
+ }
+}
diff --git a/tests/integration/repofiles_change_test.go b/tests/integration/repofiles_change_test.go
index 9f938c4099..dc389f5680 100644
--- a/tests/integration/repofiles_change_test.go
+++ b/tests/integration/repofiles_change_test.go
@@ -4,8 +4,9 @@
package integration
import (
+ "fmt"
"net/url"
- "path/filepath"
+ "path"
"strings"
"testing"
"time"
@@ -16,6 +17,7 @@ import (
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/contexttest"
files_service "code.gitea.io/gitea/services/repository/files"
@@ -57,6 +59,40 @@ func getUpdateRepoFilesOptions(repo *repo_model.Repository) *files_service.Chang
}
}
+func getUpdateRepoFilesRenameOptions(repo *repo_model.Repository) *files_service.ChangeRepoFilesOptions {
+ return &files_service.ChangeRepoFilesOptions{
+ Files: []*files_service.ChangeRepoFile{
+ // move normally
+ {
+ Operation: "rename",
+ FromTreePath: "README.md",
+ TreePath: "README.txt",
+ },
+ // move from in lfs
+ {
+ Operation: "rename",
+ FromTreePath: "crypt.bin",
+ TreePath: "crypt1.bin",
+ },
+ // move from lfs to normal
+ {
+ Operation: "rename",
+ FromTreePath: "jpeg.jpg",
+ TreePath: "jpeg.jpeg",
+ },
+ // move from normal to lfs
+ {
+ Operation: "rename",
+ FromTreePath: "CONTRIBUTING.md",
+ TreePath: "CONTRIBUTING.md.bin",
+ },
+ },
+ OldBranch: repo.DefaultBranch,
+ NewBranch: repo.DefaultBranch,
+ Message: "Rename files",
+ }
+}
+
func getDeleteRepoFilesOptions(repo *repo_model.Repository) *files_service.ChangeRepoFilesOptions {
return &files_service.ChangeRepoFilesOptions{
Files: []*files_service.ChangeRepoFile{
@@ -71,14 +107,14 @@ func getDeleteRepoFilesOptions(repo *repo_model.Repository) *files_service.Chang
NewBranch: repo.DefaultBranch,
Message: "Deletes README.md",
Author: &files_service.IdentityOptions{
- Name: "Bob Smith",
- Email: "bob@smith.com",
+ GitUserName: "Bob Smith",
+ GitUserEmail: "bob@smith.com",
},
Committer: nil,
}
}
-func getExpectedFileResponseForRepofilesDelete() *api.FileResponse {
+func getExpectedFileResponseForRepoFilesDelete() *api.FileResponse {
// Just returns fields that don't change, i.e. fields with commit SHAs and dates can't be determined
return &api.FileResponse{
Content: nil,
@@ -106,7 +142,7 @@ func getExpectedFileResponseForRepofilesDelete() *api.FileResponse {
}
}
-func getExpectedFileResponseForRepofilesCreate(commitID, lastCommitSHA string) *api.FileResponse {
+func getExpectedFileResponseForRepoFilesCreate(commitID string, lastCommit *git.Commit) *api.FileResponse {
treePath := "new/file.txt"
encoding := "base64"
content := "VGhpcyBpcyBhIE5FVyBmaWxl"
@@ -116,18 +152,20 @@ func getExpectedFileResponseForRepofilesCreate(commitID, lastCommitSHA string) *
downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + treePath
return &api.FileResponse{
Content: &api.ContentsResponse{
- Name: filepath.Base(treePath),
- Path: treePath,
- SHA: "103ff9234cefeee5ec5361d22b49fbb04d385885",
- LastCommitSHA: lastCommitSHA,
- Type: "file",
- Size: 18,
- Encoding: &encoding,
- Content: &content,
- URL: &selfURL,
- HTMLURL: &htmlURL,
- GitURL: &gitURL,
- DownloadURL: &downloadURL,
+ Name: path.Base(treePath),
+ Path: treePath,
+ SHA: "103ff9234cefeee5ec5361d22b49fbb04d385885",
+ LastCommitSHA: util.ToPointer(lastCommit.ID.String()),
+ LastCommitterDate: util.ToPointer(lastCommit.Committer.When),
+ LastAuthorDate: util.ToPointer(lastCommit.Author.When),
+ Type: "file",
+ Size: 18,
+ Encoding: &encoding,
+ Content: &content,
+ URL: &selfURL,
+ HTMLURL: &htmlURL,
+ GitURL: &gitURL,
+ DownloadURL: &downloadURL,
Links: &api.FileLinksResponse{
Self: &selfURL,
GitURL: &gitURL,
@@ -160,7 +198,7 @@ func getExpectedFileResponseForRepofilesCreate(commitID, lastCommitSHA string) *
SHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d",
},
},
- Message: "Updates README.md\n",
+ Message: "Creates new/file.txt\n",
Tree: &api.CommitMeta{
URL: setting.AppURL + "api/v1/repos/user2/repo1/git/trees/f93e3a1a1525fb5b91020da86e44810c87a2d7bc",
SHA: "f93e3a1a1525fb5b91020git dda86e44810c87a2d7bc",
@@ -175,7 +213,7 @@ func getExpectedFileResponseForRepofilesCreate(commitID, lastCommitSHA string) *
}
}
-func getExpectedFileResponseForRepofilesUpdate(commitID, filename, lastCommitSHA string) *api.FileResponse {
+func getExpectedFileResponseForRepoFilesUpdate(commitID, filename, lastCommitSHA string, lastCommitterWhen, lastAuthorWhen time.Time) *api.FileResponse {
encoding := "base64"
content := "VGhpcyBpcyBVUERBVEVEIGNvbnRlbnQgZm9yIHRoZSBSRUFETUUgZmlsZQ=="
selfURL := setting.AppURL + "api/v1/repos/user2/repo1/contents/" + filename + "?ref=master"
@@ -184,18 +222,20 @@ func getExpectedFileResponseForRepofilesUpdate(commitID, filename, lastCommitSHA
downloadURL := setting.AppURL + "user2/repo1/raw/branch/master/" + filename
return &api.FileResponse{
Content: &api.ContentsResponse{
- Name: filename,
- Path: filename,
- SHA: "dbf8d00e022e05b7e5cf7e535de857de57925647",
- LastCommitSHA: lastCommitSHA,
- Type: "file",
- Size: 43,
- Encoding: &encoding,
- Content: &content,
- URL: &selfURL,
- HTMLURL: &htmlURL,
- GitURL: &gitURL,
- DownloadURL: &downloadURL,
+ Name: filename,
+ Path: filename,
+ SHA: "dbf8d00e022e05b7e5cf7e535de857de57925647",
+ LastCommitSHA: util.ToPointer(lastCommitSHA),
+ LastCommitterDate: util.ToPointer(lastCommitterWhen),
+ LastAuthorDate: util.ToPointer(lastAuthorWhen),
+ Type: "file",
+ Size: 43,
+ Encoding: &encoding,
+ Content: &content,
+ URL: &selfURL,
+ HTMLURL: &htmlURL,
+ GitURL: &gitURL,
+ DownloadURL: &downloadURL,
Links: &api.FileLinksResponse{
Self: &selfURL,
GitURL: &gitURL,
@@ -243,11 +283,119 @@ func getExpectedFileResponseForRepofilesUpdate(commitID, filename, lastCommitSHA
}
}
+func getExpectedFileResponseForRepoFilesUpdateRename(commitID, lastCommitSHA string) *api.FilesResponse {
+ details := []struct {
+ filename, sha, content string
+ size int64
+ lfsOid *string
+ lfsSize *int64
+ }{
+ {
+ filename: "README.txt",
+ sha: "8276d2a29779af982c0afa976bdb793b52d442a8",
+ size: 22,
+ content: "IyBBbiBMRlMtZW5hYmxlZCByZXBvCg==",
+ },
+ {
+ filename: "crypt1.bin",
+ sha: "d4a41a0d4db4949e129bd22f871171ea988103ef",
+ size: 129,
+ content: "dmVyc2lvbiBodHRwczovL2dpdC1sZnMuZ2l0aHViLmNvbS9zcGVjL3YxCm9pZCBzaGEyNTY6MmVjY2RiNDM4MjVkMmE0OWQ5OWQ1NDJkYWEyMDA3NWNmZjFkOTdkOWQyMzQ5YTg5NzdlZmU5YzAzNjYxNzM3YwpzaXplIDIwNDgK",
+ lfsOid: util.ToPointer("2eccdb43825d2a49d99d542daa20075cff1d97d9d2349a8977efe9c03661737c"),
+ lfsSize: util.ToPointer(int64(2048)),
+ },
+ {
+ filename: "jpeg.jpeg",
+ sha: "71911bf48766c7181518c1070911019fbb00b1fc",
+ size: 107,
+ content: "/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k=",
+ },
+ {
+ filename: "CONTRIBUTING.md.bin",
+ sha: "2b6c6c4eaefa24b22f2092c3d54b263ff26feb58",
+ size: 127,
+ content: "dmVyc2lvbiBodHRwczovL2dpdC1sZnMuZ2l0aHViLmNvbS9zcGVjL3YxCm9pZCBzaGEyNTY6N2I2YjJjODhkYmE5Zjc2MGExYTU4NDY5YjY3ZmVlMmI2OThlZjdlOTM5OWM0Y2E0ZjM0YTE0Y2NiZTM5ZjYyMwpzaXplIDI3Cg==",
+ lfsOid: util.ToPointer("7b6b2c88dba9f760a1a58469b67fee2b698ef7e9399c4ca4f34a14ccbe39f623"),
+ lfsSize: util.ToPointer(int64(27)),
+ },
+ }
+
+ var responses []*api.ContentsResponse
+ for _, detail := range details {
+ selfURL := setting.AppURL + "api/v1/repos/user2/lfs/contents/" + detail.filename + "?ref=master"
+ htmlURL := setting.AppURL + "user2/lfs/src/branch/master/" + detail.filename
+ gitURL := setting.AppURL + "api/v1/repos/user2/lfs/git/blobs/" + detail.sha
+ downloadURL := setting.AppURL + "user2/lfs/raw/branch/master/" + detail.filename
+ // don't set time related fields because there might be different time in one operation
+ responses = append(responses, &api.ContentsResponse{
+ Name: detail.filename,
+ Path: detail.filename,
+ SHA: detail.sha,
+ LastCommitSHA: util.ToPointer(lastCommitSHA),
+ Type: "file",
+ Size: detail.size,
+ Encoding: util.ToPointer("base64"),
+ Content: &detail.content,
+ URL: &selfURL,
+ HTMLURL: &htmlURL,
+ GitURL: &gitURL,
+ DownloadURL: &downloadURL,
+ Links: &api.FileLinksResponse{
+ Self: &selfURL,
+ GitURL: &gitURL,
+ HTMLURL: &htmlURL,
+ },
+ LfsOid: detail.lfsOid,
+ LfsSize: detail.lfsSize,
+ })
+ }
+
+ return &api.FilesResponse{
+ Files: responses,
+ Commit: &api.FileCommitResponse{
+ CommitMeta: api.CommitMeta{
+ URL: setting.AppURL + "api/v1/repos/user2/lfs/git/commits/" + commitID,
+ SHA: commitID,
+ },
+ HTMLURL: setting.AppURL + "user2/lfs/commit/" + commitID,
+ Author: &api.CommitUser{
+ Identity: api.Identity{
+ Name: "User Two",
+ Email: "user2@noreply.example.org",
+ },
+ },
+ Committer: &api.CommitUser{
+ Identity: api.Identity{
+ Name: "User Two",
+ Email: "user2@noreply.example.org",
+ },
+ },
+ Parents: []*api.CommitMeta{
+ {
+ URL: setting.AppURL + "api/v1/repos/user2/lfs/git/commits/73cf03db6ece34e12bf91e8853dc58f678f2f82d",
+ SHA: "73cf03db6ece34e12bf91e8853dc58f678f2f82d",
+ },
+ },
+ Message: "Rename files\n",
+ Tree: &api.CommitMeta{
+ URL: setting.AppURL + "api/v1/repos/user2/lfs/git/trees/5307376dc3a5557dc1c403c29a8984668ca9ecb5",
+ SHA: "5307376dc3a5557dc1c403c29a8984668ca9ecb5",
+ },
+ },
+ Verification: &api.PayloadCommitVerification{
+ Verified: false,
+ Reason: "gpg.error.not_signed_commit",
+ Signature: "",
+ Payload: "",
+ },
+ }
+}
+
func TestChangeRepoFilesForCreate(t *testing.T) {
// setup
onGiteaRun(t, func(t *testing.T, u *url.URL) {
ctx, _ := contexttest.MockContext(t, "user2/repo1")
- ctx.SetPathParam(":id", "1")
+ ctx.SetPathParam("id", "1")
contexttest.LoadRepo(t, ctx, 1)
contexttest.LoadRepoCommit(t, ctx)
contexttest.LoadUser(t, ctx, 2)
@@ -268,14 +416,14 @@ func TestChangeRepoFilesForCreate(t *testing.T) {
commitID, _ := gitRepo.GetBranchCommitID(opts.NewBranch)
lastCommit, _ := gitRepo.GetCommitByPath("new/file.txt")
- expectedFileResponse := getExpectedFileResponseForRepofilesCreate(commitID, lastCommit.ID.String())
+ expectedFileResponse := getExpectedFileResponseForRepoFilesCreate(commitID, lastCommit)
assert.NotNil(t, expectedFileResponse)
if expectedFileResponse != nil {
- assert.EqualValues(t, expectedFileResponse.Content, filesResponse.Files[0])
- assert.EqualValues(t, expectedFileResponse.Commit.SHA, filesResponse.Commit.SHA)
- assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, filesResponse.Commit.HTMLURL)
- assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, filesResponse.Commit.Author.Email)
- assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, filesResponse.Commit.Author.Name)
+ assert.Equal(t, expectedFileResponse.Content, filesResponse.Files[0])
+ assert.Equal(t, expectedFileResponse.Commit.SHA, filesResponse.Commit.SHA)
+ assert.Equal(t, expectedFileResponse.Commit.HTMLURL, filesResponse.Commit.HTMLURL)
+ assert.Equal(t, expectedFileResponse.Commit.Author.Email, filesResponse.Commit.Author.Email)
+ assert.Equal(t, expectedFileResponse.Commit.Author.Name, filesResponse.Commit.Author.Name)
}
})
}
@@ -284,7 +432,7 @@ func TestChangeRepoFilesForUpdate(t *testing.T) {
// setup
onGiteaRun(t, func(t *testing.T, u *url.URL) {
ctx, _ := contexttest.MockContext(t, "user2/repo1")
- ctx.SetPathParam(":id", "1")
+ ctx.SetPathParam("id", "1")
contexttest.LoadRepo(t, ctx, 1)
contexttest.LoadRepoCommit(t, ctx)
contexttest.LoadUser(t, ctx, 2)
@@ -305,12 +453,12 @@ func TestChangeRepoFilesForUpdate(t *testing.T) {
commit, _ := gitRepo.GetBranchCommit(opts.NewBranch)
lastCommit, _ := commit.GetCommitByPath(opts.Files[0].TreePath)
- expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.Files[0].TreePath, lastCommit.ID.String())
- assert.EqualValues(t, expectedFileResponse.Content, filesResponse.Files[0])
- assert.EqualValues(t, expectedFileResponse.Commit.SHA, filesResponse.Commit.SHA)
- assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, filesResponse.Commit.HTMLURL)
- assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, filesResponse.Commit.Author.Email)
- assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, filesResponse.Commit.Author.Name)
+ expectedFileResponse := getExpectedFileResponseForRepoFilesUpdate(commit.ID.String(), opts.Files[0].TreePath, lastCommit.ID.String(), lastCommit.Committer.When, lastCommit.Author.When)
+ assert.Equal(t, expectedFileResponse.Content, filesResponse.Files[0])
+ assert.Equal(t, expectedFileResponse.Commit.SHA, filesResponse.Commit.SHA)
+ assert.Equal(t, expectedFileResponse.Commit.HTMLURL, filesResponse.Commit.HTMLURL)
+ assert.Equal(t, expectedFileResponse.Commit.Author.Email, filesResponse.Commit.Author.Email)
+ assert.Equal(t, expectedFileResponse.Commit.Author.Name, filesResponse.Commit.Author.Name)
})
}
@@ -318,7 +466,7 @@ func TestChangeRepoFilesForUpdateWithFileMove(t *testing.T) {
// setup
onGiteaRun(t, func(t *testing.T, u *url.URL) {
ctx, _ := contexttest.MockContext(t, "user2/repo1")
- ctx.SetPathParam(":id", "1")
+ ctx.SetPathParam("id", "1")
contexttest.LoadRepo(t, ctx, 1)
contexttest.LoadRepoCommit(t, ctx)
contexttest.LoadUser(t, ctx, 2)
@@ -341,7 +489,7 @@ func TestChangeRepoFilesForUpdateWithFileMove(t *testing.T) {
commit, _ := gitRepo.GetBranchCommit(opts.NewBranch)
lastCommit, _ := commit.GetCommitByPath(opts.Files[0].TreePath)
- expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.Files[0].TreePath, lastCommit.ID.String())
+ expectedFileResponse := getExpectedFileResponseForRepoFilesUpdate(commit.ID.String(), opts.Files[0].TreePath, lastCommit.ID.String(), lastCommit.Committer.When, lastCommit.Author.When)
// assert that the old file no longer exists in the last commit of the branch
fromEntry, err := commit.GetTreeEntryByPath(opts.Files[0].FromTreePath)
switch err.(type) {
@@ -355,12 +503,44 @@ func TestChangeRepoFilesForUpdateWithFileMove(t *testing.T) {
assert.Nil(t, fromEntry) // Should no longer exist here
assert.NotNil(t, toEntry) // Should exist here
// assert SHA has remained the same but paths use the new file name
- assert.EqualValues(t, expectedFileResponse.Content.SHA, filesResponse.Files[0].SHA)
- assert.EqualValues(t, expectedFileResponse.Content.Name, filesResponse.Files[0].Name)
- assert.EqualValues(t, expectedFileResponse.Content.Path, filesResponse.Files[0].Path)
- assert.EqualValues(t, expectedFileResponse.Content.URL, filesResponse.Files[0].URL)
- assert.EqualValues(t, expectedFileResponse.Commit.SHA, filesResponse.Commit.SHA)
- assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, filesResponse.Commit.HTMLURL)
+ assert.Equal(t, expectedFileResponse.Content.SHA, filesResponse.Files[0].SHA)
+ assert.Equal(t, expectedFileResponse.Content.Name, filesResponse.Files[0].Name)
+ assert.Equal(t, expectedFileResponse.Content.Path, filesResponse.Files[0].Path)
+ assert.Equal(t, expectedFileResponse.Content.URL, filesResponse.Files[0].URL)
+ assert.Equal(t, expectedFileResponse.Commit.SHA, filesResponse.Commit.SHA)
+ assert.Equal(t, expectedFileResponse.Commit.HTMLURL, filesResponse.Commit.HTMLURL)
+ })
+}
+
+func TestChangeRepoFilesForUpdateWithFileRename(t *testing.T) {
+ onGiteaRun(t, func(t *testing.T, u *url.URL) {
+ ctx, _ := contexttest.MockContext(t, "user2/lfs")
+ ctx.SetPathParam("id", "54")
+ contexttest.LoadRepo(t, ctx, 54)
+ contexttest.LoadRepoCommit(t, ctx)
+ contexttest.LoadUser(t, ctx, 2)
+ contexttest.LoadGitRepo(t, ctx)
+ defer ctx.Repo.GitRepo.Close()
+
+ repo := ctx.Repo.Repository
+ opts := getUpdateRepoFilesRenameOptions(repo)
+
+ // test
+ filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, ctx.Doer, opts)
+
+ // asserts
+ assert.NoError(t, err)
+ gitRepo, _ := gitrepo.OpenRepository(git.DefaultContext, repo)
+ defer gitRepo.Close()
+
+ commit, _ := gitRepo.GetBranchCommit(repo.DefaultBranch)
+ lastCommit, _ := commit.GetCommitByPath(opts.Files[0].TreePath)
+ expectedFileResponse := getExpectedFileResponseForRepoFilesUpdateRename(commit.ID.String(), lastCommit.ID.String())
+ for _, file := range filesResponse.Files {
+ file.LastCommitterDate, file.LastAuthorDate = nil, nil // there might be different time in one operation, so we ignore them
+ }
+ assert.Len(t, filesResponse.Files, 4)
+ assert.Equal(t, expectedFileResponse.Files, filesResponse.Files)
})
}
@@ -369,7 +549,7 @@ func TestChangeRepoFilesWithoutBranchNames(t *testing.T) {
// setup
onGiteaRun(t, func(t *testing.T, u *url.URL) {
ctx, _ := contexttest.MockContext(t, "user2/repo1")
- ctx.SetPathParam(":id", "1")
+ ctx.SetPathParam("id", "1")
contexttest.LoadRepo(t, ctx, 1)
contexttest.LoadRepoCommit(t, ctx)
contexttest.LoadUser(t, ctx, 2)
@@ -392,8 +572,8 @@ func TestChangeRepoFilesWithoutBranchNames(t *testing.T) {
commit, _ := gitRepo.GetBranchCommit(repo.DefaultBranch)
lastCommit, _ := commit.GetCommitByPath(opts.Files[0].TreePath)
- expectedFileResponse := getExpectedFileResponseForRepofilesUpdate(commit.ID.String(), opts.Files[0].TreePath, lastCommit.ID.String())
- assert.EqualValues(t, expectedFileResponse.Content, filesResponse.Files[0])
+ expectedFileResponse := getExpectedFileResponseForRepoFilesUpdate(commit.ID.String(), opts.Files[0].TreePath, lastCommit.ID.String(), lastCommit.Committer.When, lastCommit.Author.When)
+ assert.Equal(t, expectedFileResponse.Content, filesResponse.Files[0])
})
}
@@ -405,7 +585,7 @@ func testDeleteRepoFiles(t *testing.T, u *url.URL) {
// setup
unittest.PrepareTestEnv(t)
ctx, _ := contexttest.MockContext(t, "user2/repo1")
- ctx.SetPathParam(":id", "1")
+ ctx.SetPathParam("id", "1")
contexttest.LoadRepo(t, ctx, 1)
contexttest.LoadRepoCommit(t, ctx)
contexttest.LoadUser(t, ctx, 2)
@@ -418,13 +598,13 @@ func testDeleteRepoFiles(t *testing.T, u *url.URL) {
t.Run("Delete README.md file", func(t *testing.T) {
filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts)
assert.NoError(t, err)
- expectedFileResponse := getExpectedFileResponseForRepofilesDelete()
+ expectedFileResponse := getExpectedFileResponseForRepoFilesDelete()
assert.NotNil(t, filesResponse)
assert.Nil(t, filesResponse.Files[0])
- assert.EqualValues(t, expectedFileResponse.Commit.Message, filesResponse.Commit.Message)
- assert.EqualValues(t, expectedFileResponse.Commit.Author.Identity, filesResponse.Commit.Author.Identity)
- assert.EqualValues(t, expectedFileResponse.Commit.Committer.Identity, filesResponse.Commit.Committer.Identity)
- assert.EqualValues(t, expectedFileResponse.Verification, filesResponse.Verification)
+ assert.Equal(t, expectedFileResponse.Commit.Message, filesResponse.Commit.Message)
+ assert.Equal(t, expectedFileResponse.Commit.Author.Identity, filesResponse.Commit.Author.Identity)
+ assert.Equal(t, expectedFileResponse.Commit.Committer.Identity, filesResponse.Commit.Committer.Identity)
+ assert.Equal(t, expectedFileResponse.Verification, filesResponse.Verification)
})
t.Run("Verify README.md has been deleted", func(t *testing.T) {
@@ -444,7 +624,7 @@ func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) {
// setup
unittest.PrepareTestEnv(t)
ctx, _ := contexttest.MockContext(t, "user2/repo1")
- ctx.SetPathParam(":id", "1")
+ ctx.SetPathParam("id", "1")
contexttest.LoadRepo(t, ctx, 1)
contexttest.LoadRepoCommit(t, ctx)
contexttest.LoadUser(t, ctx, 2)
@@ -460,13 +640,13 @@ func testDeleteRepoFilesWithoutBranchNames(t *testing.T, u *url.URL) {
t.Run("Delete README.md without Branch Name", func(t *testing.T) {
filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts)
assert.NoError(t, err)
- expectedFileResponse := getExpectedFileResponseForRepofilesDelete()
+ expectedFileResponse := getExpectedFileResponseForRepoFilesDelete()
assert.NotNil(t, filesResponse)
assert.Nil(t, filesResponse.Files[0])
- assert.EqualValues(t, expectedFileResponse.Commit.Message, filesResponse.Commit.Message)
- assert.EqualValues(t, expectedFileResponse.Commit.Author.Identity, filesResponse.Commit.Author.Identity)
- assert.EqualValues(t, expectedFileResponse.Commit.Committer.Identity, filesResponse.Commit.Committer.Identity)
- assert.EqualValues(t, expectedFileResponse.Verification, filesResponse.Verification)
+ assert.Equal(t, expectedFileResponse.Commit.Message, filesResponse.Commit.Message)
+ assert.Equal(t, expectedFileResponse.Commit.Author.Identity, filesResponse.Commit.Author.Identity)
+ assert.Equal(t, expectedFileResponse.Commit.Committer.Identity, filesResponse.Commit.Committer.Identity)
+ assert.Equal(t, expectedFileResponse.Verification, filesResponse.Verification)
})
}
@@ -474,7 +654,7 @@ func TestChangeRepoFilesErrors(t *testing.T) {
// setup
onGiteaRun(t, func(t *testing.T, u *url.URL) {
ctx, _ := contexttest.MockContext(t, "user2/repo1")
- ctx.SetPathParam(":id", "1")
+ ctx.SetPathParam("id", "1")
contexttest.LoadRepo(t, ctx, 1)
contexttest.LoadRepoCommit(t, ctx)
contexttest.LoadUser(t, ctx, 2)
@@ -490,7 +670,7 @@ func TestChangeRepoFilesErrors(t *testing.T) {
filesResponse, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, doer, opts)
assert.Error(t, err)
assert.Nil(t, filesResponse)
- expectedError := "branch does not exist [name: " + opts.OldBranch + "]"
+ expectedError := fmt.Sprintf("branch does not exist [repo_id: %d name: %s]", repo.ID, opts.OldBranch)
assert.EqualError(t, err, expectedError)
})
diff --git a/tests/integration/session_test.go b/tests/integration/session_test.go
index b18a25827d..f72e2e24b7 100644
--- a/tests/integration/session_test.go
+++ b/tests/integration/session_test.go
@@ -27,11 +27,11 @@ func Test_RegenerateSession(t *testing.T) {
sess, err := auth.RegenerateSession(db.DefaultContext, "", key)
assert.NoError(t, err)
- assert.EqualValues(t, key, sess.Key)
+ assert.Equal(t, key, sess.Key)
assert.Empty(t, sess.Data)
sess, err = auth.ReadSession(db.DefaultContext, key2)
assert.NoError(t, err)
- assert.EqualValues(t, key2, sess.Key)
+ assert.Equal(t, key2, sess.Key)
assert.Empty(t, sess.Data)
}
diff --git a/tests/integration/setting_test.go b/tests/integration/setting_test.go
index 9dad9ca716..64fd28c5e9 100644
--- a/tests/integration/setting_test.go
+++ b/tests/integration/setting_test.go
@@ -8,6 +8,7 @@ import (
"testing"
"code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
@@ -92,8 +93,7 @@ func TestSettingShowUserEmailProfile(t *testing.T) {
func TestSettingLandingPage(t *testing.T) {
defer tests.PrepareTestEnv(t)()
-
- landingPage := setting.LandingPageURL
+ defer test.MockVariableValue(&setting.LandingPageURL)()
setting.LandingPageURL = setting.LandingPageHome
req := NewRequest(t, "GET", "/")
@@ -113,6 +113,4 @@ func TestSettingLandingPage(t *testing.T) {
req = NewRequest(t, "GET", "/")
resp = MakeRequest(t, req, http.StatusSeeOther)
assert.Equal(t, "/user/login", resp.Header().Get("Location"))
-
- setting.LandingPageURL = landingPage
}
diff --git a/tests/integration/signin_test.go b/tests/integration/signin_test.go
index abad9eb5e5..fa37145d98 100644
--- a/tests/integration/signin_test.go
+++ b/tests/integration/signin_test.go
@@ -9,14 +9,22 @@ import (
"strings"
"testing"
+ auth_model "code.gitea.io/gitea/models/auth"
+ "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/translation"
+ "code.gitea.io/gitea/modules/web"
+ "code.gitea.io/gitea/routers"
+ "code.gitea.io/gitea/routers/web/auth"
+ "code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/tests"
+ "github.com/markbates/goth"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func testLoginFailed(t *testing.T, username, password, message string) {
@@ -30,7 +38,7 @@ func testLoginFailed(t *testing.T, username, password, message string) {
htmlDoc := NewHTMLParser(t, resp.Body)
resultMsg := htmlDoc.doc.Find(".ui.message>p").Text()
- assert.EqualValues(t, message, resultMsg)
+ assert.Equal(t, message, resultMsg)
}
func TestSignin(t *testing.T) {
@@ -42,7 +50,7 @@ func TestSignin(t *testing.T) {
user.Name = "testuser"
user.LowerName = strings.ToLower(user.Name)
user.ID = 0
- unittest.AssertSuccessfulInsert(t, user)
+ require.NoError(t, db.Insert(db.DefaultContext, user))
samples := []struct {
username string
@@ -74,7 +82,7 @@ func TestSigninWithRememberMe(t *testing.T) {
})
session.MakeRequest(t, req, http.StatusSeeOther)
- c := session.GetCookie(setting.CookieRememberName)
+ c := session.GetRawCookie(setting.CookieRememberName)
assert.NotNil(t, c)
session = emptyTestSession(t)
@@ -93,19 +101,33 @@ func TestSigninWithRememberMe(t *testing.T) {
session.MakeRequest(t, req, http.StatusOK)
}
-func TestEnablePasswordSignInForm(t *testing.T) {
+func TestEnablePasswordSignInFormAndEnablePasskeyAuth(t *testing.T) {
defer tests.PrepareTestEnv(t)()
+ mockLinkAccount := func(ctx *context.Context) {
+ authSource := auth_model.Source{ID: 1}
+ gothUser := goth.User{Email: "invalid-email", Name: "."}
+ _ = auth.Oauth2SetLinkAccountData(ctx, auth.LinkAccountData{AuthSourceID: authSource.ID, GothUser: gothUser})
+ }
+
t.Run("EnablePasswordSignInForm=false", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
defer test.MockVariableValue(&setting.Service.EnablePasswordSignInForm, false)()
req := NewRequest(t, "GET", "/user/login")
resp := MakeRequest(t, req, http.StatusOK)
- NewHTMLParser(t, resp.Body).AssertElement(t, "form[action='/user/login']", false)
+ doc := NewHTMLParser(t, resp.Body)
+ AssertHTMLElement(t, doc, "form[action='/user/login']", false)
req = NewRequest(t, "POST", "/user/login")
MakeRequest(t, req, http.StatusForbidden)
+
+ req = NewRequest(t, "GET", "/user/link_account")
+ defer web.RouteMockReset()
+ web.RouteMock(web.MockAfterMiddlewares, mockLinkAccount)
+ resp = MakeRequest(t, req, http.StatusOK)
+ doc = NewHTMLParser(t, resp.Body)
+ AssertHTMLElement(t, doc, "form[action='/user/link_account_signin']", false)
})
t.Run("EnablePasswordSignInForm=true", func(t *testing.T) {
@@ -114,9 +136,66 @@ func TestEnablePasswordSignInForm(t *testing.T) {
req := NewRequest(t, "GET", "/user/login")
resp := MakeRequest(t, req, http.StatusOK)
- NewHTMLParser(t, resp.Body).AssertElement(t, "form[action='/user/login']", true)
+ doc := NewHTMLParser(t, resp.Body)
+ AssertHTMLElement(t, doc, "form[action='/user/login']", true)
req = NewRequest(t, "POST", "/user/login")
MakeRequest(t, req, http.StatusOK)
+
+ req = NewRequest(t, "GET", "/user/link_account")
+ defer web.RouteMockReset()
+ web.RouteMock(web.MockAfterMiddlewares, mockLinkAccount)
+ resp = MakeRequest(t, req, http.StatusOK)
+ doc = NewHTMLParser(t, resp.Body)
+ AssertHTMLElement(t, doc, "form[action='/user/link_account_signin']", true)
+ })
+
+ t.Run("EnablePasskeyAuth=false", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+ defer test.MockVariableValue(&setting.Service.EnablePasskeyAuth, false)()
+
+ req := NewRequest(t, "GET", "/user/login")
+ resp := MakeRequest(t, req, http.StatusOK)
+ doc := NewHTMLParser(t, resp.Body)
+ AssertHTMLElement(t, doc, ".signin-passkey", false)
+ })
+
+ t.Run("EnablePasskeyAuth=true", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+ defer test.MockVariableValue(&setting.Service.EnablePasskeyAuth, true)()
+
+ req := NewRequest(t, "GET", "/user/login")
+ resp := MakeRequest(t, req, http.StatusOK)
+ doc := NewHTMLParser(t, resp.Body)
+ AssertHTMLElement(t, doc, ".signin-passkey", true)
+ })
+}
+
+func TestRequireSignInView(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+ t.Run("NoRequireSignInView", func(t *testing.T) {
+ require.False(t, setting.Service.RequireSignInViewStrict)
+ require.False(t, setting.Service.BlockAnonymousAccessExpensive)
+ req := NewRequest(t, "GET", "/user2/repo1/src/branch/master")
+ MakeRequest(t, req, http.StatusOK)
+ })
+ t.Run("RequireSignInView", func(t *testing.T) {
+ defer test.MockVariableValue(&setting.Service.RequireSignInViewStrict, true)()
+ defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
+ req := NewRequest(t, "GET", "/user2/repo1/src/branch/master")
+ resp := MakeRequest(t, req, http.StatusSeeOther)
+ assert.Equal(t, "/user/login", resp.Header().Get("Location"))
+ })
+ t.Run("BlockAnonymousAccessExpensive", func(t *testing.T) {
+ defer test.MockVariableValue(&setting.Service.RequireSignInViewStrict, false)()
+ defer test.MockVariableValue(&setting.Service.BlockAnonymousAccessExpensive, true)()
+ defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())()
+
+ req := NewRequest(t, "GET", "/user2/repo1")
+ MakeRequest(t, req, http.StatusOK)
+
+ req = NewRequest(t, "GET", "/user2/repo1/src/branch/master")
+ resp := MakeRequest(t, req, http.StatusSeeOther)
+ assert.Equal(t, "/user/login", resp.Header().Get("Location"))
})
}
diff --git a/tests/integration/signup_test.go b/tests/integration/signup_test.go
index e9a05201ee..c08f57d33e 100644
--- a/tests/integration/signup_test.go
+++ b/tests/integration/signup_test.go
@@ -9,6 +9,7 @@ import (
"strings"
"testing"
+ "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
@@ -21,8 +22,7 @@ import (
func TestSignup(t *testing.T) {
defer tests.PrepareTestEnv(t)()
-
- setting.Service.EnableCaptcha = false
+ defer test.MockVariableValue(&setting.Service.EnableCaptcha, false)()
req := NewRequestWithValues(t, "POST", "/user/sign_up", map[string]string{
"user_name": "exampleUser",
@@ -39,9 +39,8 @@ func TestSignup(t *testing.T) {
func TestSignupAsRestricted(t *testing.T) {
defer tests.PrepareTestEnv(t)()
-
- setting.Service.EnableCaptcha = false
- setting.Service.DefaultUserIsRestricted = true
+ defer test.MockVariableValue(&setting.Service.EnableCaptcha, false)()
+ defer test.MockVariableValue(&setting.Service.DefaultUserIsRestricted, true)()
req := NewRequestWithValues(t, "POST", "/user/sign_up", map[string]string{
"user_name": "restrictedUser",
@@ -61,8 +60,7 @@ func TestSignupAsRestricted(t *testing.T) {
func TestSignupEmailValidation(t *testing.T) {
defer tests.PrepareTestEnv(t)()
-
- setting.Service.EnableCaptcha = false
+ defer test.MockVariableValue(&setting.Service.EnableCaptcha, false)()
tests := []struct {
email string
@@ -99,34 +97,39 @@ func TestSignupEmailActive(t *testing.T) {
// try to sign up and send the activation email
req := NewRequestWithValues(t, "POST", "/user/sign_up", map[string]string{
- "user_name": "test-user-1",
- "email": "email-1@example.com",
+ "user_name": "Test-User-1",
+ "email": "EmAiL-1@example.com",
"password": "password1",
"retype": "password1",
})
resp := MakeRequest(t, req, http.StatusOK)
- assert.Contains(t, resp.Body.String(), `A new confirmation email has been sent to <b>email-1@example.com</b>.`)
+ assert.Contains(t, resp.Body.String(), `A new confirmation email has been sent to <b>EmAiL-1@example.com</b>.`)
// access "user/activate" means trying to re-send the activation email
session := loginUserWithPassword(t, "test-user-1", "password1")
resp = session.MakeRequest(t, NewRequest(t, "GET", "/user/activate"), http.StatusOK)
assert.Contains(t, resp.Body.String(), "You have already requested an activation email recently")
- // access anywhere else will see a "Activate Your Account" prompt, and there is a chance to change email
+ // access anywhere else will see an "Activate Your Account" prompt, and there is a chance to change email
resp = session.MakeRequest(t, NewRequest(t, "GET", "/user/issues"), http.StatusOK)
assert.Contains(t, resp.Body.String(), `<input id="change-email" name="change_email" `)
// post to "user/activate" with a new email
session.MakeRequest(t, NewRequestWithValues(t, "POST", "/user/activate", map[string]string{"change_email": "email-changed@example.com"}), http.StatusSeeOther)
- user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "test-user-1"})
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "Test-User-1"})
assert.Equal(t, "email-changed@example.com", user.Email)
email := unittest.AssertExistsAndLoadBean(t, &user_model.EmailAddress{Email: "email-changed@example.com"})
assert.False(t, email.IsActivated)
assert.True(t, email.IsPrimary)
+ // generate an activation code from lower-cased email
+ activationCode := user_model.GenerateUserTimeLimitCode(&user_model.TimeLimitCodeOptions{Purpose: user_model.TimeLimitCodeActivateAccount}, user)
+ // and update the user email to case-sensitive, it shouldn't affect the verification later
+ _, _ = db.Exec(db.DefaultContext, "UPDATE `user` SET email=? WHERE id=?", "EmAiL-changed@example.com", user.ID)
+ user = unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "Test-User-1"})
+ assert.Equal(t, "EmAiL-changed@example.com", user.Email)
+
// access "user/activate" with a valid activation code, then get the "verify password" page
- user = unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "test-user-1"})
- activationCode := user.GenerateEmailActivateCode(user.Email)
resp = session.MakeRequest(t, NewRequest(t, "GET", "/user/activate?code="+activationCode), http.StatusOK)
assert.Contains(t, resp.Body.String(), `<input id="verify-password"`)
@@ -138,7 +141,7 @@ func TestSignupEmailActive(t *testing.T) {
resp = session.MakeRequest(t, req, http.StatusOK)
assert.Contains(t, resp.Body.String(), `Your password does not match`)
assert.Contains(t, resp.Body.String(), `<input id="verify-password"`)
- user = unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "test-user-1"})
+ user = unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "Test-User-1"})
assert.False(t, user.IsActive)
// then use a correct password, the user should be activated
@@ -148,6 +151,6 @@ func TestSignupEmailActive(t *testing.T) {
})
resp = session.MakeRequest(t, req, http.StatusSeeOther)
assert.Equal(t, "/", test.RedirectURL(resp))
- user = unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "test-user-1"})
+ user = unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "Test-User-1"})
assert.True(t, user.IsActive)
}
diff --git a/tests/integration/ssh_key_test.go b/tests/integration/ssh_key_test.go
index eb3a3e926a..b34a986be3 100644
--- a/tests/integration/ssh_key_test.go
+++ b/tests/integration/ssh_key_test.go
@@ -27,7 +27,7 @@ func doCheckRepositoryEmptyStatus(ctx APITestContext, isEmpty bool) func(*testin
func doAddChangesToCheckout(dstPath, filename string) func(*testing.T) {
return func(t *testing.T) {
- assert.NoError(t, os.WriteFile(filepath.Join(dstPath, filename), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s at time: %v", dstPath, time.Now())), 0o644))
+ assert.NoError(t, os.WriteFile(filepath.Join(dstPath, filename), fmt.Appendf(nil, "# Testing Repository\n\nOriginally created in: %s at time: %v", dstPath, time.Now()), 0o644))
assert.NoError(t, git.AddChanges(dstPath, true))
signature := git.Signature{
Email: "test@example.com",
@@ -51,7 +51,7 @@ func testPushDeployKeyOnEmptyRepo(t *testing.T, u *url.URL) {
ctx := NewAPITestContext(t, "user2", "deploy-key-empty-repo-1", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
ctxWithDeleteRepo := NewAPITestContext(t, "user2", "deploy-key-empty-repo-1", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
- keyname := fmt.Sprintf("%s-push", ctx.Reponame)
+ keyname := ctx.Reponame + "-push"
u.Path = ctx.GitPath()
t.Run("CreateEmptyRepository", doAPICreateRepository(ctx, true))
@@ -89,7 +89,7 @@ func testKeyOnlyOneType(t *testing.T, u *url.URL) {
reponame := "ssh-key-test-repo"
username := "user2"
u.Path = fmt.Sprintf("%s/%s.git", username, reponame)
- keyname := fmt.Sprintf("%s-push", reponame)
+ keyname := reponame + "-push"
// OK login
ctx := NewAPITestContext(t, username, reponame, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
diff --git a/tests/integration/timetracking_test.go b/tests/integration/timetracking_test.go
index d459de5df6..ebe084ccdc 100644
--- a/tests/integration/timetracking_test.go
+++ b/tests/integration/timetracking_test.go
@@ -42,41 +42,41 @@ func testViewTimetrackingControls(t *testing.T, session *TestSession, user, repo
htmlDoc := NewHTMLParser(t, resp.Body)
- htmlDoc.AssertElement(t, ".issue-start-time", canTrackTime)
- htmlDoc.AssertElement(t, ".issue-add-time", canTrackTime)
+ AssertHTMLElement(t, htmlDoc, ".issue-start-time", canTrackTime)
+ AssertHTMLElement(t, htmlDoc, ".issue-add-time", canTrackTime)
issueLink := path.Join(user, repo, "issues", issue)
- req = NewRequestWithValues(t, "POST", path.Join(issueLink, "times", "stopwatch", "toggle"), map[string]string{
+ reqStart := NewRequestWithValues(t, "POST", path.Join(issueLink, "times", "stopwatch", "start"), map[string]string{
"_csrf": htmlDoc.GetCSRF(),
})
if canTrackTime {
- session.MakeRequest(t, req, http.StatusOK)
+ session.MakeRequest(t, reqStart, http.StatusOK)
req = NewRequest(t, "GET", issueLink)
resp = session.MakeRequest(t, req, http.StatusOK)
htmlDoc = NewHTMLParser(t, resp.Body)
- events := htmlDoc.doc.Find(".event > span.text")
+ events := htmlDoc.doc.Find(".event > .comment-text-line")
assert.Contains(t, events.Last().Text(), "started working")
- htmlDoc.AssertElement(t, ".issue-stop-time", true)
- htmlDoc.AssertElement(t, ".issue-cancel-time", true)
+ AssertHTMLElement(t, htmlDoc, ".issue-stop-time", true)
+ AssertHTMLElement(t, htmlDoc, ".issue-cancel-time", true)
// Sleep for 1 second to not get wrong order for stopping timer
time.Sleep(time.Second)
- req = NewRequestWithValues(t, "POST", path.Join(issueLink, "times", "stopwatch", "toggle"), map[string]string{
+ reqStop := NewRequestWithValues(t, "POST", path.Join(issueLink, "times", "stopwatch", "stop"), map[string]string{
"_csrf": htmlDoc.GetCSRF(),
})
- session.MakeRequest(t, req, http.StatusOK)
+ session.MakeRequest(t, reqStop, http.StatusOK)
req = NewRequest(t, "GET", issueLink)
resp = session.MakeRequest(t, req, http.StatusOK)
htmlDoc = NewHTMLParser(t, resp.Body)
- events = htmlDoc.doc.Find(".event > span.text")
+ events = htmlDoc.doc.Find(".event > .comment-text-line")
assert.Contains(t, events.Last().Text(), "worked for ")
} else {
- session.MakeRequest(t, req, http.StatusNotFound)
+ session.MakeRequest(t, reqStart, http.StatusNotFound)
}
}
diff --git a/tests/integration/user_avatar_test.go b/tests/integration/user_avatar_test.go
index caca9a3e56..14ea012ac8 100644
--- a/tests/integration/user_avatar_test.go
+++ b/tests/integration/user_avatar_test.go
@@ -5,89 +5,87 @@ package integration
import (
"bytes"
- "fmt"
"image/png"
"io"
"mime/multipart"
"net/http"
- "net/url"
"testing"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/avatar"
+ "code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
)
func TestUserAvatar(t *testing.T) {
- onGiteaRun(t, func(t *testing.T, u *url.URL) {
- user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo3, is an org
+ defer tests.PrepareTestEnv(t)()
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo3, is an org
- seed := user2.Email
- if len(seed) == 0 {
- seed = user2.Name
- }
+ seed := user2.Email
+ if len(seed) == 0 {
+ seed = user2.Name
+ }
- img, err := avatar.RandomImage([]byte(seed))
- if err != nil {
- assert.NoError(t, err)
- return
- }
+ img, err := avatar.RandomImage([]byte(seed))
+ if err != nil {
+ assert.NoError(t, err)
+ return
+ }
- session := loginUser(t, "user2")
- csrf := GetUserCSRFToken(t, session)
+ session := loginUser(t, "user2")
+ csrf := GetUserCSRFToken(t, session)
- imgData := &bytes.Buffer{}
+ imgData := &bytes.Buffer{}
- body := &bytes.Buffer{}
+ body := &bytes.Buffer{}
- // Setup multi-part
- writer := multipart.NewWriter(body)
- writer.WriteField("source", "local")
- part, err := writer.CreateFormFile("avatar", "avatar-for-testuseravatar.png")
- if err != nil {
- assert.NoError(t, err)
- return
- }
+ // Setup multi-part
+ writer := multipart.NewWriter(body)
+ writer.WriteField("source", "local")
+ part, err := writer.CreateFormFile("avatar", "avatar-for-testuseravatar.png")
+ if err != nil {
+ assert.NoError(t, err)
+ return
+ }
- if err := png.Encode(imgData, img); err != nil {
- assert.NoError(t, err)
- return
- }
+ if err := png.Encode(imgData, img); err != nil {
+ assert.NoError(t, err)
+ return
+ }
- if _, err := io.Copy(part, imgData); err != nil {
- assert.NoError(t, err)
- return
- }
+ if _, err := io.Copy(part, imgData); err != nil {
+ assert.NoError(t, err)
+ return
+ }
- if err := writer.Close(); err != nil {
- assert.NoError(t, err)
- return
- }
+ if err := writer.Close(); err != nil {
+ assert.NoError(t, err)
+ return
+ }
- req := NewRequestWithBody(t, "POST", "/user/settings/avatar", body)
- req.Header.Add("X-Csrf-Token", csrf)
- req.Header.Add("Content-Type", writer.FormDataContentType())
+ req := NewRequestWithBody(t, "POST", "/user/settings/avatar", body)
+ req.Header.Add("X-Csrf-Token", csrf)
+ req.Header.Add("Content-Type", writer.FormDataContentType())
- session.MakeRequest(t, req, http.StatusSeeOther)
+ session.MakeRequest(t, req, http.StatusSeeOther)
- user2 = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo3, is an org
+ user2 = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo3, is an org
- req = NewRequest(t, "GET", user2.AvatarLinkWithSize(db.DefaultContext, 0))
- _ = session.MakeRequest(t, req, http.StatusOK)
+ req = NewRequest(t, "GET", user2.AvatarLinkWithSize(db.DefaultContext, 0))
+ _ = session.MakeRequest(t, req, http.StatusOK)
- testGetAvatarRedirect(t, user2)
+ testGetAvatarRedirect(t, user2)
- // Can't test if the response matches because the image is re-generated on upload but checking that this at least doesn't give a 404 should be enough.
- })
+ // Can't test if the response matches because the image is re-generated on upload but checking that this at least doesn't give a 404 should be enough.
}
func testGetAvatarRedirect(t *testing.T, user *user_model.User) {
- t.Run(fmt.Sprintf("getAvatarRedirect_%s", user.Name), func(t *testing.T) {
+ t.Run("getAvatarRedirect_"+user.Name, func(t *testing.T) {
req := NewRequestf(t, "GET", "/%s.png", user.Name)
resp := MakeRequest(t, req, http.StatusSeeOther)
- assert.EqualValues(t, fmt.Sprintf("/avatars/%s", user.Avatar), resp.Header().Get("location"))
+ assert.Equal(t, "/avatars/"+user.Avatar, resp.Header().Get("location"))
})
}
diff --git a/tests/integration/user_settings_test.go b/tests/integration/user_settings_test.go
index d8402eb25f..eab1a72ed5 100644
--- a/tests/integration/user_settings_test.go
+++ b/tests/integration/user_settings_test.go
@@ -19,21 +19,21 @@ import (
func assertNavbar(t *testing.T, doc *HTMLDoc) {
// Only show the account page if users can change their email notifications, delete themselves, or manage credentials
if setting.Admin.UserDisabledFeatures.Contains(setting.UserFeatureDeletion, setting.UserFeatureManageCredentials) && !setting.Service.EnableNotifyMail {
- doc.AssertElement(t, ".menu a[href='/user/settings/account']", false)
+ AssertHTMLElement(t, doc, ".menu a[href='/user/settings/account']", false)
} else {
- doc.AssertElement(t, ".menu a[href='/user/settings/account']", true)
+ AssertHTMLElement(t, doc, ".menu a[href='/user/settings/account']", true)
}
if setting.Admin.UserDisabledFeatures.Contains(setting.UserFeatureManageMFA, setting.UserFeatureManageCredentials) {
- doc.AssertElement(t, ".menu a[href='/user/settings/security']", false)
+ AssertHTMLElement(t, doc, ".menu a[href='/user/settings/security']", false)
} else {
- doc.AssertElement(t, ".menu a[href='/user/settings/security']", true)
+ AssertHTMLElement(t, doc, ".menu a[href='/user/settings/security']", true)
}
if setting.Admin.UserDisabledFeatures.Contains(setting.UserFeatureManageSSHKeys, setting.UserFeatureManageGPGKeys) {
- doc.AssertElement(t, ".menu a[href='/user/settings/keys']", false)
+ AssertHTMLElement(t, doc, ".menu a[href='/user/settings/keys']", false)
} else {
- doc.AssertElement(t, ".menu a[href='/user/settings/keys']", true)
+ AssertHTMLElement(t, doc, ".menu a[href='/user/settings/keys']", true)
}
}
@@ -64,11 +64,11 @@ func TestUserSettingsAccount(t *testing.T) {
doc := NewHTMLParser(t, resp.Body)
// account navbar should display
- doc.AssertElement(t, ".menu a[href='/user/settings/account']", true)
+ AssertHTMLElement(t, doc, ".menu a[href='/user/settings/account']", true)
- doc.AssertElement(t, "#password", true)
- doc.AssertElement(t, "#email", true)
- doc.AssertElement(t, "#delete-form", true)
+ AssertHTMLElement(t, doc, "#password", true)
+ AssertHTMLElement(t, doc, "#email", true)
+ AssertHTMLElement(t, doc, "#delete-form", true)
})
t.Run("credentials disabled", func(t *testing.T) {
@@ -83,9 +83,9 @@ func TestUserSettingsAccount(t *testing.T) {
assertNavbar(t, doc)
- doc.AssertElement(t, "#password", false)
- doc.AssertElement(t, "#email", false)
- doc.AssertElement(t, "#delete-form", true)
+ AssertHTMLElement(t, doc, "#password", false)
+ AssertHTMLElement(t, doc, "#email", false)
+ AssertHTMLElement(t, doc, "#delete-form", true)
})
t.Run("deletion disabled", func(t *testing.T) {
@@ -100,9 +100,9 @@ func TestUserSettingsAccount(t *testing.T) {
assertNavbar(t, doc)
- doc.AssertElement(t, "#password", true)
- doc.AssertElement(t, "#email", true)
- doc.AssertElement(t, "#delete-form", false)
+ AssertHTMLElement(t, doc, "#password", true)
+ AssertHTMLElement(t, doc, "#email", true)
+ AssertHTMLElement(t, doc, "#delete-form", false)
})
t.Run("deletion, credentials and email notifications are disabled", func(t *testing.T) {
@@ -249,7 +249,7 @@ func TestUserSettingsSecurity(t *testing.T) {
assertNavbar(t, doc)
- doc.AssertElement(t, "#register-webauthn", true)
+ AssertHTMLElement(t, doc, "#register-webauthn", true)
})
t.Run("mfa disabled", func(t *testing.T) {
@@ -263,7 +263,7 @@ func TestUserSettingsSecurity(t *testing.T) {
assertNavbar(t, doc)
- doc.AssertElement(t, "#register-webauthn", false)
+ AssertHTMLElement(t, doc, "#register-webauthn", false)
})
t.Run("credentials and mfa disabled", func(t *testing.T) {
@@ -356,8 +356,8 @@ func TestUserSettingsKeys(t *testing.T) {
assertNavbar(t, doc)
- doc.AssertElement(t, "#add-ssh-button", true)
- doc.AssertElement(t, "#add-gpg-key-panel", true)
+ AssertHTMLElement(t, doc, "#add-ssh-button", true)
+ AssertHTMLElement(t, doc, "#add-gpg-key-panel", true)
})
t.Run("ssh keys disabled", func(t *testing.T) {
@@ -372,8 +372,8 @@ func TestUserSettingsKeys(t *testing.T) {
assertNavbar(t, doc)
- doc.AssertElement(t, "#add-ssh-button", false)
- doc.AssertElement(t, "#add-gpg-key-panel", true)
+ AssertHTMLElement(t, doc, "#add-ssh-button", false)
+ AssertHTMLElement(t, doc, "#add-gpg-key-panel", true)
})
t.Run("gpg keys disabled", func(t *testing.T) {
@@ -388,8 +388,8 @@ func TestUserSettingsKeys(t *testing.T) {
assertNavbar(t, doc)
- doc.AssertElement(t, "#add-ssh-button", true)
- doc.AssertElement(t, "#add-gpg-key-panel", false)
+ AssertHTMLElement(t, doc, "#add-ssh-button", true)
+ AssertHTMLElement(t, doc, "#add-gpg-key-panel", false)
})
t.Run("ssh & gpg keys disabled", func(t *testing.T) {
diff --git a/tests/integration/user_test.go b/tests/integration/user_test.go
index 5b6f28d1ff..34692d9cab 100644
--- a/tests/integration/user_test.go
+++ b/tests/integration/user_test.go
@@ -134,8 +134,7 @@ Note: This user hasn't uploaded any GPG keys.
=twTO
------END PGP PUBLIC KEY BLOCK-----
-`)
+-----END PGP PUBLIC KEY BLOCK-----`)
// Import key
// User1 <user1@example.com>
session := loginUser(t, "user1")
@@ -169,8 +168,7 @@ C0TLXKur6NVYQMn01iyL+FZzRpEWNuYF3f9QeeLJ/+l2DafESNhNTy17+RPmacK6
7XhJ1v6JYuh8kaYaEz8OpZDeh7f6Ho6PzJrsy/TKTKhGgZNINj1iaPFyOkQgKR5M
GrE0MHOxUbc9tbtyk0F1SuzREUBH
=DDXw
------END PGP PUBLIC KEY BLOCK-----
-`)
+-----END PGP PUBLIC KEY BLOCK-----`)
// Export new key
testExportUserGPGKeys(t, "user1", `-----BEGIN PGP PUBLIC KEY BLOCK-----
@@ -201,8 +199,7 @@ C0TLXKur6NVYQMn01iyL+FZzRpEWNuYF3f9QeeLJ/+l2DafESNhNTy17+RPmacK6
7XhJ1v6JYuh8kaYaEz8OpZDeh7f6Ho6PzJrsy/TKTKhGgZNINj1iaPFyOkQgKR5M
GrE0MHOxUbc9tbtyk0F1SuzREUBH
=WFf5
------END PGP PUBLIC KEY BLOCK-----
-`)
+-----END PGP PUBLIC KEY BLOCK-----`)
}
func testExportUserGPGKeys(t *testing.T, user, expected string) {
@@ -220,12 +217,12 @@ func TestGetUserRss(t *testing.T) {
user34 := "the_34-user.with.all.allowedChars"
req := NewRequestf(t, "GET", "/%s.rss", user34)
resp := MakeRequest(t, req, http.StatusOK)
- if assert.EqualValues(t, "application/rss+xml;charset=utf-8", resp.Header().Get("Content-Type")) {
+ if assert.Equal(t, "application/rss+xml;charset=utf-8", resp.Header().Get("Content-Type")) {
rssDoc := NewHTMLParser(t, resp.Body).Find("channel")
title, _ := rssDoc.ChildrenFiltered("title").Html()
- assert.EqualValues(t, "Feed of &#34;the_1-user.with.all.allowedChars&#34;", title)
+ assert.Equal(t, "Feed of &#34;the_1-user.with.all.allowedChars&#34;", title)
description, _ := rssDoc.ChildrenFiltered("description").Html()
- assert.EqualValues(t, "&lt;p dir=&#34;auto&#34;&gt;some &lt;a href=&#34;https://commonmark.org/&#34; rel=&#34;nofollow&#34;&gt;commonmark&lt;/a&gt;!&lt;/p&gt;\n", description)
+ assert.Equal(t, "&lt;p dir=&#34;auto&#34;&gt;some &lt;a href=&#34;https://commonmark.org/&#34; rel=&#34;nofollow&#34;&gt;commonmark&lt;/a&gt;!&lt;/p&gt;\n", description)
}
req = NewRequestf(t, "GET", "/non-existent-user.rss")
@@ -250,18 +247,18 @@ func TestListStopWatches(t *testing.T) {
stopwatch := unittest.AssertExistsAndLoadBean(t, &issues_model.Stopwatch{UserID: owner.ID})
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: stopwatch.IssueID})
if assert.Len(t, apiWatches, 1) {
- assert.EqualValues(t, stopwatch.CreatedUnix.AsTime().Unix(), apiWatches[0].Created.Unix())
- assert.EqualValues(t, issue.Index, apiWatches[0].IssueIndex)
- assert.EqualValues(t, issue.Title, apiWatches[0].IssueTitle)
- assert.EqualValues(t, repo.Name, apiWatches[0].RepoName)
- assert.EqualValues(t, repo.OwnerName, apiWatches[0].RepoOwnerName)
+ assert.Equal(t, stopwatch.CreatedUnix.AsTime().Unix(), apiWatches[0].Created.Unix())
+ assert.Equal(t, issue.Index, apiWatches[0].IssueIndex)
+ assert.Equal(t, issue.Title, apiWatches[0].IssueTitle)
+ assert.Equal(t, repo.Name, apiWatches[0].RepoName)
+ assert.Equal(t, repo.OwnerName, apiWatches[0].RepoOwnerName)
assert.Positive(t, apiWatches[0].Seconds)
}
}
func TestUserLocationMapLink(t *testing.T) {
- setting.Service.UserLocationMapURL = "https://example/foo/"
defer tests.PrepareTestEnv(t)()
+ defer test.MockVariableValue(&setting.Service.UserLocationMapURL, "https://example/foo/")()
session := loginUser(t, "user2")
req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{
@@ -276,5 +273,5 @@ func TestUserLocationMapLink(t *testing.T) {
req = NewRequest(t, "GET", "/user2/")
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
- htmlDoc.AssertElement(t, `a[href="https://example/foo/A%2Fb"]`, true)
+ AssertHTMLElement(t, htmlDoc, `a[href="https://example/foo/A%2Fb"]`, true)
}
diff --git a/tests/integration/view_test.go b/tests/integration/view_test.go
index f434446801..9ed3e30857 100644
--- a/tests/integration/view_test.go
+++ b/tests/integration/view_test.go
@@ -25,3 +25,43 @@ func TestRenderFileSVGIsInImgTag(t *testing.T) {
assert.True(t, exists, "The SVG image should be in an <img> tag so that scripts in the SVG are not run")
assert.Equal(t, "/user2/repo2/raw/branch/master/line.svg", src)
}
+
+func TestCommitListActions(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+ session := loginUser(t, "user2")
+
+ t.Run("WikiRevisionList", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ req := NewRequest(t, "GET", "/user2/repo1/wiki/Home?action=_revision")
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ htmlDoc := NewHTMLParser(t, resp.Body)
+ AssertHTMLElement(t, htmlDoc, ".commit-list .copy-commit-id", true)
+ AssertHTMLElement(t, htmlDoc, `.commit-list .view-single-diff`, false)
+ AssertHTMLElement(t, htmlDoc, `.commit-list .view-commit-path`, false)
+ })
+
+ t.Run("RepoCommitList", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ req := NewRequest(t, "GET", "/user2/repo1/commits/branch/master")
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ htmlDoc := NewHTMLParser(t, resp.Body)
+
+ AssertHTMLElement(t, htmlDoc, `.commit-list .copy-commit-id`, true)
+ AssertHTMLElement(t, htmlDoc, `.commit-list .view-single-diff`, false)
+ AssertHTMLElement(t, htmlDoc, `.commit-list .view-commit-path`, true)
+ })
+
+ t.Run("RepoFileHistory", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ req := NewRequest(t, "GET", "/user2/repo1/commits/branch/master/README.md")
+ resp := session.MakeRequest(t, req, http.StatusOK)
+ htmlDoc := NewHTMLParser(t, resp.Body)
+
+ AssertHTMLElement(t, htmlDoc, `.commit-list .copy-commit-id`, true)
+ AssertHTMLElement(t, htmlDoc, `.commit-list .view-single-diff`, true)
+ AssertHTMLElement(t, htmlDoc, `.commit-list .view-commit-path`, true)
+ })
+}
diff --git a/tests/integration/webfinger_test.go b/tests/integration/webfinger_test.go
index a1abc8d32b..757d442cd2 100644
--- a/tests/integration/webfinger_test.go
+++ b/tests/integration/webfinger_test.go
@@ -7,11 +7,13 @@ import (
"fmt"
"net/http"
"net/url"
+ "strconv"
"testing"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
@@ -19,11 +21,7 @@ import (
func TestWebfinger(t *testing.T) {
defer tests.PrepareTestEnv(t)()
-
- setting.Federation.Enabled = true
- defer func() {
- setting.Federation.Enabled = false
- }()
+ defer test.MockVariableValue(&setting.Federation.Enabled, true)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
@@ -52,7 +50,7 @@ func TestWebfinger(t *testing.T) {
var jrd webfingerJRD
DecodeJSON(t, resp, &jrd)
assert.Equal(t, "acct:user2@"+appURL.Host, jrd.Subject)
- assert.ElementsMatch(t, []string{user.HTMLURL(), appURL.String() + "api/v1/activitypub/user-id/" + fmt.Sprint(user.ID)}, jrd.Aliases)
+ assert.ElementsMatch(t, []string{user.HTMLURL(), appURL.String() + "api/v1/activitypub/user-id/" + strconv.FormatInt(user.ID, 10)}, jrd.Aliases)
req = NewRequest(t, "GET", fmt.Sprintf("/.well-known/webfinger?resource=acct:%s@%s", user.LowerName, "unknown.host"))
MakeRequest(t, req, http.StatusBadRequest)
@@ -63,6 +61,6 @@ func TestWebfinger(t *testing.T) {
req = NewRequest(t, "GET", fmt.Sprintf("/.well-known/webfinger?resource=acct:%s@%s", "user31", appURL.Host))
session.MakeRequest(t, req, http.StatusOK)
- req = NewRequest(t, "GET", fmt.Sprintf("/.well-known/webfinger?resource=mailto:%s", user.Email))
+ req = NewRequest(t, "GET", "/.well-known/webfinger?resource=mailto:"+user.Email)
MakeRequest(t, req, http.StatusNotFound)
}
diff --git a/tests/integration/wiki_test.go b/tests/integration/wiki_test.go
index bb73f71a45..ac458af378 100644
--- a/tests/integration/wiki_test.go
+++ b/tests/integration/wiki_test.go
@@ -4,8 +4,6 @@
package integration
import (
- "context"
- "fmt"
"net/http"
"net/url"
"os"
@@ -30,7 +28,7 @@ func assertFileExist(t *testing.T, p string) {
func assertFileEqual(t *testing.T, p string, content []byte) {
bs, err := os.ReadFile(p)
assert.NoError(t, err)
- assert.EqualValues(t, content, bs)
+ assert.Equal(t, content, bs)
}
func TestRepoCloneWiki(t *testing.T) {
@@ -39,11 +37,11 @@ func TestRepoCloneWiki(t *testing.T) {
dstPath := t.TempDir()
- r := fmt.Sprintf("%suser2/repo1.wiki.git", u.String())
+ r := u.String() + "user2/repo1.wiki.git"
u, _ = url.Parse(r)
u.User = url.UserPassword("user2", userPassword)
t.Run("Clone", func(t *testing.T) {
- assert.NoError(t, git.CloneWithArgs(context.Background(), git.AllowLFSFiltersArgs(), u.String(), dstPath, git.CloneRepoOptions{}))
+ assert.NoError(t, git.CloneWithArgs(t.Context(), git.AllowLFSFiltersArgs(), u.String(), dstPath, git.CloneRepoOptions{}))
assertFileEqual(t, filepath.Join(dstPath, "Home.md"), []byte("# Home page\n\nThis is the home page!\n"))
assertFileExist(t, filepath.Join(dstPath, "Page-With-Image.md"))
assertFileExist(t, filepath.Join(dstPath, "Page-With-Spaced-Name.md"))
@@ -70,6 +68,6 @@ func Test_RepoWikiPages(t *testing.T) {
href, _ := firstAnchor.Attr("href")
pagePath := strings.TrimPrefix(href, "/user2/repo1/wiki/")
- assert.EqualValues(t, expectedPagePaths[i], pagePath)
+ assert.Equal(t, expectedPagePaths[i], pagePath)
})
}
diff --git a/tests/integration/workflow_run_api_check_test.go b/tests/integration/workflow_run_api_check_test.go
new file mode 100644
index 0000000000..6a80bb5118
--- /dev/null
+++ b/tests/integration/workflow_run_api_check_test.go
@@ -0,0 +1,167 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package integration
+
+import (
+ "fmt"
+ "net/http"
+ "net/url"
+ "testing"
+
+ auth_model "code.gitea.io/gitea/models/auth"
+ api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/tests"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestAPIWorkflowRun(t *testing.T) {
+ t.Run("AdminRuns", func(t *testing.T) {
+ testAPIWorkflowRunBasic(t, "/api/v1/admin/actions", "User1", 802, auth_model.AccessTokenScopeReadAdmin, auth_model.AccessTokenScopeReadRepository)
+ })
+ t.Run("UserRuns", func(t *testing.T) {
+ testAPIWorkflowRunBasic(t, "/api/v1/user/actions", "User2", 803, auth_model.AccessTokenScopeReadUser, auth_model.AccessTokenScopeReadRepository)
+ })
+ t.Run("OrgRuns", func(t *testing.T) {
+ testAPIWorkflowRunBasic(t, "/api/v1/orgs/org3/actions", "User1", 802, auth_model.AccessTokenScopeReadOrganization, auth_model.AccessTokenScopeReadRepository)
+ })
+ t.Run("RepoRuns", func(t *testing.T) {
+ testAPIWorkflowRunBasic(t, "/api/v1/repos/org3/repo5/actions", "User2", 802, auth_model.AccessTokenScopeReadRepository)
+ })
+}
+
+func testAPIWorkflowRunBasic(t *testing.T, apiRootURL, userUsername string, runID int64, scope ...auth_model.AccessTokenScope) {
+ defer tests.PrepareTestEnv(t)()
+ token := getUserToken(t, userUsername, scope...)
+
+ apiRunsURL := fmt.Sprintf("%s/%s", apiRootURL, "runs")
+ req := NewRequest(t, "GET", apiRunsURL).AddTokenAuth(token)
+ runnerListResp := MakeRequest(t, req, http.StatusOK)
+ runnerList := api.ActionWorkflowRunsResponse{}
+ DecodeJSON(t, runnerListResp, &runnerList)
+
+ foundRun := false
+
+ for _, run := range runnerList.Entries {
+ // Verify filtering works
+ verifyWorkflowRunCanbeFoundWithStatusFilter(t, apiRunsURL, token, run.ID, "", run.Status, "", "", "", "")
+ verifyWorkflowRunCanbeFoundWithStatusFilter(t, apiRunsURL, token, run.ID, run.Conclusion, "", "", "", "", "")
+ verifyWorkflowRunCanbeFoundWithStatusFilter(t, apiRunsURL, token, run.ID, "", "", "", run.HeadBranch, "", "")
+ verifyWorkflowRunCanbeFoundWithStatusFilter(t, apiRunsURL, token, run.ID, "", "", run.Event, "", "", "")
+ verifyWorkflowRunCanbeFoundWithStatusFilter(t, apiRunsURL, token, run.ID, "", "", "", "", run.TriggerActor.UserName, "")
+ verifyWorkflowRunCanbeFoundWithStatusFilter(t, apiRunsURL, token, run.ID, "", "", "", "", run.TriggerActor.UserName, run.HeadSha)
+
+ // Verify run url works
+ req := NewRequest(t, "GET", run.URL).AddTokenAuth(token)
+ runResp := MakeRequest(t, req, http.StatusOK)
+ apiRun := api.ActionWorkflowRun{}
+ DecodeJSON(t, runResp, &apiRun)
+ assert.Equal(t, run.ID, apiRun.ID)
+ assert.Equal(t, run.Status, apiRun.Status)
+ assert.Equal(t, run.Conclusion, apiRun.Conclusion)
+ assert.Equal(t, run.Event, apiRun.Event)
+
+ // Verify jobs list works
+ req = NewRequest(t, "GET", fmt.Sprintf("%s/%s", run.URL, "jobs")).AddTokenAuth(token)
+ jobsResp := MakeRequest(t, req, http.StatusOK)
+ jobList := api.ActionWorkflowJobsResponse{}
+ DecodeJSON(t, jobsResp, &jobList)
+
+ if run.ID == runID {
+ foundRun = true
+ assert.Len(t, jobList.Entries, 1)
+ for _, job := range jobList.Entries {
+ // Check the jobs list of the run
+ verifyWorkflowJobCanbeFoundWithStatusFilter(t, fmt.Sprintf("%s/%s", run.URL, "jobs"), token, job.ID, "", job.Status)
+ verifyWorkflowJobCanbeFoundWithStatusFilter(t, fmt.Sprintf("%s/%s", run.URL, "jobs"), token, job.ID, job.Conclusion, "")
+ // Check the run independent job list
+ verifyWorkflowJobCanbeFoundWithStatusFilter(t, fmt.Sprintf("%s/%s", apiRootURL, "jobs"), token, job.ID, "", job.Status)
+ verifyWorkflowJobCanbeFoundWithStatusFilter(t, fmt.Sprintf("%s/%s", apiRootURL, "jobs"), token, job.ID, job.Conclusion, "")
+
+ // Verify job url works
+ req := NewRequest(t, "GET", job.URL).AddTokenAuth(token)
+ jobsResp := MakeRequest(t, req, http.StatusOK)
+ apiJob := api.ActionWorkflowJob{}
+ DecodeJSON(t, jobsResp, &apiJob)
+ assert.Equal(t, job.ID, apiJob.ID)
+ assert.Equal(t, job.RunID, apiJob.RunID)
+ assert.Equal(t, job.Status, apiJob.Status)
+ assert.Equal(t, job.Conclusion, apiJob.Conclusion)
+ }
+ }
+ }
+ assert.True(t, foundRun, "Expected to find run with ID %d", runID)
+}
+
+func verifyWorkflowRunCanbeFoundWithStatusFilter(t *testing.T, runAPIURL, token string, id int64, conclusion, status, event, branch, actor, headSHA string) {
+ filter := url.Values{}
+ if conclusion != "" {
+ filter.Add("status", conclusion)
+ }
+ if status != "" {
+ filter.Add("status", status)
+ }
+ if event != "" {
+ filter.Set("event", event)
+ }
+ if branch != "" {
+ filter.Set("branch", branch)
+ }
+ if actor != "" {
+ filter.Set("actor", actor)
+ }
+ if headSHA != "" {
+ filter.Set("head_sha", headSHA)
+ }
+ req := NewRequest(t, "GET", runAPIURL+"?"+filter.Encode()).AddTokenAuth(token)
+ runResp := MakeRequest(t, req, http.StatusOK)
+ runList := api.ActionWorkflowRunsResponse{}
+ DecodeJSON(t, runResp, &runList)
+
+ found := false
+ for _, run := range runList.Entries {
+ if conclusion != "" {
+ assert.Equal(t, conclusion, run.Conclusion)
+ }
+ if status != "" {
+ assert.Equal(t, status, run.Status)
+ }
+ if event != "" {
+ assert.Equal(t, event, run.Event)
+ }
+ if branch != "" {
+ assert.Equal(t, branch, run.HeadBranch)
+ }
+ if actor != "" {
+ assert.Equal(t, actor, run.Actor.UserName)
+ }
+ found = found || run.ID == id
+ }
+ assert.True(t, found, "Expected to find run with ID %d", id)
+}
+
+func verifyWorkflowJobCanbeFoundWithStatusFilter(t *testing.T, runAPIURL, token string, id int64, conclusion, status string) {
+ filter := conclusion
+ if filter == "" {
+ filter = status
+ }
+ if filter == "" {
+ return
+ }
+ req := NewRequest(t, "GET", runAPIURL+"?status="+filter).AddTokenAuth(token)
+ jobListResp := MakeRequest(t, req, http.StatusOK)
+ jobList := api.ActionWorkflowJobsResponse{}
+ DecodeJSON(t, jobListResp, &jobList)
+
+ found := false
+ for _, job := range jobList.Entries {
+ if conclusion != "" {
+ assert.Equal(t, conclusion, job.Conclusion)
+ } else {
+ assert.Equal(t, status, job.Status)
+ }
+ found = found || job.ID == id
+ }
+ assert.True(t, found, "Expected to find job with ID %d", id)
+}
diff --git a/tests/integration/xss_test.go b/tests/integration/xss_test.go
index a8eaa5fc62..9058fc210a 100644
--- a/tests/integration/xss_test.go
+++ b/tests/integration/xss_test.go
@@ -32,8 +32,8 @@ func TestXSSUserFullName(t *testing.T) {
req = NewRequestf(t, "GET", "/%s", user.Name)
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
- assert.EqualValues(t, 0, htmlDoc.doc.Find("script.evil").Length())
- assert.EqualValues(t, fullName,
+ assert.Equal(t, 0, htmlDoc.doc.Find("script.evil").Length())
+ assert.Equal(t, fullName,
htmlDoc.doc.Find("div.content").Find(".header.text.center").Text(),
)
}
diff --git a/tests/mssql.ini.tmpl b/tests/mssql.ini.tmpl
index 77c969e813..42bf683a07 100644
--- a/tests/mssql.ini.tmpl
+++ b/tests/mssql.ini.tmpl
@@ -26,6 +26,9 @@ TYPE = immediate
[queue.push_update]
TYPE = immediate
+[queue.webhook_sender]
+TYPE = immediate
+
[repository]
ROOT = {{REPO_TEST_DIR}}tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mssql/gitea-repositories
@@ -42,6 +45,7 @@ SIGNING_KEY = none
SSH_DOMAIN = localhost
HTTP_PORT = 3003
ROOT_URL = http://localhost:3003/
+LOCAL_ROOT_URL = http://127.0.0.1:3003/
DISABLE_SSH = false
SSH_LISTEN_HOST = localhost
SSH_PORT = 2201
@@ -93,7 +97,6 @@ COLORIZE = true
LEVEL = Debug
[security]
-DISABLE_GIT_HOOKS = false
INSTALL_LOCK = true
SECRET_KEY = 9pCviYTWSb
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTU1NTE2MTh9.hhSVGOANkaKk3vfCd2jDOIww4pUk0xtg9JRde5UogyQ
@@ -112,3 +115,6 @@ ENABLED = true
[actions]
ENABLED = true
+
+[webhook]
+ALLOWED_HOST_LIST = 127.0.0.1
diff --git a/tests/mysql.ini.tmpl b/tests/mysql.ini.tmpl
index 0fddde46de..7cef540d1d 100644
--- a/tests/mysql.ini.tmpl
+++ b/tests/mysql.ini.tmpl
@@ -28,6 +28,9 @@ TYPE = immediate
[queue.push_update]
TYPE = immediate
+[queue.webhook_sender]
+TYPE = immediate
+
[repository]
ROOT = {{REPO_TEST_DIR}}tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mysql/gitea-repositories
@@ -44,6 +47,7 @@ SIGNING_KEY = none
SSH_DOMAIN = localhost
HTTP_PORT = 3001
ROOT_URL = http://localhost:3001/
+LOCAL_ROOT_URL = http://127.0.0.1:3001/
DISABLE_SSH = false
SSH_LISTEN_HOST = localhost
SSH_PORT = 2201
@@ -94,7 +98,6 @@ COLORIZE = true
LEVEL = Debug
[security]
-DISABLE_GIT_HOOKS = false
INSTALL_LOCK = true
SECRET_KEY = 9pCviYTWSb
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTU1NTE2MTh9.hhSVGOANkaKk3vfCd2jDOIww4pUk0xtg9JRde5UogyQ
@@ -119,3 +122,6 @@ REPLY_TO_ADDRESS = incoming+%{token}@localhost
[actions]
ENABLED = true
+
+[webhook]
+ALLOWED_HOST_LIST = 127.0.0.1
diff --git a/tests/pgsql.ini.tmpl b/tests/pgsql.ini.tmpl
index 695662c2e9..13a5932608 100644
--- a/tests/pgsql.ini.tmpl
+++ b/tests/pgsql.ini.tmpl
@@ -27,6 +27,9 @@ TYPE = immediate
[queue.push_update]
TYPE = immediate
+[queue.webhook_sender]
+TYPE = immediate
+
[repository]
ROOT = {{REPO_TEST_DIR}}tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-pgsql/gitea-repositories
@@ -43,6 +46,7 @@ SIGNING_KEY = none
SSH_DOMAIN = localhost
HTTP_PORT = 3002
ROOT_URL = http://localhost:3002/
+LOCAL_ROOT_URL = http://127.0.0.1:3002/
DISABLE_SSH = false
SSH_LISTEN_HOST = localhost
SSH_PORT = 2202
@@ -94,7 +98,6 @@ COLORIZE = true
LEVEL = Debug
[security]
-DISABLE_GIT_HOOKS = false
INSTALL_LOCK = true
SECRET_KEY = 9pCviYTWSb
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTU1NTE2MTh9.hhSVGOANkaKk3vfCd2jDOIww4pUk0xtg9JRde5UogyQ
@@ -128,3 +131,6 @@ ENABLED = true
[actions]
ENABLED = true
+
+[webhook]
+ALLOWED_HOST_LIST = 127.0.0.1
diff --git a/tests/sqlite.ini.tmpl b/tests/sqlite.ini.tmpl
index 1cbcd8b2e5..938f203633 100644
--- a/tests/sqlite.ini.tmpl
+++ b/tests/sqlite.ini.tmpl
@@ -22,6 +22,9 @@ TYPE = immediate
[queue.push_update]
TYPE = immediate
+[queue.webhook_sender]
+TYPE = immediate
+
[repository]
ROOT = {{REPO_TEST_DIR}}tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-sqlite/gitea-repositories
@@ -38,6 +41,7 @@ SIGNING_KEY = none
SSH_DOMAIN = localhost
HTTP_PORT = 3003
ROOT_URL = http://localhost:3003/
+LOCAL_ROOT_URL = http://127.0.0.1:3003/
DISABLE_SSH = false
SSH_LISTEN_HOST = localhost
SSH_PORT = 2203
@@ -93,7 +97,6 @@ COLORIZE = true
LEVEL = Debug
[security]
-DISABLE_GIT_HOOKS = false
INSTALL_LOCK = true
SECRET_KEY = 9pCviYTWSb
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTI3OTU5ODN9.OQkH5UmzID2XBdwQ9TAI6Jj2t1X-wElVTjbE7aoN4I8
@@ -117,3 +120,6 @@ RENDER_CONTENT_MODE=sanitized
[actions]
ENABLED = true
+
+[webhook]
+ALLOWED_HOST_LIST = 127.0.0.1
diff --git a/tests/test_utils.go b/tests/test_utils.go
index 0fe0200ea7..ad692058a6 100644
--- a/tests/test_utils.go
+++ b/tests/test_utils.go
@@ -1,7 +1,6 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
-//nolint:forbidigo
package tests
import (
@@ -18,7 +17,6 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
- repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/test"
@@ -56,9 +54,9 @@ func InitTest(requireGitea bool) {
// Notice: when doing "ssh push", Gitea executes sub processes, debugger won't work for the sub processes.
giteaConf = "tests/sqlite.ini"
_ = os.Setenv("GITEA_CONF", giteaConf)
- fmt.Printf("Environment variable $GITEA_CONF not set, use default: %s\n", giteaConf)
+ _, _ = fmt.Fprintf(os.Stderr, "Environment variable $GITEA_CONF not set - defaulting to %s\n", giteaConf)
if !setting.EnableSQLite3 {
- testlogger.Fatalf(`sqlite3 requires: import _ "github.com/mattn/go-sqlite3" or -tags sqlite,sqlite_unlock_notify` + "\n")
+ testlogger.Fatalf(`sqlite3 requires: -tags sqlite,sqlite_unlock_notify` + "\n")
}
}
if !filepath.IsAbs(giteaConf) {
@@ -67,9 +65,8 @@ func InitTest(requireGitea bool) {
setting.CustomConf = giteaConf
}
- unittest.InitSettings()
+ unittest.InitSettingsForTesting()
setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
- _ = util.RemoveAll(repo_module.LocalCopyPath())
if err := git.InitFull(context.Background()); err != nil {
log.Fatal("git.InitOnceWithSync: %v", err)
@@ -93,7 +90,7 @@ func InitTest(requireGitea bool) {
if err != nil {
log.Fatal("sql.Open: %v", err)
}
- if _, err = db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s", setting.Database.Name)); err != nil {
+ if _, err = db.Exec("CREATE DATABASE IF NOT EXISTS " + setting.Database.Name); err != nil {
log.Fatal("db.Exec: %v", err)
}
case setting.Database.Type.IsPostgreSQL():
@@ -118,7 +115,7 @@ func InitTest(requireGitea bool) {
defer dbrows.Close()
if !dbrows.Next() {
- if _, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s", setting.Database.Name)); err != nil {
+ if _, err = db.Exec("CREATE DATABASE " + setting.Database.Name); err != nil {
log.Fatal("db.Exec: CREATE DATABASE: %v", err)
}
}
@@ -148,7 +145,7 @@ func InitTest(requireGitea bool) {
if !schrows.Next() {
// Create and setup a DB schema
- if _, err = db.Exec(fmt.Sprintf("CREATE SCHEMA %s", setting.Database.Schema)); err != nil {
+ if _, err = db.Exec("CREATE SCHEMA " + setting.Database.Schema); err != nil {
log.Fatal("db.Exec: CREATE SCHEMA: %v", err)
}
}