From 271a67a4b51ec5dbad15671213b151d7eb7136ce Mon Sep 17 00:00:00 2001
From: walking dev <104449470+walkingdevel@users.noreply.github.com>
Date: Sat, 10 Sep 2022 17:22:56 +0000
Subject: [PATCH] tests and initial api (#199)
---
.gitignore | 2 +-
api/api.v | 6 ++
api/branch.v | 7 ++
api/commit.v | 7 ++
api/issue.v | 7 ++
run.sh | 2 +-
src/branch_routes.v | 16 +++
src/commit_routes.v | 20 +++-
src/commit_service.v | 2 +-
src/issue_routes.v | 16 +++
src/issue_service.v | 6 ++
src/repo_routes.v | 8 +-
src/repo_template.v | 2 +-
src/templates/new.html | 2 +-
tests/first_run.v | 234 ++++++++++++++++++++++++++++++++++-------
15 files changed, 288 insertions(+), 49 deletions(-)
create mode 100644 api/api.v
create mode 100644 api/branch.v
create mode 100644 api/commit.v
create mode 100644 api/issue.v
diff --git a/.gitignore b/.gitignore
index 735aa85..aefa1c0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,7 +4,7 @@ gitly
*.css.map
.sass-cache/
.lite_workspace.lua
-static/assets/version
+src/static/assets/version
logs/
repos/
archives/
diff --git a/api/api.v b/api/api.v
new file mode 100644
index 0000000..9703428
--- /dev/null
+++ b/api/api.v
@@ -0,0 +1,6 @@
+module api
+
+struct ApiResponse {
+pub:
+ success bool
+}
diff --git a/api/branch.v b/api/branch.v
new file mode 100644
index 0000000..9c72c50
--- /dev/null
+++ b/api/branch.v
@@ -0,0 +1,7 @@
+module api
+
+pub struct ApiBranchCount {
+ ApiResponse
+pub:
+ result int
+}
diff --git a/api/commit.v b/api/commit.v
new file mode 100644
index 0000000..3afc040
--- /dev/null
+++ b/api/commit.v
@@ -0,0 +1,7 @@
+module api
+
+pub struct ApiCommitCount {
+ ApiResponse
+pub:
+ result int
+}
diff --git a/api/issue.v b/api/issue.v
new file mode 100644
index 0000000..24fb3bf
--- /dev/null
+++ b/api/issue.v
@@ -0,0 +1,7 @@
+module api
+
+pub struct ApiIssueCount {
+ ApiResponse
+pub:
+ result int
+}
diff --git a/run.sh b/run.sh
index 559c727..e325d33 100755
--- a/run.sh
+++ b/run.sh
@@ -1,3 +1,3 @@
-sassc static/css/gitly.scss > static/css/gitly.css
+sassc src/static/css/gitly.scss > src/static/css/gitly.css
v .
./gitly
diff --git a/src/branch_routes.v b/src/branch_routes.v
index 6408e9e..da599f2 100644
--- a/src/branch_routes.v
+++ b/src/branch_routes.v
@@ -1,6 +1,22 @@
module main
import vweb
+import api
+
+['/api/v1/:user/:repo_name/branches/count']
+fn (mut app App) handle_branch_count(username string, repo_name string) vweb.Result {
+ // TODO: add auth checking module
+ if !app.exists_user_repo(username, repo_name) {
+ return app.not_found()
+ }
+
+ count := app.get_count_repo_branches(app.repo.id)
+
+ return app.json(api.ApiBranchCount{
+ success: true
+ result: count
+ })
+}
['/:user/:repo/branches']
pub fn (mut app App) branches(user string, repo string) vweb.Result {
diff --git a/src/commit_routes.v b/src/commit_routes.v
index 412745d..3124414 100644
--- a/src/commit_routes.v
+++ b/src/commit_routes.v
@@ -3,10 +3,22 @@ module main
import vweb
import highlight
import time
+import api
-['/:user/:repo/:branch_name/commits']
-pub fn (mut app App) handle_commits(username string, repo string, branch_name string) vweb.Result {
- return app.commits(username, repo, branch_name, 0)
+['/api/v1/:user/:repo_name/:branch_name/commits/count']
+fn (mut app App) handle_commits_count(username string, repo_name string, branch_name string) vweb.Result {
+ // TODO: add auth checking module
+ if !app.exists_user_repo(username, repo_name) {
+ return app.not_found()
+ }
+
+ branch := app.find_repo_branch_by_name(app.repo.id, branch_name)
+ count := app.get_repo_commit_count(app.repo.id, branch.id)
+
+ return app.json(api.ApiCommitCount{
+ success: true
+ result: count
+ })
}
['/:username/:repo_name/commits/:branch_name/:page']
@@ -18,7 +30,7 @@ pub fn (mut app App) commits(username string, repo_name string, branch_name stri
app.show_menu = true
branch := app.find_repo_branch_by_name(app.repo.id, branch_name)
- commits_count := app.get_count_repo_commits(app.repo.id, branch.id)
+ commits_count := app.get_repo_commit_count(app.repo.id, branch.id)
mut commits := app.find_repo_commits_as_page(app.repo.id, branch.id, page)
// TODO: move to render logic
diff --git a/src/commit_service.v b/src/commit_service.v
index 56e6588..7174930 100644
--- a/src/commit_service.v
+++ b/src/commit_service.v
@@ -98,7 +98,7 @@ fn (mut app App) find_repo_commits_as_page(repo_id int, branch_id int, page int)
}
}
-fn (mut app App) get_count_repo_commits(repo_id int, branch_id int) int {
+fn (mut app App) get_repo_commit_count(repo_id int, branch_id int) int {
return sql app.db {
select count from Commit where repo_id == repo_id && branch_id == branch_id
}
diff --git a/src/issue_routes.v b/src/issue_routes.v
index ce5d94e..3390313 100644
--- a/src/issue_routes.v
+++ b/src/issue_routes.v
@@ -2,6 +2,22 @@ module main
import vweb
import validation
+import api
+
+['/api/v1/:user/:repo_name/issues/count']
+fn (mut app App) handle_issues_count(username string, repo_name string) vweb.Result {
+ // TODO: add auth checking module
+ if !app.exists_user_repo(username, repo_name) {
+ return app.not_found()
+ }
+
+ count := app.get_repo_issue_count(app.repo.id)
+
+ return app.json(api.ApiIssueCount{
+ success: true
+ result: count
+ })
+}
['/:user/:repo/issues/new']
pub fn (mut app App) new_issue(user string, repo string) vweb.Result {
diff --git a/src/issue_service.v b/src/issue_service.v
index 778dd10..aa77f58 100644
--- a/src/issue_service.v
+++ b/src/issue_service.v
@@ -45,6 +45,12 @@ fn (mut app App) find_repo_issues_as_page(repo_id int, page int) []Issue {
}
}
+fn (mut app App) get_repo_issue_count(repo_id int) int {
+ return sql app.db {
+ select count from Issue where repo_id == repo_id
+ }
+}
+
fn (mut app App) get_all_repo_issues(repo_id int) []Issue {
issues := sql app.db {
select from Issue where repo_id == repo_id && is_pr == false
diff --git a/src/repo_routes.v b/src/repo_routes.v
index 1186104..702010a 100644
--- a/src/repo_routes.v
+++ b/src/repo_routes.v
@@ -159,7 +159,7 @@ pub fn (mut app App) new() vweb.Result {
}
['/new'; post]
-pub fn (mut app App) handle_new_repo(name string, clone_url string, description string) vweb.Result {
+pub fn (mut app App) handle_new_repo(name string, clone_url string, description string, no_redirect string) vweb.Result {
mut valid_clone_url := clone_url
is_clone_url_empty := validation.is_string_empty(clone_url)
is_public := app.form['repo_visibility'] == 'public'
@@ -245,6 +245,10 @@ pub fn (mut app App) handle_new_repo(name string, clone_url string, description
app.update_repo(mut app.repo)
}
+ if no_redirect == '1' {
+ return app.text('ok')
+ }
+
has_first_repo_activity := app.has_activity(app.user.id, 'first_repo')
if !has_first_repo_activity {
@@ -354,7 +358,7 @@ pub fn (mut app App) tree(username string, repository_name string, branch_name s
items << dirs
items << files
- commits_count := app.get_count_repo_commits(app.repo.id, branch.id)
+ commits_count := app.get_repo_commit_count(app.repo.id, branch.id)
has_commits := commits_count > 0
// Get readme after updating repository
diff --git a/src/repo_template.v b/src/repo_template.v
index 0932d1f..1820350 100644
--- a/src/repo_template.v
+++ b/src/repo_template.v
@@ -12,7 +12,7 @@ fn get_declension_form(count int, first_form string, second_form string) string
fn (mut app App) format_commits_count(repo Repo, branch_name string) vweb.RawHtml {
branch := app.find_repo_branch_by_name(repo.id, branch_name)
- commits_count := app.get_count_repo_commits(repo.id, branch.id)
+ commits_count := app.get_repo_commit_count(repo.id, branch.id)
return get_declension_form(commits_count, 'commit', 'commits')
}
diff --git a/src/templates/new.html b/src/templates/new.html
index 18bd7c5..5ae4cba 100644
--- a/src/templates/new.html
+++ b/src/templates/new.html
@@ -36,7 +36,7 @@
-
+
diff --git a/tests/first_run.v b/tests/first_run.v
index 8eafd65..f243c4a 100644
--- a/tests/first_run.v
+++ b/tests/first_run.v
@@ -1,8 +1,83 @@
import os
import net.http
import time
+import json
+import api
-const myfolder = os.dir(os.executable())
+const gitly_url = 'http://127.0.0.1:8080'
+
+const default_branch = 'main'
+
+const test_username = 'bob'
+
+const test_github_repo_url = 'https://github.com/vlang/ui'
+
+const test_github_repo_primary_branch = 'master'
+
+fn main() {
+ before()?
+
+ test_index_page()
+
+ ilog('Register the first user `$test_username`')
+ mut register_headers, token := register_user(test_username, '1234zxcv', 'bob@example.com') or {
+ exit_with_message(err.str())
+ }
+
+ ilog('Check all cookies that must be present')
+ assert register_headers.contains(.set_cookie)
+
+ ilog('Ensure the login token is present after registration')
+ has_token := token != ''
+ assert has_token
+
+ test_user_page(test_username)
+ test_login_with_token(test_username, token)
+ test_static_served()
+
+ test_create_repo(token, 'test1', '')
+ assert get_repo_commit_count(token, test_username, 'test1', default_branch) == 0
+ assert get_repo_issue_count(token, test_username, 'test1') == 0
+ assert get_repo_branch_count(token, test_username, 'test1') == 0
+
+ test_create_repo(token, 'test2', test_github_repo_url)
+ assert get_repo_commit_count(token, test_username, 'test2', test_github_repo_primary_branch) > 0
+ assert get_repo_issue_count(token, test_username, 'test2') == 0
+ assert get_repo_branch_count(token, test_username, 'test2') > 0
+
+ after()?
+}
+
+fn before() ? {
+ cd_executable_dir()?
+
+ ilog('Make sure gitly is not running')
+ kill_gitly_processes()
+
+ remove_database_if_exists()?
+ remove_repos_dir_if_exists()?
+ compile_gitly()
+
+ ilog('Start gitly in the background, then wait till gitly starts and is responding to requests')
+ go run_gitly()
+
+ wait_gitly()
+}
+
+fn after() ? {
+ remove_database_if_exists()?
+ remove_repos_dir_if_exists()?
+
+ ilog('Ensure gitly is stopped')
+ kill_gitly_processes()
+}
+
+fn run_gitly() {
+ gitly_process := os.execute('./gitly &')
+ if gitly_process.exit_code != 0 {
+ exit_with_message(gitly_process.str())
+ }
+}
[noreturn]
fn exit_with_message(message string) {
@@ -14,33 +89,56 @@ fn ilog(message string) {
println('$time.now().format_ss_milli() | $message')
}
-fn main() {
+fn cd_executable_dir() ? {
+ executable_dir := os.dir(os.executable())
// Ensure that we are always running in the gitly folder, no matter what is the starting one:
- os.chdir(os.dir(myfolder))?
+ os.chdir(os.dir(executable_dir))?
+
ilog('Testing first gitly run.')
+}
- ilog('Make sure gitly is not running')
+fn kill_gitly_processes() {
os.execute('pkill -9 gitly')
+}
+fn remove_database_if_exists() ? {
ilog('Remove old gitly DB')
+
if os.exists('gitly.sqlite') {
os.rm('gitly.sqlite')?
}
+}
+
+fn remove_repos_dir_if_exists() ? {
+ ilog('Remove repos directory')
+
+ if os.exists('repos') {
+ os.rmdir_all('repos')?
+ }
+}
+fn compile_gitly() {
ilog('Compile gitly')
+
os.execute('v .')
+}
- ilog('Start gitly in the background, then wait till gitly starts and is responding to requests')
- go run_gitly()
+fn wait_gitly() {
for waiting_cycles := 0; waiting_cycles < 50; waiting_cycles++ {
- ilog(' wait: $waiting_cycles')
+ ilog('\twait: $waiting_cycles')
time.sleep(100 * time.millisecond)
- http.get('http://127.0.0.1:8080') or { continue }
+ http.get(prepare_url('')) or { continue }
break
}
+}
+fn prepare_url(path string) string {
+ return '$gitly_url/$path'
+}
+
+fn test_index_page() {
ilog("Ensure gitly's main page is up")
- index_page_result := http.get('http://127.0.0.1:8080') or { exit_with_message(err.str()) }
+ index_page_result := http.get(prepare_url('')) or { exit_with_message(err.str()) }
assert index_page_result.body.contains('')
assert index_page_result.body.contains('')
@@ -51,56 +149,116 @@ fn main() {
// Make sure no one's logged in
assert index_page_result.body.contains("
Log in")
+}
- ilog('Register the first user `bob`')
- mut register_result := http.post('http://127.0.0.1:8080/register', 'username=bob&password=1234zxcv&email=bob@example.com&no_redirect=1') or {
- exit_with_message(err.str())
+// returns headers and token
+fn register_user(username string, password string, email string) ?(http.Header, string) {
+ response := http.post(prepare_url('register'), 'username=$username&password=$password&email=$email&no_redirect=1') or {
+ return err
}
- ilog('Check all cookies that must be present')
- assert register_result.header.contains(.set_cookie)
- ilog('Ensure the login token is present after registration')
- mut has_token := false
mut token := ''
- for val in register_result.header.values(.set_cookie) {
+ for val in response.header.values(.set_cookie) {
token = val.find_between('token=', ';')
- has_token = token != ''
}
- assert has_token
- ilog('Testing the new user /bob page is up after registration')
- user_page_result := http.get('http://127.0.0.1:8080/bob') or { exit_with_message(err.str()) }
- assert user_page_result.body.contains('
bob
')
+ return response.header, token
+}
+
+fn test_static_served() {
+ ilog('Ensure that static css is served')
+ css := http.get(prepare_url('css/gitly.css')) or { exit_with_message(err.str()) }
+
+ assert css.status_code != 404
+ assert css.body.contains('body')
+ assert css.body.contains('html')
+}
+
+fn test_user_page(username string) {
+ ilog('Testing the new user /$username page is up after registration')
+ user_page_result := http.get(prepare_url(username)) or { exit_with_message(err.str()) }
+
+ assert user_page_result.body.contains('
$username
')
+}
+
+fn test_login_with_token(username string, token string) {
+ ilog('Try to login in with `$username` user token')
- ilog('Try to login in with `bob` user token')
login_result := http.fetch(
method: .get
cookies: {
'token': token
}
- url: 'http://127.0.0.1:8080/bob'
+ url: prepare_url(username)
) or { exit_with_message(err.str()) }
- ilog('Ensure that after login, there is a signed in as `bob` message')
+ ilog('Ensure that after login, there is a signed in as `$username` message')
+
assert login_result.body.contains('
Signed in as')
- assert login_result.body.contains("
bob")
+ assert login_result.body.contains("
$username")
+}
- ilog('Ensure that static css is served')
- css := http.get('http://127.0.0.1:8080/css/gitly.css') or { exit_with_message(err.str()) }
+fn test_create_repo(token string, name string, clone_url string) {
+ description := 'test description'
+ repo_visibility := 'public'
- println(css)
+ response := http.fetch(
+ method: .post
+ cookies: {
+ 'token': token
+ }
+ url: prepare_url('new')
+ data: 'name=$name&description=$description&clone_url=$clone_url&repo_visibility=$repo_visibility&no_redirect=1'
+ ) or { exit_with_message(err.str()) }
- assert css.status_code != 404
- assert css.body.contains('body')
- assert css.body.contains('html')
+ assert response.status_code == 200
+ assert response.body == 'ok'
+}
- ilog('Ensure gitly is stopped')
- os.execute('pkill -9 gitly')
+fn get_repo_commit_count(token string, username string, repo_name string, branch_name string) int {
+ response := http.fetch(
+ method: .get
+ cookies: {
+ 'token': token
+ }
+ url: prepare_url('api/v1/$username/$repo_name/$branch_name/commits/count')
+ ) or { exit_with_message(err.str()) }
+
+ response_json := json.decode(api.ApiCommitCount, response.body) or {
+ exit_with_message(err.str())
+ }
+
+ return response_json.result
}
-fn run_gitly() {
- gitly_process := os.execute('./gitly &')
- if gitly_process.exit_code != 0 {
- exit_with_message(gitly_process.str())
+fn get_repo_issue_count(token string, username string, repo_name string) int {
+ response := http.fetch(
+ method: .get
+ cookies: {
+ 'token': token
+ }
+ url: prepare_url('api/v1/$username/$repo_name/issues/count')
+ ) or { exit_with_message(err.str()) }
+
+ response_json := json.decode(api.ApiIssueCount, response.body) or {
+ exit_with_message(err.str())
}
+
+ return response_json.result
+}
+
+fn get_repo_branch_count(token string, username string, repo_name string) int {
+ response := http.fetch(
+ method: .get
+ cookies: {
+ 'token': token
+ }
+ url: prepare_url('api/v1/$username/$repo_name/branches/count')
+ ) or { exit_with_message(err.str()) }
+
+ response_json := json.decode(api.ApiBranchCount, response.body) or {
+ exit_with_message(err.str())
+ }
+
+ return response_json.result
}
--
2.39.5