mirror of
https://github.com/simon987/task_tracker.git
synced 2025-04-19 02:06:45 +00:00
Add API endpoint to pause a worker
This commit is contained in:
parent
8f10567bd0
commit
72c8e18044
@ -86,6 +86,7 @@ func New() *WebAPI {
|
|||||||
|
|
||||||
api.router.POST("/worker/create", LogRequestMiddleware(api.CreateWorker))
|
api.router.POST("/worker/create", LogRequestMiddleware(api.CreateWorker))
|
||||||
api.router.POST("/worker/update", LogRequestMiddleware(api.UpdateWorker))
|
api.router.POST("/worker/update", LogRequestMiddleware(api.UpdateWorker))
|
||||||
|
api.router.POST("/worker/set_paused", LogRequestMiddleware(api.WorkerSetPaused))
|
||||||
api.router.GET("/worker/get/:id", LogRequestMiddleware(api.GetWorker))
|
api.router.GET("/worker/get/:id", LogRequestMiddleware(api.GetWorker))
|
||||||
api.router.GET("/worker/stats", LogRequestMiddleware(api.GetAllWorkerStats))
|
api.router.GET("/worker/stats", LogRequestMiddleware(api.GetAllWorkerStats))
|
||||||
|
|
||||||
|
@ -269,6 +269,11 @@ type UpdateWorkerRequest struct {
|
|||||||
Alias string `json:"alias"`
|
Alias string `json:"alias"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WorkerSetPausedRequest struct {
|
||||||
|
Worker int64 `json:"worker"`
|
||||||
|
Paused bool `json:"paused"`
|
||||||
|
}
|
||||||
|
|
||||||
type CreateWorkerRequest struct {
|
type CreateWorkerRequest struct {
|
||||||
Alias string `json:"alias"`
|
Alias string `json:"alias"`
|
||||||
}
|
}
|
||||||
|
@ -200,6 +200,14 @@ func (api *WebAPI) GetTaskFromProject(r *Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if worker.Paused {
|
||||||
|
r.Json(JsonResponse{
|
||||||
|
Ok: false,
|
||||||
|
Message: "A manager has paused you",
|
||||||
|
}, 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
project, err := strconv.ParseInt(r.Ctx.UserValue("project").(string), 10, 64)
|
project, err := strconv.ParseInt(r.Ctx.UserValue("project").(string), 10, 64)
|
||||||
if err != nil || project <= 0 {
|
if err != nil || project <= 0 {
|
||||||
r.Json(JsonResponse{
|
r.Json(JsonResponse{
|
||||||
|
@ -126,6 +126,54 @@ func (api *WebAPI) UpdateWorker(r *Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *WebAPI) WorkerSetPaused(r *Request) {
|
||||||
|
|
||||||
|
sess := api.Session.StartFasthttp(r.Ctx)
|
||||||
|
manager := sess.Get("manager")
|
||||||
|
|
||||||
|
if manager == nil || !manager.(*storage.Manager).WebsiteAdmin {
|
||||||
|
r.Json(JsonResponse{
|
||||||
|
Ok: false,
|
||||||
|
Message: "Unauthorized",
|
||||||
|
}, 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req := &WorkerSetPausedRequest{}
|
||||||
|
err := json.Unmarshal(r.Ctx.Request.Body(), req)
|
||||||
|
if err != nil {
|
||||||
|
r.Json(JsonResponse{
|
||||||
|
Ok: false,
|
||||||
|
Message: "Could not parse request",
|
||||||
|
}, 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
worker := api.Database.GetWorker(req.Worker)
|
||||||
|
if worker == nil {
|
||||||
|
r.Json(JsonResponse{
|
||||||
|
Ok: false,
|
||||||
|
Message: "Invalid worker",
|
||||||
|
}, 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
worker.Paused = req.Paused
|
||||||
|
|
||||||
|
ok := api.Database.UpdateWorker(worker)
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
r.OkJson(JsonResponse{
|
||||||
|
Ok: true,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
r.OkJson(JsonResponse{
|
||||||
|
Ok: false,
|
||||||
|
Message: "Could not update worker",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (api *WebAPI) GetAllWorkerStats(r *Request) {
|
func (api *WebAPI) GetAllWorkerStats(r *Request) {
|
||||||
|
|
||||||
stats := api.Database.GetAllWorkerStats()
|
stats := api.Database.GetAllWorkerStats()
|
||||||
|
229
schema.sql
229
schema.sql
@ -1,179 +1,180 @@
|
|||||||
DROP TABLE IF EXISTS worker, project, task, log_entry,
|
DROP TABLE IF EXISTS worker, project, task, log_entry,
|
||||||
worker_access, manager, manager_has_role_on_project, project_monitoring_snapshot,
|
worker_access, manager, manager_has_role_on_project, project_monitoring_snapshot,
|
||||||
worker_verifies_task;
|
worker_verifies_task;
|
||||||
|
|
||||||
CREATE TABLE worker
|
CREATE TABLE worker
|
||||||
(
|
(
|
||||||
id SERIAL PRIMARY KEY NOT NULL,
|
id SERIAL PRIMARY KEY NOT NULL,
|
||||||
alias TEXT NOT NULL,
|
alias TEXT NOT NULL,
|
||||||
created INTEGER NOT NULL,
|
created INTEGER NOT NULL,
|
||||||
secret BYTEA NOT NULL,
|
secret BYTEA NOT NULL,
|
||||||
closed_task_count INTEGER DEFAULT 0 NOT NULL
|
closed_task_count INTEGER DEFAULT 0 NOT NULL,
|
||||||
|
paused boolean NOT NULL DEFAULT false
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE project
|
CREATE TABLE project
|
||||||
(
|
(
|
||||||
id SERIAL PRIMARY KEY NOT NULL,
|
id SERIAL PRIMARY KEY NOT NULL,
|
||||||
priority INTEGER DEFAULT 0 NOT NULL,
|
priority INTEGER DEFAULT 0 NOT NULL,
|
||||||
closed_task_count INT DEFAULT 0 NOT NULL,
|
closed_task_count INT DEFAULT 0 NOT NULL,
|
||||||
chain INT DEFAULT NULL REFERENCES project (id),
|
chain INT DEFAULT NULL REFERENCES project (id),
|
||||||
public boolean NOT NULL,
|
public boolean NOT NULL,
|
||||||
hidden boolean NOT NULL,
|
hidden boolean NOT NULL,
|
||||||
paused boolean NOT NULL,
|
paused boolean NOT NULL,
|
||||||
name TEXT UNIQUE NOT NULL,
|
name TEXT UNIQUE NOT NULL,
|
||||||
clone_url TEXT NOT NULL,
|
clone_url TEXT NOT NULL,
|
||||||
git_repo TEXT NOT NULL,
|
git_repo TEXT NOT NULL,
|
||||||
version TEXT NOT NULL,
|
version TEXT NOT NULL,
|
||||||
motd TEXT NOT NULL,
|
motd TEXT NOT NULL,
|
||||||
secret TEXT NOT NULL DEFAULT '{}',
|
secret TEXT NOT NULL DEFAULT '{}',
|
||||||
webhook_secret TEXT NOT NULL,
|
webhook_secret TEXT NOT NULL,
|
||||||
assign_rate DOUBLE PRECISION NOT NULL,
|
assign_rate DOUBLE PRECISION NOT NULL,
|
||||||
submit_rate DOUBLE PRECISION NOT NULL
|
submit_rate DOUBLE PRECISION NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE worker_access
|
CREATE TABLE worker_access
|
||||||
(
|
(
|
||||||
worker INTEGER REFERENCES worker (id),
|
worker INTEGER REFERENCES worker (id),
|
||||||
project INTEGER REFERENCES project (id),
|
project INTEGER REFERENCES project (id),
|
||||||
role_assign boolean,
|
role_assign boolean,
|
||||||
role_submit boolean,
|
role_submit boolean,
|
||||||
request boolean,
|
request boolean,
|
||||||
primary key (worker, project)
|
primary key (worker, project)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE task
|
CREATE TABLE task
|
||||||
(
|
(
|
||||||
hash64 BIGINT DEFAULT NULL,
|
hash64 BIGINT DEFAULT NULL,
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
project INTEGER REFERENCES project (id),
|
project INTEGER REFERENCES project (id),
|
||||||
assignee INTEGER REFERENCES worker (id),
|
assignee INTEGER REFERENCES worker (id),
|
||||||
max_assign_time INTEGER DEFAULT 0,
|
max_assign_time INTEGER DEFAULT 0,
|
||||||
assign_time INTEGER DEFAULT NULL,
|
assign_time INTEGER DEFAULT NULL,
|
||||||
verification_count INTEGER DEFAULT 0,
|
verification_count INTEGER DEFAULT 0,
|
||||||
priority SMALLINT DEFAULT 0,
|
priority SMALLINT DEFAULT 0,
|
||||||
retries SMALLINT DEFAULT 0,
|
retries SMALLINT DEFAULT 0,
|
||||||
max_retries SMALLINT,
|
max_retries SMALLINT,
|
||||||
status SMALLINT DEFAULT 1,
|
status SMALLINT DEFAULT 1,
|
||||||
recipe TEXT,
|
recipe TEXT,
|
||||||
UNIQUE (project, hash64)
|
UNIQUE (project, hash64)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE worker_verifies_task
|
CREATE TABLE worker_verifies_task
|
||||||
(
|
(
|
||||||
verification_hash BIGINT NOT NULL,
|
verification_hash BIGINT NOT NULL,
|
||||||
task BIGINT REFERENCES task (id) ON DELETE CASCADE NOT NULL,
|
task BIGINT REFERENCES task (id) ON DELETE CASCADE NOT NULL,
|
||||||
worker INT REFERENCES worker (id) NOT NULL
|
worker INT REFERENCES worker (id) NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE log_entry
|
CREATE TABLE log_entry
|
||||||
(
|
(
|
||||||
level INTEGER NOT NULL,
|
level INTEGER NOT NULL,
|
||||||
message TEXT NOT NULL,
|
message TEXT NOT NULL,
|
||||||
message_data TEXT NOT NULL,
|
message_data TEXT NOT NULL,
|
||||||
timestamp INTEGER NOT NULL
|
timestamp INTEGER NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE manager
|
CREATE TABLE manager
|
||||||
(
|
(
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
register_time INTEGER NOT NULL,
|
register_time INTEGER NOT NULL,
|
||||||
tracker_admin BOOLEAN NOT NULL,
|
tracker_admin BOOLEAN NOT NULL,
|
||||||
username TEXT UNIQUE NOT NULL,
|
username TEXT UNIQUE NOT NULL,
|
||||||
password BYTEA NOT NULL
|
password BYTEA NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE manager_has_role_on_project
|
CREATE TABLE manager_has_role_on_project
|
||||||
(
|
(
|
||||||
manager INTEGER REFERENCES manager (id) NOT NULL,
|
manager INTEGER REFERENCES manager (id) NOT NULL,
|
||||||
role SMALLINT NOT NULL,
|
role SMALLINT NOT NULL,
|
||||||
project INTEGER REFERENCES project (id) NOT NULL,
|
project INTEGER REFERENCES project (id) NOT NULL,
|
||||||
PRIMARY KEY (manager, project)
|
PRIMARY KEY (manager, project)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE project_monitoring_snapshot
|
CREATE TABLE project_monitoring_snapshot
|
||||||
(
|
(
|
||||||
project INT REFERENCES project (id) NOT NULL,
|
project INT REFERENCES project (id) NOT NULL,
|
||||||
new_task_count INT NOT NULL,
|
new_task_count INT NOT NULL,
|
||||||
failed_task_count INT NOT NULL,
|
failed_task_count INT NOT NULL,
|
||||||
closed_task_count INT NOT NULL,
|
closed_task_count INT NOT NULL,
|
||||||
awaiting_verification_task_count INT NOT NULL,
|
awaiting_verification_task_count INT NOT NULL,
|
||||||
worker_access_count INT NOT NULL,
|
worker_access_count INT NOT NULL,
|
||||||
timestamp INT NOT NULL
|
timestamp INT NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION on_task_delete_proc() RETURNS TRIGGER AS
|
CREATE OR REPLACE FUNCTION on_task_delete_proc() RETURNS TRIGGER AS
|
||||||
$$
|
$$
|
||||||
DECLARE
|
DECLARE
|
||||||
chain INTEGER;
|
chain INTEGER;
|
||||||
BEGIN
|
BEGIN
|
||||||
if OLD.assignee IS NOT NULL THEN
|
if OLD.assignee IS NOT NULL THEN
|
||||||
UPDATE project
|
UPDATE project
|
||||||
SET closed_task_count=closed_task_count + 1
|
SET closed_task_count=closed_task_count + 1
|
||||||
WHERE id = OLD.project returning project.chain into chain;
|
WHERE id = OLD.project returning project.chain into chain;
|
||||||
UPDATE worker SET closed_task_count=closed_task_count + 1 WHERE id = OLD.assignee;
|
UPDATE worker SET closed_task_count=closed_task_count + 1 WHERE id = OLD.assignee;
|
||||||
IF chain != 0 THEN
|
IF chain != 0 THEN
|
||||||
INSERT into task (hash64, project, assignee, max_assign_time, assign_time, verification_count,
|
INSERT into task (hash64, project, assignee, max_assign_time, assign_time, verification_count,
|
||||||
priority, retries, max_retries, status, recipe)
|
priority, retries, max_retries, status, recipe)
|
||||||
VALUES (old.hash64, chain, NULL, old.max_assign_time, NULL,
|
VALUES (old.hash64, chain, NULL, old.max_assign_time, NULL,
|
||||||
old.verification_count, old.priority, 0, old.max_retries, 1,
|
old.verification_count, old.priority, 0, old.max_retries, 1,
|
||||||
old.recipe)
|
old.recipe)
|
||||||
ON CONFLICT DO NOTHING;
|
ON CONFLICT DO NOTHING;
|
||||||
|
end if;
|
||||||
end if;
|
end if;
|
||||||
end if;
|
RETURN OLD;
|
||||||
RETURN OLD;
|
|
||||||
END;
|
END;
|
||||||
$$ LANGUAGE 'plpgsql';
|
$$ LANGUAGE 'plpgsql';
|
||||||
CREATE TRIGGER on_task_delete
|
CREATE TRIGGER on_task_delete
|
||||||
BEFORE DELETE
|
BEFORE DELETE
|
||||||
ON task
|
ON task
|
||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
EXECUTE PROCEDURE on_task_delete_proc();
|
EXECUTE PROCEDURE on_task_delete_proc();
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION on_manager_insert() RETURNS TRIGGER AS
|
CREATE OR REPLACE FUNCTION on_manager_insert() RETURNS TRIGGER AS
|
||||||
$$
|
$$
|
||||||
BEGIN
|
BEGIN
|
||||||
IF NEW.id = 1 THEN
|
IF NEW.id = 1 THEN
|
||||||
UPDATE manager SET tracker_admin= TRUE WHERE id = 1;
|
UPDATE manager SET tracker_admin= TRUE WHERE id = 1;
|
||||||
end if;
|
end if;
|
||||||
RETURN NEW;
|
RETURN NEW;
|
||||||
END;
|
END;
|
||||||
$$ LANGUAGE 'plpgsql';
|
$$ LANGUAGE 'plpgsql';
|
||||||
CREATE TRIGGER on_manager_insert
|
CREATE TRIGGER on_manager_insert
|
||||||
AFTER INSERT
|
AFTER INSERT
|
||||||
ON manager
|
ON manager
|
||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
EXECUTE PROCEDURE on_manager_insert();
|
EXECUTE PROCEDURE on_manager_insert();
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION release_task_ok(wid INT, tid INT, ver BIGINT) RETURNS BOOLEAN AS
|
CREATE OR REPLACE FUNCTION release_task_ok(wid INT, tid INT, ver BIGINT) RETURNS BOOLEAN AS
|
||||||
$$
|
$$
|
||||||
DECLARE
|
DECLARE
|
||||||
res INT = NULL;
|
res INT = NULL;
|
||||||
BEGIN
|
BEGIN
|
||||||
DELETE FROM task WHERE id = tid AND assignee = wid AND verification_count < 2 RETURNING project INTO res;
|
DELETE FROM task WHERE id = tid AND assignee = wid AND verification_count < 2 RETURNING project INTO res;
|
||||||
|
|
||||||
IF res IS NULL THEN
|
|
||||||
INSERT INTO worker_verifies_task (worker, verification_hash, task)
|
|
||||||
SELECT wid, ver, task.id
|
|
||||||
FROM task
|
|
||||||
WHERE assignee = wid
|
|
||||||
AND task.id = tid;
|
|
||||||
|
|
||||||
DELETE
|
|
||||||
FROM task
|
|
||||||
WHERE id = tid
|
|
||||||
AND assignee = wid
|
|
||||||
AND (SELECT COUNT(*) as vcnt
|
|
||||||
FROM worker_verifies_task wvt
|
|
||||||
WHERE task = tid
|
|
||||||
GROUP BY wvt.verification_hash
|
|
||||||
ORDER BY vcnt DESC
|
|
||||||
LIMIT 1) >= task.verification_count RETURNING task.id INTO res;
|
|
||||||
|
|
||||||
IF res IS NULL THEN
|
IF res IS NULL THEN
|
||||||
UPDATE task SET assignee= NULL WHERE id = tid AND assignee = wid;
|
INSERT INTO worker_verifies_task (worker, verification_hash, task)
|
||||||
end if;
|
SELECT wid, ver, task.id
|
||||||
end if;
|
FROM task
|
||||||
|
WHERE assignee = wid
|
||||||
|
AND task.id = tid;
|
||||||
|
|
||||||
RETURN res IS NOT NULL;
|
DELETE
|
||||||
|
FROM task
|
||||||
|
WHERE id = tid
|
||||||
|
AND assignee = wid
|
||||||
|
AND (SELECT COUNT(*) as vcnt
|
||||||
|
FROM worker_verifies_task wvt
|
||||||
|
WHERE task = tid
|
||||||
|
GROUP BY wvt.verification_hash
|
||||||
|
ORDER BY vcnt DESC
|
||||||
|
LIMIT 1) >= task.verification_count RETURNING task.id INTO res;
|
||||||
|
|
||||||
|
IF res IS NULL THEN
|
||||||
|
UPDATE task SET assignee= NULL WHERE id = tid AND assignee = wid;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
RETURN res IS NOT NULL;
|
||||||
END;
|
END;
|
||||||
$$ LANGUAGE 'plpgsql';
|
$$ LANGUAGE 'plpgsql';
|
||||||
|
@ -9,6 +9,7 @@ type Worker struct {
|
|||||||
Created int64 `json:"created"`
|
Created int64 `json:"created"`
|
||||||
Alias string `json:"alias,omitempty"`
|
Alias string `json:"alias,omitempty"`
|
||||||
Secret []byte `json:"secret"`
|
Secret []byte `json:"secret"`
|
||||||
|
Paused bool `json:"paused"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WorkerStats struct {
|
type WorkerStats struct {
|
||||||
@ -96,8 +97,8 @@ func (database *Database) GrantAccess(workerId int64, projectId int64) bool {
|
|||||||
func (database *Database) UpdateWorker(worker *Worker) bool {
|
func (database *Database) UpdateWorker(worker *Worker) bool {
|
||||||
|
|
||||||
db := database.getDB()
|
db := database.getDB()
|
||||||
res, err := db.Exec(`UPDATE worker SET alias=$1 WHERE id=$2`,
|
res, err := db.Exec(`UPDATE worker SET alias=$1, paused=$2 WHERE id=$3`,
|
||||||
worker.Alias, worker.Id)
|
worker.Alias, worker.Paused, worker.Id)
|
||||||
handleErr(err)
|
handleErr(err)
|
||||||
|
|
||||||
rowsAffected, _ := res.RowsAffected()
|
rowsAffected, _ := res.RowsAffected()
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/simon987/task_tracker/client"
|
"github.com/simon987/task_tracker/client"
|
||||||
"github.com/simon987/task_tracker/storage"
|
"github.com/simon987/task_tracker/storage"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -29,6 +30,10 @@ func TestCreateGetWorker(t *testing.T) {
|
|||||||
if w.Alias != "my_worker_alias" {
|
if w.Alias != "my_worker_alias" {
|
||||||
t.Error()
|
t.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if w.Paused != false {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetWorkerNotFound(t *testing.T) {
|
func TestGetWorkerNotFound(t *testing.T) {
|
||||||
@ -68,6 +73,10 @@ func TestUpdateAliasValid(t *testing.T) {
|
|||||||
if w.Alias != "new alias" {
|
if w.Alias != "new alias" {
|
||||||
t.Error()
|
t.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if w.Paused != false {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateWorkerAliasInvalid(t *testing.T) {
|
func TestCreateWorkerAliasInvalid(t *testing.T) {
|
||||||
@ -109,6 +118,74 @@ func TestInvalidAccessRequest(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAssignTaskWhenPaused(t *testing.T) {
|
||||||
|
|
||||||
|
w := genWid()
|
||||||
|
|
||||||
|
pid := createProjectAsAdmin(api.CreateProjectRequest{
|
||||||
|
Name: "testassigntaskwhenpaused",
|
||||||
|
CloneUrl: "testassigntaskwhenpaused",
|
||||||
|
GitRepo: "testassigntaskwhenpaused",
|
||||||
|
}).Content.Id
|
||||||
|
|
||||||
|
requestAccess(api.CreateWorkerAccessRequest{
|
||||||
|
Submit: true,
|
||||||
|
Assign: true,
|
||||||
|
Project: pid,
|
||||||
|
}, w)
|
||||||
|
acceptAccessRequest(pid, w.Id, testAdminCtx)
|
||||||
|
|
||||||
|
r := createTask(api.SubmitTaskRequest{
|
||||||
|
Project: pid,
|
||||||
|
Recipe: "a",
|
||||||
|
Hash64: 1,
|
||||||
|
}, w)
|
||||||
|
|
||||||
|
if r.Ok != true {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
pauseWorker(&api.WorkerSetPausedRequest{
|
||||||
|
Paused: true,
|
||||||
|
Worker: w.Id,
|
||||||
|
}, testAdminCtx)
|
||||||
|
|
||||||
|
resp := getTaskFromProject(pid, w)
|
||||||
|
|
||||||
|
if resp.Ok != false {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
if !strings.Contains(resp.Message, "paused") {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPauseInvalidWorker(t *testing.T) {
|
||||||
|
|
||||||
|
r := pauseWorker(&api.WorkerSetPausedRequest{
|
||||||
|
Paused: true,
|
||||||
|
Worker: 9999111,
|
||||||
|
}, testAdminCtx)
|
||||||
|
|
||||||
|
if r.Ok != false {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPauseUnauthorized(t *testing.T) {
|
||||||
|
|
||||||
|
w := genWid()
|
||||||
|
|
||||||
|
r := pauseWorker(&api.WorkerSetPausedRequest{
|
||||||
|
Paused: true,
|
||||||
|
Worker: w.Id,
|
||||||
|
}, testUserCtx)
|
||||||
|
|
||||||
|
if r.Ok != false {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func createWorker(req api.CreateWorkerRequest) (ar client.CreateWorkerResponse) {
|
func createWorker(req api.CreateWorkerRequest) (ar client.CreateWorkerResponse) {
|
||||||
r := Post("/worker/create", req, nil, nil)
|
r := Post("/worker/create", req, nil, nil)
|
||||||
UnmarshalResponse(r, &ar)
|
UnmarshalResponse(r, &ar)
|
||||||
@ -147,8 +224,13 @@ func rejectAccessRequest(pid int64, wid int64, s *http.Client) (ar api.JsonRespo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateWorker(request api.UpdateWorkerRequest, w *storage.Worker) (ar api.JsonResponse) {
|
func updateWorker(request api.UpdateWorkerRequest, w *storage.Worker) (ar api.JsonResponse) {
|
||||||
|
|
||||||
r := Post("/worker/update", request, w, nil)
|
r := Post("/worker/update", request, w, nil)
|
||||||
UnmarshalResponse(r, &ar)
|
UnmarshalResponse(r, &ar)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pauseWorker(request *api.WorkerSetPausedRequest, s *http.Client) (ar api.JsonResponse) {
|
||||||
|
r := Post("/worker/set_paused", request, nil, s)
|
||||||
|
UnmarshalResponse(r, &ar)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
229
test/schema.sql
229
test/schema.sql
@ -1,180 +1,181 @@
|
|||||||
DROP TABLE IF EXISTS worker, project, task, log_entry,
|
DROP TABLE IF EXISTS worker, project, task, log_entry,
|
||||||
worker_access, manager, manager_has_role_on_project, project_monitoring_snapshot,
|
worker_access, manager, manager_has_role_on_project, project_monitoring_snapshot,
|
||||||
worker_verifies_task;
|
worker_verifies_task;
|
||||||
|
|
||||||
CREATE TABLE worker
|
CREATE TABLE worker
|
||||||
(
|
(
|
||||||
id SERIAL PRIMARY KEY NOT NULL,
|
id SERIAL PRIMARY KEY NOT NULL,
|
||||||
alias TEXT NOT NULL,
|
alias TEXT NOT NULL,
|
||||||
created INTEGER NOT NULL,
|
created INTEGER NOT NULL,
|
||||||
secret BYTEA NOT NULL,
|
secret BYTEA NOT NULL,
|
||||||
closed_task_count INTEGER DEFAULT 0 NOT NULL
|
closed_task_count INTEGER DEFAULT 0 NOT NULL,
|
||||||
|
paused boolean NOT NULL DEFAULT false
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE project
|
CREATE TABLE project
|
||||||
(
|
(
|
||||||
id SERIAL PRIMARY KEY NOT NULL,
|
id SERIAL PRIMARY KEY NOT NULL,
|
||||||
priority INTEGER DEFAULT 0 NOT NULL,
|
priority INTEGER DEFAULT 0 NOT NULL,
|
||||||
closed_task_count INT DEFAULT 0 NOT NULL,
|
closed_task_count INT DEFAULT 0 NOT NULL,
|
||||||
chain INT DEFAULT NULL REFERENCES project (id),
|
chain INT DEFAULT NULL REFERENCES project (id),
|
||||||
public boolean NOT NULL,
|
public boolean NOT NULL,
|
||||||
hidden boolean NOT NULL,
|
hidden boolean NOT NULL,
|
||||||
paused boolean NOT NULL,
|
paused boolean NOT NULL,
|
||||||
name TEXT UNIQUE NOT NULL,
|
name TEXT UNIQUE NOT NULL,
|
||||||
clone_url TEXT NOT NULL,
|
clone_url TEXT NOT NULL,
|
||||||
git_repo TEXT NOT NULL,
|
git_repo TEXT NOT NULL,
|
||||||
version TEXT NOT NULL,
|
version TEXT NOT NULL,
|
||||||
motd TEXT NOT NULL,
|
motd TEXT NOT NULL,
|
||||||
secret TEXT NOT NULL DEFAULT '{}',
|
secret TEXT NOT NULL DEFAULT '{}',
|
||||||
webhook_secret TEXT NOT NULL,
|
webhook_secret TEXT NOT NULL,
|
||||||
assign_rate DOUBLE PRECISION NOT NULL,
|
assign_rate DOUBLE PRECISION NOT NULL,
|
||||||
submit_rate DOUBLE PRECISION NOT NULL
|
submit_rate DOUBLE PRECISION NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE worker_access
|
CREATE TABLE worker_access
|
||||||
(
|
(
|
||||||
worker INTEGER REFERENCES worker (id),
|
worker INTEGER REFERENCES worker (id),
|
||||||
project INTEGER REFERENCES project (id),
|
project INTEGER REFERENCES project (id),
|
||||||
role_assign boolean,
|
role_assign boolean,
|
||||||
role_submit boolean,
|
role_submit boolean,
|
||||||
request boolean,
|
request boolean,
|
||||||
primary key (worker, project)
|
primary key (worker, project)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE task
|
CREATE TABLE task
|
||||||
(
|
(
|
||||||
hash64 BIGINT DEFAULT NULL,
|
hash64 BIGINT DEFAULT NULL,
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
project INTEGER REFERENCES project (id),
|
project INTEGER REFERENCES project (id),
|
||||||
assignee INTEGER REFERENCES worker (id),
|
assignee INTEGER REFERENCES worker (id),
|
||||||
max_assign_time INTEGER DEFAULT 0,
|
max_assign_time INTEGER DEFAULT 0,
|
||||||
assign_time INTEGER DEFAULT NULL,
|
assign_time INTEGER DEFAULT NULL,
|
||||||
verification_count INTEGER DEFAULT 0,
|
verification_count INTEGER DEFAULT 0,
|
||||||
priority SMALLINT DEFAULT 0,
|
priority SMALLINT DEFAULT 0,
|
||||||
retries SMALLINT DEFAULT 0,
|
retries SMALLINT DEFAULT 0,
|
||||||
max_retries SMALLINT,
|
max_retries SMALLINT,
|
||||||
status SMALLINT DEFAULT 1,
|
status SMALLINT DEFAULT 1,
|
||||||
recipe TEXT,
|
recipe TEXT,
|
||||||
UNIQUE (project, hash64)
|
UNIQUE (project, hash64)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE worker_verifies_task
|
CREATE TABLE worker_verifies_task
|
||||||
(
|
(
|
||||||
verification_hash BIGINT NOT NULL,
|
verification_hash BIGINT NOT NULL,
|
||||||
task BIGINT REFERENCES task (id) ON DELETE CASCADE NOT NULL,
|
task BIGINT REFERENCES task (id) ON DELETE CASCADE NOT NULL,
|
||||||
worker INT REFERENCES worker (id) NOT NULL
|
worker INT REFERENCES worker (id) NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE log_entry
|
CREATE TABLE log_entry
|
||||||
(
|
(
|
||||||
level INTEGER NOT NULL,
|
level INTEGER NOT NULL,
|
||||||
message TEXT NOT NULL,
|
message TEXT NOT NULL,
|
||||||
message_data TEXT NOT NULL,
|
message_data TEXT NOT NULL,
|
||||||
timestamp INTEGER NOT NULL
|
timestamp INTEGER NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE manager
|
CREATE TABLE manager
|
||||||
(
|
(
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
register_time INTEGER NOT NULL,
|
register_time INTEGER NOT NULL,
|
||||||
tracker_admin BOOLEAN NOT NULL,
|
tracker_admin BOOLEAN NOT NULL,
|
||||||
username TEXT UNIQUE NOT NULL,
|
username TEXT UNIQUE NOT NULL,
|
||||||
password BYTEA NOT NULL
|
password BYTEA NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE manager_has_role_on_project
|
CREATE TABLE manager_has_role_on_project
|
||||||
(
|
(
|
||||||
manager INTEGER REFERENCES manager (id) NOT NULL,
|
manager INTEGER REFERENCES manager (id) NOT NULL,
|
||||||
role SMALLINT NOT NULL,
|
role SMALLINT NOT NULL,
|
||||||
project INTEGER REFERENCES project (id) NOT NULL,
|
project INTEGER REFERENCES project (id) NOT NULL,
|
||||||
PRIMARY KEY (manager, project)
|
PRIMARY KEY (manager, project)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE project_monitoring_snapshot
|
CREATE TABLE project_monitoring_snapshot
|
||||||
(
|
(
|
||||||
project INT REFERENCES project (id) NOT NULL,
|
project INT REFERENCES project (id) NOT NULL,
|
||||||
new_task_count INT NOT NULL,
|
new_task_count INT NOT NULL,
|
||||||
failed_task_count INT NOT NULL,
|
failed_task_count INT NOT NULL,
|
||||||
closed_task_count INT NOT NULL,
|
closed_task_count INT NOT NULL,
|
||||||
awaiting_verification_task_count INT NOT NULL,
|
awaiting_verification_task_count INT NOT NULL,
|
||||||
worker_access_count INT NOT NULL,
|
worker_access_count INT NOT NULL,
|
||||||
timestamp INT NOT NULL
|
timestamp INT NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION on_task_delete_proc() RETURNS TRIGGER AS
|
CREATE OR REPLACE FUNCTION on_task_delete_proc() RETURNS TRIGGER AS
|
||||||
$$
|
$$
|
||||||
DECLARE
|
DECLARE
|
||||||
chain INTEGER;
|
chain INTEGER;
|
||||||
BEGIN
|
BEGIN
|
||||||
if OLD.assignee IS NOT NULL THEN
|
if OLD.assignee IS NOT NULL THEN
|
||||||
UPDATE project
|
UPDATE project
|
||||||
SET closed_task_count=closed_task_count + 1
|
SET closed_task_count=closed_task_count + 1
|
||||||
WHERE id = OLD.project returning project.chain into chain;
|
WHERE id = OLD.project returning project.chain into chain;
|
||||||
UPDATE worker SET closed_task_count=closed_task_count + 1 WHERE id = OLD.assignee;
|
UPDATE worker SET closed_task_count=closed_task_count + 1 WHERE id = OLD.assignee;
|
||||||
IF chain != 0 THEN
|
IF chain != 0 THEN
|
||||||
INSERT into task (hash64, project, assignee, max_assign_time, assign_time, verification_count,
|
INSERT into task (hash64, project, assignee, max_assign_time, assign_time, verification_count,
|
||||||
priority, retries, max_retries, status, recipe)
|
priority, retries, max_retries, status, recipe)
|
||||||
VALUES (old.hash64, chain, NULL, old.max_assign_time, NULL,
|
VALUES (old.hash64, chain, NULL, old.max_assign_time, NULL,
|
||||||
old.verification_count, old.priority, 0, old.max_retries, 1,
|
old.verification_count, old.priority, 0, old.max_retries, 1,
|
||||||
old.recipe)
|
old.recipe)
|
||||||
ON CONFLICT DO NOTHING;
|
ON CONFLICT DO NOTHING;
|
||||||
|
end if;
|
||||||
end if;
|
end if;
|
||||||
end if;
|
RETURN OLD;
|
||||||
RETURN OLD;
|
|
||||||
END;
|
END;
|
||||||
$$ LANGUAGE 'plpgsql';
|
$$ LANGUAGE 'plpgsql';
|
||||||
CREATE TRIGGER on_task_delete
|
CREATE TRIGGER on_task_delete
|
||||||
BEFORE DELETE
|
BEFORE DELETE
|
||||||
ON task
|
ON task
|
||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
EXECUTE PROCEDURE on_task_delete_proc();
|
EXECUTE PROCEDURE on_task_delete_proc();
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION on_manager_insert() RETURNS TRIGGER AS
|
CREATE OR REPLACE FUNCTION on_manager_insert() RETURNS TRIGGER AS
|
||||||
$$
|
$$
|
||||||
BEGIN
|
BEGIN
|
||||||
IF NEW.id = 1 THEN
|
IF NEW.id = 1 THEN
|
||||||
UPDATE manager SET tracker_admin= TRUE WHERE id = 1;
|
UPDATE manager SET tracker_admin= TRUE WHERE id = 1;
|
||||||
end if;
|
end if;
|
||||||
RETURN NEW;
|
RETURN NEW;
|
||||||
END;
|
END;
|
||||||
$$ LANGUAGE 'plpgsql';
|
$$ LANGUAGE 'plpgsql';
|
||||||
CREATE TRIGGER on_manager_insert
|
CREATE TRIGGER on_manager_insert
|
||||||
AFTER INSERT
|
AFTER INSERT
|
||||||
ON manager
|
ON manager
|
||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
EXECUTE PROCEDURE on_manager_insert();
|
EXECUTE PROCEDURE on_manager_insert();
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION release_task_ok(wid INT, tid INT, ver BIGINT) RETURNS BOOLEAN AS
|
CREATE OR REPLACE FUNCTION release_task_ok(wid INT, tid INT, ver BIGINT) RETURNS BOOLEAN AS
|
||||||
$$
|
$$
|
||||||
DECLARE
|
DECLARE
|
||||||
res INT = NULL;
|
res INT = NULL;
|
||||||
BEGIN
|
BEGIN
|
||||||
DELETE FROM task WHERE id = tid AND assignee = wid AND verification_count < 2 RETURNING project INTO res;
|
DELETE FROM task WHERE id = tid AND assignee = wid AND verification_count < 2 RETURNING project INTO res;
|
||||||
|
|
||||||
IF res IS NULL THEN
|
|
||||||
INSERT INTO worker_verifies_task (worker, verification_hash, task)
|
|
||||||
SELECT wid, ver, task.id
|
|
||||||
FROM task
|
|
||||||
WHERE assignee = wid
|
|
||||||
AND task.id = tid;
|
|
||||||
|
|
||||||
DELETE
|
|
||||||
FROM task
|
|
||||||
WHERE id = tid
|
|
||||||
AND assignee = wid
|
|
||||||
AND (SELECT COUNT(*) as vcnt
|
|
||||||
FROM worker_verifies_task wvt
|
|
||||||
WHERE task = tid
|
|
||||||
GROUP BY wvt.verification_hash
|
|
||||||
ORDER BY vcnt DESC
|
|
||||||
LIMIT 1) >= task.verification_count RETURNING task.id INTO res;
|
|
||||||
|
|
||||||
IF res IS NULL THEN
|
IF res IS NULL THEN
|
||||||
UPDATE task SET assignee= NULL WHERE id = tid AND assignee = wid;
|
INSERT INTO worker_verifies_task (worker, verification_hash, task)
|
||||||
end if;
|
SELECT wid, ver, task.id
|
||||||
end if;
|
FROM task
|
||||||
|
WHERE assignee = wid
|
||||||
|
AND task.id = tid;
|
||||||
|
|
||||||
RETURN res IS NOT NULL;
|
DELETE
|
||||||
|
FROM task
|
||||||
|
WHERE id = tid
|
||||||
|
AND assignee = wid
|
||||||
|
AND (SELECT COUNT(*) as vcnt
|
||||||
|
FROM worker_verifies_task wvt
|
||||||
|
WHERE task = tid
|
||||||
|
GROUP BY wvt.verification_hash
|
||||||
|
ORDER BY vcnt DESC
|
||||||
|
LIMIT 1) >= task.verification_count RETURNING task.id INTO res;
|
||||||
|
|
||||||
|
IF res IS NULL THEN
|
||||||
|
UPDATE task SET assignee= NULL WHERE id = tid AND assignee = wid;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
RETURN res IS NOT NULL;
|
||||||
END;
|
END;
|
||||||
$$ LANGUAGE 'plpgsql';
|
$$ LANGUAGE 'plpgsql';
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user