diff --git a/api/main.go b/api/main.go index 3008e46..5c12015 100644 --- a/api/main.go +++ b/api/main.go @@ -9,15 +9,18 @@ import ( "github.com/simon987/task_tracker/config" "github.com/simon987/task_tracker/storage" "github.com/valyala/fasthttp" + "sync" ) type WebAPI struct { - server *fasthttp.Server - router *fasthttprouter.Router - Database *storage.Database - SessionConfig sessions.Config - Session *sessions.Sessions - Cron *cron.Cron + server *fasthttp.Server + router *fasthttprouter.Router + Database *storage.Database + SessionConfig sessions.Config + Session *sessions.Sessions + Cron *cron.Cron + AssignLimiters sync.Map + SubmitLimiters sync.Map } type RequestHandler func(*Request) @@ -98,7 +101,6 @@ func New() *WebAPI { api.router.POST("/task/submit", LogRequestMiddleware(api.SubmitTask)) api.router.GET("/task/get/:project", LogRequestMiddleware(api.GetTaskFromProject)) - api.router.GET("/task/get", LogRequestMiddleware(api.GetTask)) api.router.POST("/task/release", LogRequestMiddleware(api.ReleaseTask)) api.router.POST("/git/receivehook", LogRequestMiddleware(api.ReceiveGitWebHook)) diff --git a/api/models.go b/api/models.go index c4f8b23..ee38bf3 100644 --- a/api/models.go +++ b/api/models.go @@ -3,6 +3,7 @@ package api import ( "encoding/json" "github.com/simon987/task_tracker/storage" + "golang.org/x/time/rate" ) const ( @@ -12,9 +13,10 @@ const ( ) type JsonResponse struct { - Ok bool `json:"ok"` - Message string `json:"message,omitempty"` - Content interface{} `json:"content,omitempty"` + Ok bool `json:"ok"` + Message string `json:"message,omitempty"` + RateLimitDelay string `json:"rate_limit_delay,omitempty"` + Content interface{} `json:"content,omitempty"` } type GitPayload struct { @@ -115,15 +117,17 @@ type GetSnapshotsResponse struct { } type CreateProjectRequest struct { - Name string `json:"name"` - CloneUrl string `json:"clone_url"` - GitRepo string `json:"git_repo"` - Version string `json:"version"` - Priority int64 `json:"priority"` - Motd string `json:"motd"` - Public bool `json:"public"` - Hidden bool `json:"hidden"` - Chain int64 `json:"chain"` + Name string `json:"name"` + CloneUrl string `json:"clone_url"` + GitRepo string `json:"git_repo"` + Version string `json:"version"` + Priority int64 `json:"priority"` + Motd string `json:"motd"` + Public bool `json:"public"` + Hidden bool `json:"hidden"` + Chain int64 `json:"chain"` + AssignRate rate.Limit `json:"assign_rate"` + SubmitRate rate.Limit `json:"submit_rate"` } func (req *CreateProjectRequest) isValid() bool { @@ -140,15 +144,17 @@ func (req *CreateProjectRequest) isValid() bool { } type UpdateProjectRequest struct { - Name string `json:"name"` - CloneUrl string `json:"clone_url"` - GitRepo string `json:"git_repo"` - Priority int64 `json:"priority"` - Motd string `json:"motd"` - Public bool `json:"public"` - Hidden bool `json:"hidden"` - Chain int64 `json:"chain"` - Paused bool `json:"paused"` + Name string `json:"name"` + CloneUrl string `json:"clone_url"` + GitRepo string `json:"git_repo"` + Priority int64 `json:"priority"` + Motd string `json:"motd"` + Public bool `json:"public"` + Hidden bool `json:"hidden"` + Chain int64 `json:"chain"` + Paused bool `json:"paused"` + AssignRate rate.Limit `json:"assign_rate"` + SubmitRate rate.Limit `json:"submit_rate"` } func (req *UpdateProjectRequest) isValid() bool { diff --git a/api/project.go b/api/project.go index 0381162..3310a4d 100644 --- a/api/project.go +++ b/api/project.go @@ -5,6 +5,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/google/uuid" "github.com/simon987/task_tracker/storage" + "golang.org/x/time/rate" "strconv" ) @@ -62,16 +63,25 @@ func (api *WebAPI) CreateProject(r *Request) { }, 400) return } + + if createReq.AssignRate == 0 { + createReq.AssignRate = rate.Inf + } + if createReq.SubmitRate == 0 { + createReq.SubmitRate = rate.Inf + } project := &storage.Project{ - Name: createReq.Name, - Version: createReq.Version, - CloneUrl: createReq.CloneUrl, - GitRepo: createReq.GitRepo, - Priority: createReq.Priority, - Motd: createReq.Motd, - Public: createReq.Public, - Hidden: createReq.Hidden, - Chain: createReq.Chain, + Name: createReq.Name, + Version: createReq.Version, + CloneUrl: createReq.CloneUrl, + GitRepo: createReq.GitRepo, + Priority: createReq.Priority, + Motd: createReq.Motd, + Public: createReq.Public, + Hidden: createReq.Hidden, + Chain: createReq.Chain, + AssignRate: createReq.AssignRate, + SubmitRate: createReq.SubmitRate, } if !createReq.isValid() { @@ -156,16 +166,18 @@ func (api *WebAPI) UpdateProject(r *Request) { } project := &storage.Project{ - Id: id, - Name: updateReq.Name, - CloneUrl: updateReq.CloneUrl, - GitRepo: updateReq.GitRepo, - Priority: updateReq.Priority, - Motd: updateReq.Motd, - Public: updateReq.Public, - Hidden: updateReq.Hidden, - Chain: updateReq.Chain, - Paused: updateReq.Paused, + Id: id, + Name: updateReq.Name, + CloneUrl: updateReq.CloneUrl, + GitRepo: updateReq.GitRepo, + Priority: updateReq.Priority, + Motd: updateReq.Motd, + Public: updateReq.Public, + Hidden: updateReq.Hidden, + Chain: updateReq.Chain, + Paused: updateReq.Paused, + AssignRate: updateReq.AssignRate, + SubmitRate: updateReq.SubmitRate, } sess := api.Session.StartFasthttp(r.Ctx) manager := sess.Get("manager") diff --git a/api/rate.go b/api/rate.go new file mode 100644 index 0000000..f7b8470 --- /dev/null +++ b/api/rate.go @@ -0,0 +1,40 @@ +package api + +import ( + "fmt" + "golang.org/x/time/rate" + "time" +) + +func (api *WebAPI) ReserveSubmit(pid int64) *rate.Reservation { + + limiter, ok := api.SubmitLimiters.Load(pid) + if !ok { + project := api.Database.GetProject(pid) + if project == nil { + return &rate.Reservation{} + } + + limiter = rate.NewLimiter(project.SubmitRate, 1) + api.SubmitLimiters.Store(pid, limiter) + } + + return limiter.(*rate.Limiter).ReserveN(time.Now(), 1) +} + +func (api *WebAPI) ReserveAssign(pid int64) *rate.Reservation { + + limiter, ok := api.AssignLimiters.Load(pid) + if !ok { + project := api.Database.GetProject(pid) + if project == nil { + return &rate.Reservation{} + } + + limiter = rate.NewLimiter(project.AssignRate, 1) + api.AssignLimiters.Store(pid, limiter) + fmt.Printf("Create") + } + + return limiter.(*rate.Limiter).ReserveN(time.Now(), 1) +} diff --git a/api/task.go b/api/task.go index ad1e34d..a350aec 100644 --- a/api/task.go +++ b/api/task.go @@ -11,6 +11,7 @@ import ( "github.com/dchest/siphash" "github.com/simon987/task_tracker/storage" "strconv" + "time" ) func (api *WebAPI) SubmitTask(r *Request) { @@ -53,6 +54,17 @@ func (api *WebAPI) SubmitTask(r *Request) { return } + reservation := api.ReserveSubmit(createReq.Project) + delay := reservation.DelayFrom(time.Now()).Seconds() + if delay > 0 { + r.Json(JsonResponse{ + Ok: false, + Message: "Too many requests", + RateLimitDelay: strconv.FormatFloat(delay, 'f', -1, 64), + }, 429) + return + } + if createReq.UniqueString != "" { //TODO: Load key from config createReq.Hash64 = int64(siphash.Hash(1, 2, []byte(createReq.UniqueString))) @@ -65,6 +77,7 @@ func (api *WebAPI) SubmitTask(r *Request) { Ok: false, Message: err.Error(), }, 400) + reservation.Cancel() } else { r.OkJson(JsonResponse{ Ok: true, @@ -84,47 +97,33 @@ func (api *WebAPI) GetTaskFromProject(r *Request) { } project, err := strconv.ParseInt(r.Ctx.UserValue("project").(string), 10, 64) - handleErr(err, r) - task := api.Database.GetTaskFromProject(worker, project) - - if task == nil { - - r.OkJson(JsonResponse{ - Ok: false, - Message: "No task available", - }) - - } else { - - r.OkJson(JsonResponse{ - Ok: true, - Content: GetTaskResponse{ - Task: task, - }, - }) - } - -} - -func (api *WebAPI) GetTask(r *Request) { - - worker, err := api.validateSignature(r) - if err != nil { + if err != nil || project <= 0 { r.Json(JsonResponse{ Ok: false, - Message: err.Error(), - }, 403) + Message: "Invalid project id", + }, 400) return } - task := api.Database.GetTask(worker) - if task == nil { + reservation := api.ReserveAssign(project) + delay := reservation.DelayFrom(time.Now()).Seconds() + if delay > 0 { + r.Json(JsonResponse{ + Ok: false, + Message: "Too many requests", + RateLimitDelay: strconv.FormatFloat(delay, 'f', -1, 64), + }, 429) + return + } + task := api.Database.GetTaskFromProject(worker, project) + + if task == nil { r.OkJson(JsonResponse{ Ok: false, Message: "No task available", }) - + reservation.CancelAt(time.Now()) } else { r.OkJson(JsonResponse{ @@ -134,8 +133,8 @@ func (api *WebAPI) GetTask(r *Request) { }, }) } -} +} func (api WebAPI) validateSignature(r *Request) (*storage.Worker, error) { widStr := string(r.Ctx.Request.Header.Peek("X-Worker-Id")) diff --git a/jenkins/Jenkinsfile b/jenkins/Jenkinsfile index 353d36b..678679d 100644 --- a/jenkins/Jenkinsfile +++ b/jenkins/Jenkinsfile @@ -68,7 +68,7 @@ pipeline { node('master') { unstash 'webdist' unstash 'apidist' - sshCommand remote: remote, command: "rm -rf tt_api config.yml schema.sql webroot deploy.sh" + sshCommand remote: remote, command: "cd task_tracker && rm -rf tt_api config.yml schema.sql webroot deploy.sh" sshPut remote: remote, from: 'tt_api', into: 'task_tracker/tt_api' sshPut remote: remote, from: 'config.yml', into: 'task_tracker/config.yml' sshPut remote: remote, from: 'schema.sql', into: 'task_tracker/schema.sql' diff --git a/schema.sql b/schema.sql index 878f063..0c9a6b8 100755 --- a/schema.sql +++ b/schema.sql @@ -15,17 +15,20 @@ CREATE TABLE project ( id SERIAL PRIMARY KEY 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), - public boolean NOT NULL, - hidden boolean NOT NULL, - paused boolean NOT NULL, - name TEXT UNIQUE NOT NULL, - clone_url TEXT NOT NULL, - git_repo TEXT NOT NULL, - version TEXT NOT NULL, - motd TEXT NOT NULL, - secret TEXT NOT NULL DEFAULT '{}' + public boolean NOT NULL, + hidden boolean NOT NULL, + paused boolean NOT NULL, + name TEXT UNIQUE NOT NULL, + clone_url TEXT NOT NULL, + git_repo TEXT NOT NULL, + version TEXT NOT NULL, + motd TEXT NOT NULL, + secret TEXT NOT NULL DEFAULT '{}', + webhook_secret TEXT NOT NULL, + assign_rate DOUBLE PRECISION NOT NULL, + submit_rate DOUBLE PRECISION NOT NULL ); CREATE TABLE worker_access diff --git a/storage/project.go b/storage/project.go index dba5b8d..97e2a2f 100644 --- a/storage/project.go +++ b/storage/project.go @@ -3,21 +3,24 @@ package storage import ( "database/sql" "github.com/Sirupsen/logrus" + "golang.org/x/time/rate" "strings" ) type Project struct { - Id int64 `json:"id"` - Priority int64 `json:"priority"` - Name string `json:"name"` - CloneUrl string `json:"clone_url"` - GitRepo string `json:"git_repo"` - Version string `json:"version"` - Motd string `json:"motd"` - Public bool `json:"public"` - Hidden bool `json:"hidden"` - Chain int64 `json:"chain"` - Paused bool `json:"paused"` + Id int64 `json:"id"` + Priority int64 `json:"priority"` + Name string `json:"name"` + CloneUrl string `json:"clone_url"` + GitRepo string `json:"git_repo"` + Version string `json:"version"` + Motd string `json:"motd"` + Public bool `json:"public"` + Hidden bool `json:"hidden"` + Chain int64 `json:"chain"` + Paused bool `json:"paused"` + AssignRate rate.Limit `json:"assign_rate"` + SubmitRate rate.Limit `json:"submit_rate"` } type AssignedTasks struct { @@ -29,10 +32,11 @@ func (database *Database) SaveProject(project *Project, webhookSecret string) (i db := database.getDB() row := db.QueryRow(`INSERT INTO project (name, git_repo, clone_url, version, priority, - motd, public, hidden, chain, paused, webhook_secret) - VALUES ($1,$2,$3,$4,$5,$6,$7,$8,NULLIF($9, 0),$10,$11) RETURNING id`, + motd, public, hidden, chain, paused, webhook_secret, assign_rate, submit_rate) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,NULLIF($9, 0),$10,$11,$12,$13) RETURNING id`, project.Name, project.GitRepo, project.CloneUrl, project.Version, project.Priority, project.Motd, - project.Public, project.Hidden, project.Chain, project.Paused, webhookSecret) + project.Public, project.Hidden, project.Chain, project.Paused, webhookSecret, project.AssignRate, + project.SubmitRate) var id int64 err := row.Scan(&id) @@ -58,7 +62,7 @@ func (database *Database) GetProject(id int64) *Project { db := database.getDB() row := db.QueryRow(`SELECT id, priority, name, clone_url, git_repo, version, - motd, public, hidden, COALESCE(chain, 0), paused + motd, public, hidden, COALESCE(chain, 0), paused, assign_rate, submit_rate FROM project WHERE id=$1`, id) project, err := scanProject(row) @@ -81,7 +85,7 @@ func scanProject(row *sql.Row) (*Project, error) { p := &Project{} err := row.Scan(&p.Id, &p.Priority, &p.Name, &p.CloneUrl, &p.GitRepo, &p.Version, - &p.Motd, &p.Public, &p.Hidden, &p.Chain, &p.Paused) + &p.Motd, &p.Public, &p.Hidden, &p.Chain, &p.Paused, &p.AssignRate, &p.SubmitRate) return p, err } @@ -90,7 +94,8 @@ func (database *Database) GetProjectWithRepoName(repoName string) *Project { db := database.getDB() row := db.QueryRow(`SELECT id, priority, name, clone_url, git_repo, version, - motd, public, hidden, COALESCE(chain, 0), paused FROM project WHERE LOWER(git_repo)=$1`, + motd, public, hidden, COALESCE(chain, 0), paused, assign_rate, submit_rate + FROM project WHERE LOWER(git_repo)=$1`, strings.ToLower(repoName)) project, err := scanProject(row) @@ -109,11 +114,13 @@ func (database *Database) UpdateProject(project *Project) error { db := database.getDB() res, err := db.Exec(`UPDATE project - SET (priority, name, clone_url, git_repo, version, motd, public, hidden, chain, paused) = - ($1,$2,$3,$4,$5,$6,$7,$8,NULLIF($9, 0), $10) - WHERE id=$11`, + SET (priority, name, clone_url, git_repo, version, motd, public, hidden, chain, paused, + assign_rate, submit_rate) = + ($1,$2,$3,$4,$5,$6,$7,$8,NULLIF($9, 0), $10,$11,$12) + WHERE id=$13`, project.Priority, project.Name, project.CloneUrl, project.GitRepo, project.Version, project.Motd, - project.Public, project.Hidden, project.Chain, project.Paused, project.Id) + project.Public, project.Hidden, project.Chain, project.Paused, project.AssignRate, project.SubmitRate, + project.Id) if err != nil { return err } diff --git a/storage/task.go b/storage/task.go index 7aab7d6..2bf2c7b 100644 --- a/storage/task.go +++ b/storage/task.go @@ -1,7 +1,6 @@ package storage import ( - "database/sql" "errors" "fmt" "github.com/Sirupsen/logrus" @@ -69,75 +68,6 @@ func (database *Database) SaveTask(task *Task, project int64, hash64 int64, wid return nil } -func (database *Database) GetTask(worker *Worker) *Task { - - db := database.getDB() - - row := db.QueryRow(` - UPDATE task - SET assignee=$1, assign_time=extract(epoch from now() at time zone 'utc') - WHERE id IN - ( - SELECT task.id - FROM task - INNER JOIN project project on task.project = project.id - LEFT JOIN worker_verifies_task wvt on task.id = wvt.task AND wvt.worker=$1 - WHERE NOT project.paused AND assignee IS NULL AND task.status=1 - AND (project.public OR ( - SELECT a.role_assign AND not a.request FROM worker_access a WHERE a.worker=$1 AND a.project=project.id - )) - AND wvt.task IS NULL - ORDER BY project.priority DESC, task.priority DESC - LIMIT 1 - ) - RETURNING id`, worker.Id) - var id int64 - - err := row.Scan(&id) - if err != nil { - logrus.WithError(err).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 task.id, task.priority, task.project, assignee, retries, max_retries, - status, recipe, max_assign_time, assign_time, verification_count, project.priority, project.name, - project.clone_url, project.git_repo, project.version, project.motd, project.public, COALESCE(project.chain,0) FROM task - INNER JOIN project project ON task.project = project.id - WHERE task.id=$1`, id) - 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, &task.MaxAssignTime, - &task.AssignTime, &task.VerificationCount, &project.Priority, &project.Name, - &project.CloneUrl, &project.GitRepo, &project.Version, &project.Motd, &project.Public, - &project.Chain) - handleErr(err) - - logrus.WithFields(logrus.Fields{ - "id": id, - "task": task, - }).Trace("Database.getTaskById SELECT task") - - return task -} - func (database Database) ReleaseTask(id int64, workerId int64, result TaskResult, verification int64) bool { db := database.getDB() @@ -205,12 +135,24 @@ func (database *Database) GetTaskFromProject(worker *Worker, projectId int64) *T return nil } - logrus.WithFields(logrus.Fields{ - "id": id, - "worker": worker, - }).Trace("Database.getTask UPDATE task") + row = db.QueryRow(` + SELECT task.id, task.priority, task.project, assignee, retries, max_retries, + status, recipe, max_assign_time, assign_time, verification_count, project.priority, project.name, + project.clone_url, project.git_repo, project.version, project.motd, project.public, COALESCE(project.chain,0), + project.assign_rate, project.submit_rate + FROM task + INNER JOIN project project ON task.project = project.id + WHERE task.id=$1`, id) + project := &Project{} + task := &Task{} + task.Project = project - task := getTaskById(id, db) + err = row.Scan(&task.Id, &task.Priority, &project.Id, &task.Assignee, + &task.Retries, &task.MaxRetries, &task.Status, &task.Recipe, &task.MaxAssignTime, + &task.AssignTime, &task.VerificationCount, &project.Priority, &project.Name, + &project.CloneUrl, &project.GitRepo, &project.Version, &project.Motd, &project.Public, + &project.Chain, &project.AssignRate, &project.SubmitRate) + handleErr(err) return task } diff --git a/test/api_project_test.go b/test/api_project_test.go index a5e9959..dd0c346 100644 --- a/test/api_project_test.go +++ b/test/api_project_test.go @@ -13,14 +13,16 @@ import ( func TestCreateGetProject(t *testing.T) { resp := createProjectAsAdmin(api.CreateProjectRequest{ - Name: "Test name", - CloneUrl: "http://github.com/test/test", - GitRepo: "drone/webhooktest", - Version: "Test Version", - Priority: 123, - Motd: "motd", - Public: true, - Hidden: false, + Name: "Test name", + CloneUrl: "http://github.com/test/test", + GitRepo: "drone/webhooktest", + Version: "Test Version", + Priority: 123, + Motd: "motd", + Public: true, + Hidden: false, + AssignRate: 10.0, + SubmitRate: 20.0, }) id := resp.Content.Id @@ -64,6 +66,12 @@ func TestCreateGetProject(t *testing.T) { if getResp.Project.Hidden != false { t.Error() } + if getResp.Project.SubmitRate != 20.0 { + t.Error() + } + if getResp.Project.AssignRate != 10.0 { + t.Error() + } } func TestCreateProjectInvalid(t *testing.T) { @@ -107,24 +115,28 @@ func TestGetProjectNotFound(t *testing.T) { func TestUpdateProjectValid(t *testing.T) { pid := createProjectAsAdmin(api.CreateProjectRequest{ - Public: true, - Version: "versionA", - Motd: "MotdA", - Name: "NameA", - CloneUrl: "CloneUrlA", - GitRepo: "GitRepoA", - Priority: 1, + Public: true, + Version: "versionA", + Motd: "MotdA", + Name: "NameA", + CloneUrl: "CloneUrlA", + GitRepo: "GitRepoA", + Priority: 1, + AssignRate: 3, + SubmitRate: 3, }).Content.Id updateResp := updateProject(api.UpdateProjectRequest{ - Priority: 2, - GitRepo: "GitRepoB", - CloneUrl: "CloneUrlB", - Name: "NameB", - Motd: "MotdB", - Public: false, - Hidden: true, - Paused: true, + Priority: 2, + GitRepo: "GitRepoB", + CloneUrl: "CloneUrlB", + Name: "NameB", + Motd: "MotdB", + Public: false, + Hidden: true, + Paused: true, + AssignRate: 1, + SubmitRate: 2, }, pid, testAdminCtx) if updateResp.Ok != true { @@ -154,6 +166,12 @@ func TestUpdateProjectValid(t *testing.T) { if proj.Project.Paused != true { t.Error() } + if proj.Project.AssignRate != 1 { + t.Error() + } + if proj.Project.SubmitRate != 2 { + t.Error() + } } func TestUpdateProjectInvalid(t *testing.T) { diff --git a/test/api_rate_test.go b/test/api_rate_test.go new file mode 100644 index 0000000..95d7d3e --- /dev/null +++ b/test/api_rate_test.go @@ -0,0 +1,80 @@ +package test + +import ( + "fmt" + "github.com/simon987/task_tracker/api" + "testing" +) + +func TestAssignRateLimit(t *testing.T) { + + project := createProjectAsAdmin(api.CreateProjectRequest{ + SubmitRate: 2, + AssignRate: 2, + Name: "testassignratelimit", + GitRepo: "testassignratelimit", + CloneUrl: "testassignratelimit", + }).Content.Id + + w := genWid() + requestAccess(api.CreateWorkerAccessRequest{ + Project: project, + Submit: true, + Assign: true, + }, w) + acceptAccessRequest(project, w.Id, testAdminCtx) + + for i := 0; i < 3; i++ { + createTask(api.SubmitTaskRequest{ + Project: project, + Recipe: fmt.Sprintf("%d", i), + }, w) + } + + var lastResp TaskAR + for i := 0; i < 3; i++ { + lastResp = getTaskFromProject(project, w) + } + + if lastResp.Ok != false { + t.Error() + } + if len(lastResp.Message) <= 0 { + t.Error() + } +} + +func TestSubmitRateLimit(t *testing.T) { + + project := createProjectAsAdmin(api.CreateProjectRequest{ + SubmitRate: 2, + AssignRate: 2, + Name: "testsubmitratlimit", + GitRepo: "testsubmitratelimit", + CloneUrl: "testsubmitratelimit", + }).Content.Id + + w := genWid() + requestAccess(api.CreateWorkerAccessRequest{ + Project: project, + Submit: true, + Assign: true, + }, w) + acceptAccessRequest(project, w.Id, testAdminCtx) + + var lastResp api.JsonResponse + for i := 0; i < 2; i++ { + lastResp = createTask(api.SubmitTaskRequest{ + Project: project, + Recipe: fmt.Sprintf("%d", i), + }, w) + } + + if lastResp.Ok != false { + t.Error() + } + if len(lastResp.Message) <= 0 { + t.Error() + } + +} diff --git a/test/api_task_test.go b/test/api_task_test.go index 40ea7b0..9bbc363 100644 --- a/test/api_task_test.go +++ b/test/api_task_test.go @@ -57,7 +57,7 @@ func TestCreateTaskInvalidProject(t *testing.T) { func TestGetTaskInvalidWid(t *testing.T) { - resp := getTask(nil) + resp := getTaskFromProject(testProject, genWid()) if resp.Ok != false { t.Error() @@ -70,7 +70,7 @@ func TestGetTaskInvalidWid(t *testing.T) { func TestGetTaskInvalidWorker(t *testing.T) { - resp := getTask(&storage.Worker{ + resp := getTaskFromProject(testProject, &storage.Worker{ Id: -1, }) @@ -138,12 +138,14 @@ func TestCreateTaskInvalidRecipe(t *testing.T) { func TestCreateGetTask(t *testing.T) { pid := createProjectAsAdmin(api.CreateProjectRequest{ - Name: "My project", - Version: "1.0", - CloneUrl: "http://github.com/test/test", - GitRepo: "myrepo", - Priority: 999, - Public: true, + Name: "My project", + Version: "1.0", + CloneUrl: "http://github.com/test/test", + GitRepo: "myrepo", + Priority: 999, + Public: true, + AssignRate: 2, + SubmitRate: 2, }).Content.Id worker := genWid() @@ -197,6 +199,12 @@ func TestCreateGetTask(t *testing.T) { if taskResp.Task.Project.Public != true { t.Error() } + if taskResp.Task.Project.AssignRate == 1 { + t.Error() + } + if taskResp.Task.Project.SubmitRate != 2 { + t.Error() + } } func createTasks(prefix string) (int64, int64) { @@ -279,36 +287,6 @@ func TestTaskProjectPriority(t *testing.T) { } } -func TestTaskPriority(t *testing.T) { - - wid := genWid() - - // Clean other tasks - for i := 0; i < 20; i++ { - getTask(wid) - } - - createTasks("") - - t1 := getTask(wid).Content - t2 := getTask(wid).Content - t3 := getTask(wid).Content - t4 := getTask(wid).Content - - 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 TestTaskNoAccess(t *testing.T) { worker := genWid() @@ -400,15 +378,6 @@ func TestTaskHasAccess(t *testing.T) { } } -func TestNoMoreTasks(t *testing.T) { - - worker := genWid() - - for i := 0; i < 15; i++ { - getTask(worker) - } -} - func TestReleaseTaskSuccess(t *testing.T) { worker := genWid() diff --git a/test/schema.sql b/test/schema.sql index b8cf304..79559a4 100755 --- a/test/schema.sql +++ b/test/schema.sql @@ -16,17 +16,19 @@ CREATE TABLE project id SERIAL PRIMARY KEY NOT NULL, priority INTEGER DEFAULT 0 NOT NULL, closed_task_count INT DEFAULT 0 NOT NULL, - chain INT DEFAULT NULL REFERENCES project (id), - public boolean NOT NULL, - hidden boolean NOT NULL, - paused boolean NOT NULL, - name TEXT UNIQUE NOT NULL, - clone_url TEXT NOT NULL, - git_repo TEXT NOT NULL, - version TEXT NOT NULL, - motd TEXT NOT NULL, - secret TEXT NOT NULL DEFAULT '{}', - webhook_secret TEXT NOT NULL + chain INT DEFAULT NULL REFERENCES project (id), + public boolean NOT NULL, + hidden boolean NOT NULL, + paused boolean NOT NULL, + name TEXT UNIQUE NOT NULL, + clone_url TEXT NOT NULL, + git_repo TEXT NOT NULL, + version TEXT NOT NULL, + motd TEXT NOT NULL, + secret TEXT NOT NULL DEFAULT '{}', + webhook_secret TEXT NOT NULL, + assign_rate DOUBLE PRECISION NOT NULL, + submit_rate DOUBLE PRECISION NOT NULL ); CREATE TABLE worker_access