mirror of
https://github.com/simon987/task_tracker.git
synced 2025-04-19 18:16:45 +00:00
Task GET
This commit is contained in:
parent
83276ce8b0
commit
a2b5de0e01
15
api/main.go
15
api/main.go
@ -9,18 +9,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type WebAPI struct {
|
type WebAPI struct {
|
||||||
server *fasthttp.Server
|
server *fasthttp.Server
|
||||||
router *fasthttprouter.Router
|
router *fasthttprouter.Router
|
||||||
Database *storage.Database
|
Database *storage.Database
|
||||||
}
|
}
|
||||||
|
|
||||||
type Info struct {
|
type Info struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var info = Info {
|
var info = Info{
|
||||||
Name: "task_tracker",
|
Name: "task_tracker",
|
||||||
Version: "1.0",
|
Version: "1.0",
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ func New() *WebAPI {
|
|||||||
|
|
||||||
api.server = &fasthttp.Server{
|
api.server = &fasthttp.Server{
|
||||||
Handler: api.router.Handler,
|
Handler: api.router.Handler,
|
||||||
Name: info.Name,
|
Name: info.Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
api.router.GET("/", LogRequest(Index))
|
api.router.GET("/", LogRequest(Index))
|
||||||
@ -55,7 +55,8 @@ func New() *WebAPI {
|
|||||||
api.router.GET("/project/get/:id", LogRequest(api.ProjectGet))
|
api.router.GET("/project/get/:id", LogRequest(api.ProjectGet))
|
||||||
|
|
||||||
api.router.POST("/task/create", LogRequest(api.TaskCreate))
|
api.router.POST("/task/create", LogRequest(api.TaskCreate))
|
||||||
api.router.GET("/task/get/", LogRequest(api.TaskGet))
|
api.router.GET("/task/get/:project", LogRequest(api.TaskGetFromProject))
|
||||||
|
api.router.GET("/task/get", LogRequest(api.TaskGet))
|
||||||
|
|
||||||
return api
|
return api
|
||||||
}
|
}
|
||||||
|
@ -7,20 +7,21 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type CreateProjectRequest struct {
|
type CreateProjectRequest struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
GitUrl string `json:"git_url"`
|
GitUrl string `json:"git_url"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
|
Priority int64 `json:"priority"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateProjectResponse struct {
|
type CreateProjectResponse struct {
|
||||||
Ok bool `json:"ok"`
|
Ok bool `json:"ok"`
|
||||||
Id int64 `json:"id,omitempty"`
|
Id int64 `json:"id,omitempty"`
|
||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetProjectResponse struct {
|
type GetProjectResponse struct {
|
||||||
Ok bool `json:"ok"`
|
Ok bool `json:"ok"`
|
||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message,omitempty"`
|
||||||
Project *storage.Project `json:"project,omitempty"`
|
Project *storage.Project `json:"project,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,9 +31,10 @@ func (api *WebAPI) ProjectCreate(r *Request) {
|
|||||||
if r.GetJson(createReq) {
|
if r.GetJson(createReq) {
|
||||||
|
|
||||||
project := &storage.Project{
|
project := &storage.Project{
|
||||||
Name: createReq.Name,
|
Name: createReq.Name,
|
||||||
Version: createReq.Version,
|
Version: createReq.Version,
|
||||||
GitUrl: createReq.GitUrl,
|
GitUrl: createReq.GitUrl,
|
||||||
|
Priority: createReq.Priority,
|
||||||
}
|
}
|
||||||
|
|
||||||
if isValidProject(project) {
|
if isValidProject(project) {
|
||||||
@ -40,8 +42,8 @@ func (api *WebAPI) ProjectCreate(r *Request) {
|
|||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Json(CreateProjectResponse{
|
r.Json(CreateProjectResponse{
|
||||||
Ok: false,
|
Ok: false,
|
||||||
Message:err.Error(),
|
Message: err.Error(),
|
||||||
}, 500)
|
}, 500)
|
||||||
} else {
|
} else {
|
||||||
r.OkJson(CreateProjectResponse{
|
r.OkJson(CreateProjectResponse{
|
||||||
@ -55,7 +57,7 @@ func (api *WebAPI) ProjectCreate(r *Request) {
|
|||||||
}).Warn("Invalid project")
|
}).Warn("Invalid project")
|
||||||
|
|
||||||
r.Json(CreateProjectResponse{
|
r.Json(CreateProjectResponse{
|
||||||
Ok: false,
|
Ok: false,
|
||||||
Message: "Invalid project",
|
Message: "Invalid project",
|
||||||
}, 400)
|
}, 400)
|
||||||
}
|
}
|
||||||
@ -80,12 +82,12 @@ func (api *WebAPI) ProjectGet(r *Request) {
|
|||||||
|
|
||||||
if project != nil {
|
if project != nil {
|
||||||
r.OkJson(GetProjectResponse{
|
r.OkJson(GetProjectResponse{
|
||||||
Ok: true,
|
Ok: true,
|
||||||
Project:project,
|
Project: project,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
r.Json(GetProjectResponse{
|
r.Json(GetProjectResponse{
|
||||||
Ok: false,
|
Ok: false,
|
||||||
Message: "Project not found",
|
Message: "Project not found",
|
||||||
}, 404)
|
}, 404)
|
||||||
}
|
}
|
||||||
|
94
api/task.go
94
api/task.go
@ -1,19 +1,29 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/google/uuid"
|
||||||
"src/task_tracker/storage"
|
"src/task_tracker/storage"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CreateTaskRequest struct {
|
type CreateTaskRequest struct {
|
||||||
Project int64 `json:"project"`
|
Project int64 `json:"project"`
|
||||||
MaxRetries int64 `json:"max_retries"`
|
MaxRetries int64 `json:"max_retries"`
|
||||||
Recipe string `json:"recipe"`
|
Recipe string `json:"recipe"`
|
||||||
|
Priority int64 `json:"priority"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateTaskResponse struct {
|
type CreateTaskResponse struct {
|
||||||
Ok bool
|
Ok bool `json:"ok"`
|
||||||
Message string
|
Message string `json:"message,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetTaskResponse struct {
|
||||||
|
Ok bool `json:"ok"`
|
||||||
|
Message string `json:"message,omitempty"`
|
||||||
|
Task *storage.Task `json:"task,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *WebAPI) TaskCreate(r *Request) {
|
func (api *WebAPI) TaskCreate(r *Request) {
|
||||||
@ -22,17 +32,17 @@ func (api *WebAPI) TaskCreate(r *Request) {
|
|||||||
if r.GetJson(&createReq) {
|
if r.GetJson(&createReq) {
|
||||||
|
|
||||||
task := &storage.Task{
|
task := &storage.Task{
|
||||||
Project:createReq.Project,
|
|
||||||
MaxRetries: createReq.MaxRetries,
|
MaxRetries: createReq.MaxRetries,
|
||||||
Recipe:createReq.Recipe,
|
Recipe: createReq.Recipe,
|
||||||
|
Priority: createReq.Priority,
|
||||||
}
|
}
|
||||||
|
|
||||||
if isTaskValid(task) {
|
if isTaskValid(task) {
|
||||||
err := api.Database.SaveTask(task)
|
err := api.Database.SaveTask(task, createReq.Project)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Json(CreateTaskResponse{
|
r.Json(CreateTaskResponse{
|
||||||
Ok: false,
|
Ok: false,
|
||||||
Message: err.Error(), //todo: hide sensitive error?
|
Message: err.Error(), //todo: hide sensitive error?
|
||||||
}, 500)
|
}, 500)
|
||||||
} else {
|
} else {
|
||||||
@ -45,11 +55,10 @@ func (api *WebAPI) TaskCreate(r *Request) {
|
|||||||
"task": task,
|
"task": task,
|
||||||
}).Warn("Invalid task")
|
}).Warn("Invalid task")
|
||||||
r.Json(CreateTaskResponse{
|
r.Json(CreateTaskResponse{
|
||||||
Ok: false,
|
Ok: false,
|
||||||
Message: "Invalid task",
|
Message: "Invalid task",
|
||||||
}, 400)
|
}, 400)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,9 +66,6 @@ func isTaskValid(task *storage.Task) bool {
|
|||||||
if task.MaxRetries < 0 {
|
if task.MaxRetries < 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if task.Project <= 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if len(task.Recipe) <= 0 {
|
if len(task.Recipe) <= 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -67,7 +73,67 @@ func isTaskValid(task *storage.Task) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *WebAPI) TaskGetFromProject(r *Request) {
|
||||||
|
|
||||||
|
worker, err := api.workerFromQueryArgs(r)
|
||||||
|
if err != nil {
|
||||||
|
r.Json(GetTaskResponse{
|
||||||
|
Ok: false,
|
||||||
|
Message: err.Error(),
|
||||||
|
}, 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
project, err := strconv.Atoi(r.Ctx.UserValue("project").(string))
|
||||||
|
handleErr(err, r)
|
||||||
|
task := api.Database.GetTaskFromProject(worker, int64(project))
|
||||||
|
|
||||||
|
r.OkJson(GetTaskResponse{
|
||||||
|
Ok: true,
|
||||||
|
Task: task,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (api *WebAPI) TaskGet(r *Request) {
|
func (api *WebAPI) TaskGet(r *Request) {
|
||||||
|
|
||||||
|
worker, err := api.workerFromQueryArgs(r)
|
||||||
|
if err != nil {
|
||||||
|
r.Json(GetTaskResponse{
|
||||||
|
Ok: false,
|
||||||
|
Message: err.Error(),
|
||||||
|
}, 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
task := api.Database.GetTask(worker)
|
||||||
|
|
||||||
|
r.OkJson(GetTaskResponse{
|
||||||
|
Ok: true,
|
||||||
|
Task: task,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api WebAPI) workerFromQueryArgs(r *Request) (*storage.Worker, error) {
|
||||||
|
|
||||||
|
widStr := string(r.Ctx.QueryArgs().Peek("wid"))
|
||||||
|
wid, err := uuid.Parse(widStr)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).WithFields(logrus.Fields{
|
||||||
|
"wid": widStr,
|
||||||
|
}).Warn("Can't parse wid")
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
worker := api.Database.GetWorker(wid)
|
||||||
|
|
||||||
|
if worker == nil {
|
||||||
|
logrus.WithError(err).WithFields(logrus.Fields{
|
||||||
|
"wid": widStr,
|
||||||
|
}).Warn("Can't parse wid")
|
||||||
|
|
||||||
|
return nil, errors.New("worker id does not match any valid worker")
|
||||||
|
}
|
||||||
|
|
||||||
|
return worker, nil
|
||||||
}
|
}
|
@ -11,15 +11,15 @@ type CreateWorkerRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CreateWorkerResponse struct {
|
type CreateWorkerResponse struct {
|
||||||
Ok bool `json:"ok"`
|
Ok bool `json:"ok"`
|
||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message,omitempty"`
|
||||||
WorkerId string `json:"id,omitempty"`
|
WorkerId uuid.UUID `json:"id,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetWorkerResponse struct {
|
type GetWorkerResponse struct {
|
||||||
Ok bool `json:"ok"`
|
Ok bool `json:"ok"`
|
||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message,omitempty"`
|
||||||
Worker *storage.Worker `json:"worker,omitempty"`
|
Worker *storage.Worker `json:"worker,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *WebAPI) WorkerCreate(r *Request) {
|
func (api *WebAPI) WorkerCreate(r *Request) {
|
||||||
@ -35,8 +35,8 @@ func (api *WebAPI) WorkerCreate(r *Request) {
|
|||||||
handleErr(err, r)
|
handleErr(err, r)
|
||||||
} else {
|
} else {
|
||||||
r.OkJson(CreateWorkerResponse{
|
r.OkJson(CreateWorkerResponse{
|
||||||
Ok: true,
|
Ok: true,
|
||||||
WorkerId: id.String(),
|
WorkerId: id,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,8 +58,8 @@ func (api *WebAPI) WorkerGet(r *Request) {
|
|||||||
}).Warn("Invalid UUID")
|
}).Warn("Invalid UUID")
|
||||||
|
|
||||||
r.Json(GetWorkerResponse{
|
r.Json(GetWorkerResponse{
|
||||||
Ok: false,
|
Ok: false,
|
||||||
Message:err.Error(),
|
Message: err.Error(),
|
||||||
}, 400)
|
}, 400)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -68,13 +68,13 @@ func (api *WebAPI) WorkerGet(r *Request) {
|
|||||||
|
|
||||||
if worker != nil {
|
if worker != nil {
|
||||||
r.OkJson(GetWorkerResponse{
|
r.OkJson(GetWorkerResponse{
|
||||||
Ok: true,
|
Ok: true,
|
||||||
Worker:worker,
|
Worker: worker,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
r.Json(GetWorkerResponse{
|
r.Json(GetWorkerResponse{
|
||||||
Ok: false,
|
Ok: false,
|
||||||
Message:"Worker not found",
|
Message: "Worker not found",
|
||||||
}, 404)
|
}, 404)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,7 +83,7 @@ func (api *WebAPI) workerCreate(request *CreateWorkerRequest, identity *storage.
|
|||||||
|
|
||||||
worker := storage.Worker{
|
worker := storage.Worker{
|
||||||
Id: uuid.New(),
|
Id: uuid.New(),
|
||||||
Created: time.Now().Unix(),
|
Created: time.Now().Unix(),
|
||||||
Identity: identity,
|
Identity: identity,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
schema.sql
17
schema.sql
@ -19,25 +19,28 @@ CREATE TABLE worker
|
|||||||
(
|
(
|
||||||
id TEXT PRIMARY KEY,
|
id TEXT PRIMARY KEY,
|
||||||
created INTEGER,
|
created INTEGER,
|
||||||
identity INTEGER REFERENCES workerIdentity(id)
|
identity INTEGER REFERENCES workerIdentity (id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE project
|
CREATE TABLE project
|
||||||
(
|
(
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
name TEXT UNIQUE,
|
priority INTEGER DEFAULT 0,
|
||||||
git_url TEXT,
|
name TEXT UNIQUE,
|
||||||
version TEXT
|
git_url TEXT,
|
||||||
|
version TEXT
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE task
|
CREATE TABLE task
|
||||||
(
|
(
|
||||||
id TEXT PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
|
priority INTEGER DEFAULT 0,
|
||||||
project INTEGER REFERENCES project (id),
|
project INTEGER REFERENCES project (id),
|
||||||
assignee TEXT REFERENCES worker (id),
|
assignee TEXT REFERENCES worker (id),
|
||||||
retries INTEGER DEFAULT 0,
|
retries INTEGER DEFAULT 0,
|
||||||
max_retries INTEGER,
|
max_retries INTEGER,
|
||||||
status Status DEFAULT 'new'
|
status Status DEFAULT 'new',
|
||||||
|
recipe TEXT
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,10 +6,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Project struct {
|
type Project struct {
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id"`
|
||||||
Name string `json:"name"`
|
Priority int64 `json:"priority"`
|
||||||
GitUrl string `json:"git_url"`
|
Name string `json:"name"`
|
||||||
Version string `json:"version"`
|
GitUrl string `json:"git_url"`
|
||||||
|
Version string `json:"version"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (database *Database) SaveProject(project *Project) (int64, error) {
|
func (database *Database) SaveProject(project *Project) (int64, error) {
|
||||||
@ -23,8 +24,8 @@ func (database *Database) SaveProject(project *Project) (int64, error) {
|
|||||||
|
|
||||||
func saveProject(project *Project, db *sql.DB) (int64, error) {
|
func saveProject(project *Project, db *sql.DB) (int64, error) {
|
||||||
|
|
||||||
row := db.QueryRow("INSERT INTO project (name, git_url, version) VALUES ($1,$2,$3) RETURNING id",
|
row := db.QueryRow("INSERT INTO project (name, git_url, version, priority) VALUES ($1,$2,$3, $4) RETURNING id",
|
||||||
project.Name, project.GitUrl, project.Version)
|
project.Name, project.GitUrl, project.Version, project.Priority)
|
||||||
|
|
||||||
var id int64
|
var id int64
|
||||||
err := row.Scan(&id)
|
err := row.Scan(&id)
|
||||||
@ -37,7 +38,7 @@ func saveProject(project *Project, db *sql.DB) (int64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
"id": id,
|
"id": id,
|
||||||
"project": project,
|
"project": project,
|
||||||
}).Trace("Database.saveProject INSERT project")
|
}).Trace("Database.saveProject INSERT project")
|
||||||
|
|
||||||
@ -57,10 +58,10 @@ func getProject(id int64, db *sql.DB) *Project {
|
|||||||
|
|
||||||
project := &Project{}
|
project := &Project{}
|
||||||
|
|
||||||
row := db.QueryRow("SELECT id, name, git_url, version FROM project WHERE id=$1",
|
row := db.QueryRow("SELECT id, name, git_url, version, priority FROM project WHERE id=$1",
|
||||||
id)
|
id)
|
||||||
|
|
||||||
err := row.Scan(&project.Id, &project.Name, &project.GitUrl, &project.Version)
|
err := row.Scan(&project.Id, &project.Name, &project.GitUrl, &project.Version, &project.Priority)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
"id": id,
|
"id": id,
|
||||||
@ -69,7 +70,7 @@ func getProject(id int64, db *sql.DB) *Project {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
"id": id,
|
"id": id,
|
||||||
"project": project,
|
"project": project,
|
||||||
}).Trace("Database.saveProject SELECT project")
|
}).Trace("Database.saveProject SELECT project")
|
||||||
|
|
||||||
|
148
storage/task.go
148
storage/task.go
@ -7,30 +7,32 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Task struct {
|
type Task struct {
|
||||||
Id int64
|
Id int64 `json:"id"`
|
||||||
Project int64
|
Priority int64 `json:"priority"`
|
||||||
Assignee uuid.UUID
|
Project *Project `json:"project"`
|
||||||
Retries int64
|
Assignee uuid.UUID `json:"assignee"`
|
||||||
MaxRetries int64
|
Retries int64 `json:"retries"`
|
||||||
Status string
|
MaxRetries int64 `json:"max_retries"`
|
||||||
Recipe string
|
Status string `json:"status"`
|
||||||
|
Recipe string `json:"recipe"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (database *Database) SaveTask(task *Task) error {
|
func (database *Database) SaveTask(task *Task, project int64) error {
|
||||||
|
|
||||||
db := database.getDB()
|
db := database.getDB()
|
||||||
taskErr := saveTask(task, db)
|
taskErr := saveTask(task, project, db)
|
||||||
err := db.Close()
|
err := db.Close()
|
||||||
handleErr(err)
|
handleErr(err)
|
||||||
|
|
||||||
return taskErr
|
return taskErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveTask(task *Task, db *sql.DB) error {
|
func saveTask(task *Task, project int64, db *sql.DB) error {
|
||||||
|
|
||||||
res, err := db.Exec("INSERT INTO task (project, max_retries, recipe) "+
|
res, err := db.Exec(`
|
||||||
"VALUES ($1,$2,$3)",
|
INSERT INTO task (project, max_retries, recipe, priority)
|
||||||
task.Project, task.MaxRetries, task.Recipe)
|
VALUES ($1,$2,$3,$4)`,
|
||||||
|
project, task.MaxRetries, task.Recipe, task.Priority)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).WithFields(logrus.Fields{
|
logrus.WithError(err).WithFields(logrus.Fields{
|
||||||
"task": task,
|
"task": task,
|
||||||
@ -48,3 +50,123 @@ func saveTask(task *Task, db *sql.DB) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (database *Database) GetTask(worker *Worker) *Task {
|
||||||
|
|
||||||
|
db := database.getDB()
|
||||||
|
task := getTask(worker, db)
|
||||||
|
err := db.Close()
|
||||||
|
handleErr(err)
|
||||||
|
|
||||||
|
return task
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTask(worker *Worker, db *sql.DB) *Task {
|
||||||
|
|
||||||
|
row := db.QueryRow(`
|
||||||
|
UPDATE task
|
||||||
|
SET assignee=$1
|
||||||
|
WHERE id IN
|
||||||
|
(
|
||||||
|
SELECT task.id
|
||||||
|
FROM task
|
||||||
|
INNER JOIN project p on task.project = p.id
|
||||||
|
WHERE assignee IS NULL
|
||||||
|
ORDER BY p.priority DESC, task.priority DESC
|
||||||
|
LIMIT 1
|
||||||
|
)
|
||||||
|
RETURNING id`, worker.Id)
|
||||||
|
var id int64
|
||||||
|
|
||||||
|
err := row.Scan(&id)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"worker": worker,
|
||||||
|
}).Trace("No task available")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"id": id,
|
||||||
|
"worker": worker,
|
||||||
|
}).Trace("Database.getTask UPDATE task")
|
||||||
|
|
||||||
|
task := getTaskById(id, db)
|
||||||
|
|
||||||
|
return task
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTaskById(id int64, db *sql.DB) *Task {
|
||||||
|
|
||||||
|
row := db.QueryRow(`
|
||||||
|
SELECT * FROM task
|
||||||
|
INNER JOIN project ON task.project = project.id
|
||||||
|
WHERE task.id=$1`, id)
|
||||||
|
task := scanTask(row)
|
||||||
|
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"id": id,
|
||||||
|
"task": task,
|
||||||
|
}).Trace("Database.getTaskById SELECT task")
|
||||||
|
|
||||||
|
return task
|
||||||
|
}
|
||||||
|
|
||||||
|
func (database *Database) GetTaskFromProject(worker *Worker, project int64) *Task {
|
||||||
|
|
||||||
|
db := database.getDB()
|
||||||
|
task := getTaskFromProject(worker, project, db)
|
||||||
|
err := db.Close()
|
||||||
|
handleErr(err)
|
||||||
|
|
||||||
|
return task
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTaskFromProject(worker *Worker, projectId int64, db *sql.DB) *Task {
|
||||||
|
|
||||||
|
row := db.QueryRow(`
|
||||||
|
UPDATE task
|
||||||
|
SET assignee=$1
|
||||||
|
WHERE id IN
|
||||||
|
(
|
||||||
|
SELECT task.id
|
||||||
|
FROM task
|
||||||
|
INNER JOIN project p on task.project = p.id
|
||||||
|
WHERE assignee IS NULL AND p.id=$2
|
||||||
|
ORDER BY p.priority DESC, task.priority DESC
|
||||||
|
LIMIT 1
|
||||||
|
)
|
||||||
|
RETURNING id`, worker.Id, projectId)
|
||||||
|
var id int64
|
||||||
|
|
||||||
|
err := row.Scan(&id)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"worker": worker,
|
||||||
|
}).Trace("No task available")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"id": id,
|
||||||
|
"worker": worker,
|
||||||
|
}).Trace("Database.getTask UPDATE task")
|
||||||
|
|
||||||
|
task := getTaskById(id, db)
|
||||||
|
|
||||||
|
return task
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanTask(row *sql.Row) *Task {
|
||||||
|
|
||||||
|
project := &Project{}
|
||||||
|
task := &Task{}
|
||||||
|
task.Project = project
|
||||||
|
|
||||||
|
err := row.Scan(&task.Id, &task.Priority, &project.Id, &task.Assignee,
|
||||||
|
&task.Retries, &task.MaxRetries, &task.Status, &task.Recipe, &project.Id,
|
||||||
|
&project.Priority, &project.Name, &project.GitUrl, &project.Version)
|
||||||
|
handleErr(err)
|
||||||
|
|
||||||
|
return task
|
||||||
|
}
|
||||||
|
@ -12,9 +12,10 @@ import (
|
|||||||
func TestCreateGetProject(t *testing.T) {
|
func TestCreateGetProject(t *testing.T) {
|
||||||
|
|
||||||
resp := createProject(api.CreateProjectRequest{
|
resp := createProject(api.CreateProjectRequest{
|
||||||
Name: "Test name",
|
Name: "Test name",
|
||||||
GitUrl: "http://github.com/test/test",
|
GitUrl: "http://github.com/test/test",
|
||||||
Version: "Test Version",
|
Version: "Test Version",
|
||||||
|
Priority: 123,
|
||||||
})
|
})
|
||||||
|
|
||||||
id := resp.Id
|
id := resp.Id
|
||||||
@ -29,26 +30,27 @@ func TestCreateGetProject(t *testing.T) {
|
|||||||
getResp, _ := getProject(id)
|
getResp, _ := getProject(id)
|
||||||
|
|
||||||
if getResp.Project.Id != id {
|
if getResp.Project.Id != id {
|
||||||
t.Fail()
|
t.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
if getResp.Project.Name != "Test name" {
|
if getResp.Project.Name != "Test name" {
|
||||||
t.Fail()
|
t.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
if getResp.Project.Version != "Test Version" {
|
if getResp.Project.Version != "Test Version" {
|
||||||
t.Fail()
|
t.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
if getResp.Project.GitUrl != "http://github.com/test/test" {
|
if getResp.Project.GitUrl != "http://github.com/test/test" {
|
||||||
t.Fail()
|
t.Error()
|
||||||
|
}
|
||||||
|
if getResp.Project.Priority != 123 {
|
||||||
|
t.Error()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateProjectInvalid(t *testing.T) {
|
func TestCreateProjectInvalid(t *testing.T) {
|
||||||
resp := createProject(api.CreateProjectRequest{
|
resp := createProject(api.CreateProjectRequest{})
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
if resp.Ok != false {
|
if resp.Ok != false {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
|
@ -2,6 +2,8 @@ package test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/google/uuid"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"src/task_tracker/api"
|
"src/task_tracker/api"
|
||||||
"testing"
|
"testing"
|
||||||
@ -11,16 +13,15 @@ func TestCreateTaskValid(t *testing.T) {
|
|||||||
|
|
||||||
//Make sure there is always a project for id:1
|
//Make sure there is always a project for id:1
|
||||||
createProject(api.CreateProjectRequest{
|
createProject(api.CreateProjectRequest{
|
||||||
Name: "Some Test name",
|
Name: "Some Test name",
|
||||||
Version: "Test Version",
|
Version: "Test Version",
|
||||||
GitUrl: "http://github.com/test/test",
|
GitUrl: "http://github.com/test/test",
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
resp := createTask(api.CreateTaskRequest{
|
resp := createTask(api.CreateTaskRequest{
|
||||||
Project:1,
|
Project: 1,
|
||||||
Recipe: "{}",
|
Recipe: "{}",
|
||||||
MaxRetries:3,
|
MaxRetries: 3,
|
||||||
})
|
})
|
||||||
|
|
||||||
if resp.Ok != true {
|
if resp.Ok != true {
|
||||||
@ -31,9 +32,9 @@ func TestCreateTaskValid(t *testing.T) {
|
|||||||
func TestCreateTaskInvalidProject(t *testing.T) {
|
func TestCreateTaskInvalidProject(t *testing.T) {
|
||||||
|
|
||||||
resp := createTask(api.CreateTaskRequest{
|
resp := createTask(api.CreateTaskRequest{
|
||||||
Project:123456,
|
Project: 123456,
|
||||||
Recipe: "{}",
|
Recipe: "{}",
|
||||||
MaxRetries:3,
|
MaxRetries: 3,
|
||||||
})
|
})
|
||||||
|
|
||||||
if resp.Ok != false {
|
if resp.Ok != false {
|
||||||
@ -48,8 +49,8 @@ func TestCreateTaskInvalidProject(t *testing.T) {
|
|||||||
func TestCreateTaskInvalidRetries(t *testing.T) {
|
func TestCreateTaskInvalidRetries(t *testing.T) {
|
||||||
|
|
||||||
resp := createTask(api.CreateTaskRequest{
|
resp := createTask(api.CreateTaskRequest{
|
||||||
Project:1,
|
Project: 1,
|
||||||
MaxRetries:-1,
|
MaxRetries: -1,
|
||||||
})
|
})
|
||||||
|
|
||||||
if resp.Ok != false {
|
if resp.Ok != false {
|
||||||
@ -61,6 +62,158 @@ func TestCreateTaskInvalidRetries(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateGetTask(t *testing.T) {
|
||||||
|
|
||||||
|
//Make sure there is always a project for id:1
|
||||||
|
resp := createProject(api.CreateProjectRequest{
|
||||||
|
Name: "My project",
|
||||||
|
Version: "1.0",
|
||||||
|
GitUrl: "http://github.com/test/test",
|
||||||
|
Priority: 999,
|
||||||
|
})
|
||||||
|
|
||||||
|
createTask(api.CreateTaskRequest{
|
||||||
|
Project: resp.Id,
|
||||||
|
Recipe: "{\"url\":\"test\"}",
|
||||||
|
MaxRetries: 3,
|
||||||
|
Priority: 9999,
|
||||||
|
})
|
||||||
|
|
||||||
|
taskResp := getTaskFromProject(resp.Id, genWid())
|
||||||
|
|
||||||
|
if taskResp.Ok != true {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
if taskResp.Task.Priority != 9999 {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
if taskResp.Task.Id == 0 {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
if taskResp.Task.Recipe != "{\"url\":\"test\"}" {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
if taskResp.Task.Status != "new" {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
if taskResp.Task.MaxRetries != 3 {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
if taskResp.Task.Project.Id != resp.Id {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
if taskResp.Task.Project.Priority != 999 {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
if taskResp.Task.Project.Version != "1.0" {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
if taskResp.Task.Project.GitUrl != "http://github.com/test/test" {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTasks(prefix string) (int64, int64) {
|
||||||
|
|
||||||
|
lowP := createProject(api.CreateProjectRequest{
|
||||||
|
Name: prefix + "low",
|
||||||
|
Version: "1.0",
|
||||||
|
GitUrl: "http://github.com/test/test",
|
||||||
|
Priority: 1,
|
||||||
|
})
|
||||||
|
highP := createProject(api.CreateProjectRequest{
|
||||||
|
Name: prefix + "high",
|
||||||
|
Version: "1.0",
|
||||||
|
GitUrl: "http://github.com/test/test",
|
||||||
|
Priority: 999,
|
||||||
|
})
|
||||||
|
createTask(api.CreateTaskRequest{
|
||||||
|
Project: lowP.Id,
|
||||||
|
Recipe: "low1",
|
||||||
|
Priority: 0,
|
||||||
|
})
|
||||||
|
createTask(api.CreateTaskRequest{
|
||||||
|
Project: lowP.Id,
|
||||||
|
Recipe: "low2",
|
||||||
|
Priority: 1,
|
||||||
|
})
|
||||||
|
createTask(api.CreateTaskRequest{
|
||||||
|
Project: highP.Id,
|
||||||
|
Recipe: "high1",
|
||||||
|
Priority: 100,
|
||||||
|
})
|
||||||
|
createTask(api.CreateTaskRequest{
|
||||||
|
Project: highP.Id,
|
||||||
|
Recipe: "high2",
|
||||||
|
Priority: 101,
|
||||||
|
})
|
||||||
|
|
||||||
|
return lowP.Id, highP.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTaskProjectPriority(t *testing.T) {
|
||||||
|
|
||||||
|
wid := genWid()
|
||||||
|
l, h := createTasks("withProject")
|
||||||
|
|
||||||
|
t1 := getTaskFromProject(l, wid)
|
||||||
|
t2 := getTaskFromProject(l, wid)
|
||||||
|
t3 := getTaskFromProject(h, wid)
|
||||||
|
t4 := getTaskFromProject(h, wid)
|
||||||
|
|
||||||
|
if t1.Task.Recipe != "low2" {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
if t2.Task.Recipe != "low1" {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
if t3.Task.Recipe != "high2" {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
if t4.Task.Recipe != "high1" {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTaskPriority(t *testing.T) {
|
||||||
|
|
||||||
|
wid := genWid()
|
||||||
|
|
||||||
|
// Clean other tasks
|
||||||
|
for i := 0; i < 20; i++ {
|
||||||
|
getTask(wid)
|
||||||
|
}
|
||||||
|
|
||||||
|
createTasks("")
|
||||||
|
|
||||||
|
t1 := getTask(wid)
|
||||||
|
t2 := getTask(wid)
|
||||||
|
t3 := getTask(wid)
|
||||||
|
t4 := getTask(wid)
|
||||||
|
|
||||||
|
if t1.Task.Recipe != "high2" {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
if t2.Task.Recipe != "high1" {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
if t3.Task.Recipe != "low2" {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
if t4.Task.Recipe != "low1" {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNoMoreTasks(t *testing.T) {
|
||||||
|
|
||||||
|
wid := genWid()
|
||||||
|
|
||||||
|
for i := 0; i < 30; i++ {
|
||||||
|
getTask(wid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func createTask(request api.CreateTaskRequest) *api.CreateTaskResponse {
|
func createTask(request api.CreateTaskRequest) *api.CreateTaskResponse {
|
||||||
|
|
||||||
r := Post("/task/create", request)
|
r := Post("/task/create", request)
|
||||||
@ -72,3 +225,27 @@ func createTask(request api.CreateTaskRequest) *api.CreateTaskResponse {
|
|||||||
|
|
||||||
return &resp
|
return &resp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getTask(wid *uuid.UUID) *api.GetTaskResponse {
|
||||||
|
|
||||||
|
r := Get(fmt.Sprintf("/task/get?wid=%s", wid))
|
||||||
|
|
||||||
|
var resp api.GetTaskResponse
|
||||||
|
data, _ := ioutil.ReadAll(r.Body)
|
||||||
|
err := json.Unmarshal(data, &resp)
|
||||||
|
handleErr(err)
|
||||||
|
|
||||||
|
return &resp
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTaskFromProject(project int64, wid *uuid.UUID) *api.GetTaskResponse {
|
||||||
|
|
||||||
|
r := Get(fmt.Sprintf("/task/get/%d?wid=%s", project, wid))
|
||||||
|
|
||||||
|
var resp api.GetTaskResponse
|
||||||
|
data, _ := ioutil.ReadAll(r.Body)
|
||||||
|
err := json.Unmarshal(data, &resp)
|
||||||
|
handleErr(err)
|
||||||
|
|
||||||
|
return &resp
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ package test
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/google/uuid"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"src/task_tracker/api"
|
"src/task_tracker/api"
|
||||||
@ -21,13 +22,13 @@ func TestCreateGetWorker(t *testing.T) {
|
|||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
|
||||||
getResp, r := getWorker(resp.WorkerId)
|
getResp, r := getWorker(resp.WorkerId.String())
|
||||||
|
|
||||||
if r.StatusCode != 200 {
|
if r.StatusCode != 200 {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.WorkerId != getResp.Worker.Id.String() {
|
if resp.WorkerId != getResp.Worker.Id {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,3 +82,9 @@ func getWorker(id string) (*api.GetWorkerResponse, *http.Response) {
|
|||||||
|
|
||||||
return resp, r
|
return resp, r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func genWid() *uuid.UUID {
|
||||||
|
|
||||||
|
resp, _ := createWorker(api.CreateWorkerRequest{})
|
||||||
|
return &resp.WorkerId
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user