aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2019-12-04 14:49:59 +0100
committerChocobozzz <me@florianbigard.com>2019-12-04 14:49:59 +0100
commit1061c73fde3005100ead8764eacb444f240440d6 (patch)
tree0a548d7f0a9a548a52adf6d702dd589b04cd5ab0
parent44df5c755c31798e64eba1ec41dd7e2d7ef50e56 (diff)
downloadPeerTube-1061c73fde3005100ead8764eacb444f240440d6.tar.gz
PeerTube-1061c73fde3005100ead8764eacb444f240440d6.tar.zst
PeerTube-1061c73fde3005100ead8764eacb444f240440d6.zip
Add ability to filter per job type
-rw-r--r--client/src/app/+admin/system/jobs/job.service.ts7
-rw-r--r--client/src/app/+admin/system/jobs/jobs.component.html20
-rw-r--r--client/src/app/+admin/system/jobs/jobs.component.scss18
-rw-r--r--client/src/app/+admin/system/jobs/jobs.component.ts39
-rw-r--r--client/src/types/job-type-client.type.ts3
-rw-r--r--server/controllers/api/jobs.ts11
-rw-r--r--server/helpers/custom-validators/jobs.ts10
-rw-r--r--server/lib/job-queue/job-queue.ts26
-rw-r--r--server/middlewares/validators/jobs.ts12
-rw-r--r--server/tests/api/check-params/jobs.ts12
-rw-r--r--server/tests/api/server/handle-down.ts9
-rw-r--r--server/tests/api/server/jobs.ts50
-rw-r--r--server/tests/real-world/real-world.ts9
-rw-r--r--shared/extra-utils/server/jobs.ts46
-rw-r--r--shared/models/server/job.model.ts6
15 files changed, 220 insertions, 58 deletions
diff --git a/client/src/app/+admin/system/jobs/job.service.ts b/client/src/app/+admin/system/jobs/job.service.ts
index 1daae8f03..120144dff 100644
--- a/client/src/app/+admin/system/jobs/job.service.ts
+++ b/client/src/app/+admin/system/jobs/job.service.ts
@@ -3,11 +3,12 @@ import { HttpClient, HttpParams } from '@angular/common/http'
3import { Injectable } from '@angular/core' 3import { Injectable } from '@angular/core'
4import { SortMeta } from 'primeng/api' 4import { SortMeta } from 'primeng/api'
5import { Observable } from 'rxjs' 5import { Observable } from 'rxjs'
6import { ResultList } from '../../../../../../shared' 6import { JobType, ResultList } from '../../../../../../shared'
7import { JobState } from '../../../../../../shared/models' 7import { JobState } from '../../../../../../shared/models'
8import { Job } from '../../../../../../shared/models/server/job.model' 8import { Job } from '../../../../../../shared/models/server/job.model'
9import { environment } from '../../../../environments/environment' 9import { environment } from '../../../../environments/environment'
10import { RestExtractor, RestPagination, RestService } from '../../../shared' 10import { RestExtractor, RestPagination, RestService } from '../../../shared'
11import { JobTypeClient } from '../../../../types/job-type-client.type'
11 12
12@Injectable() 13@Injectable()
13export class JobService { 14export class JobService {
@@ -19,10 +20,12 @@ export class JobService {
19 private restExtractor: RestExtractor 20 private restExtractor: RestExtractor
20 ) {} 21 ) {}
21 22
22 getJobs (state: JobState, pagination: RestPagination, sort: SortMeta): Observable<ResultList<Job>> { 23 getJobs (state: JobState, jobType: JobTypeClient, pagination: RestPagination, sort: SortMeta): Observable<ResultList<Job>> {
23 let params = new HttpParams() 24 let params = new HttpParams()
24 params = this.restService.addRestGetParams(params, pagination, sort) 25 params = this.restService.addRestGetParams(params, pagination, sort)
25 26
27 if (jobType !== 'all') params = params.append('jobType', jobType)
28
26 return this.authHttp.get<ResultList<Job>>(JobService.BASE_JOB_URL + '/' + state, { params }) 29 return this.authHttp.get<ResultList<Job>>(JobService.BASE_JOB_URL + '/' + state, { params })
27 .pipe( 30 .pipe(
28 map(res => { 31 map(res => {
diff --git a/client/src/app/+admin/system/jobs/jobs.component.html b/client/src/app/+admin/system/jobs/jobs.component.html
index 7ed1888e2..cd26257dd 100644
--- a/client/src/app/+admin/system/jobs/jobs.component.html
+++ b/client/src/app/+admin/system/jobs/jobs.component.html
@@ -1,10 +1,22 @@
1<div class="admin-sub-header"> 1<div class="admin-sub-header">
2 <div i18n class="form-sub-title">Jobs list</div> 2 <div i18n class="form-sub-title">Jobs list</div>
3 3
4 <div class="peertube-select-container"> 4 <div class="select-filter-block">
5 <select [(ngModel)]="jobState" (ngModelChange)="onJobStateChanged()"> 5 <label for="jobType">Job type</label>
6 <option *ngFor="let state of jobStates" [value]="state">{{ state }}</option> 6 <div class="peertube-select-container">
7 </select> 7 <select id="jobType" name="jobType" [(ngModel)]="jobType" (ngModelChange)="onJobStateOrTypeChanged()">
8 <option *ngFor="let jobType of jobTypes" [value]="jobType">{{ jobType }}</option>
9 </select>
10 </div>
11 </div>
12
13 <div class="select-filter-block">
14 <label for="jobState">Job state</label>
15 <div class="peertube-select-container">
16 <select id="jobState" name="jobState" [(ngModel)]="jobState" (ngModelChange)="onJobStateOrTypeChanged()">
17 <option *ngFor="let state of jobStates" [value]="state">{{ state }}</option>
18 </select>
19 </div>
8 </div> 20 </div>
9</div> 21</div>
10 22
diff --git a/client/src/app/+admin/system/jobs/jobs.component.scss b/client/src/app/+admin/system/jobs/jobs.component.scss
index ab05f1982..ccc0b35ca 100644
--- a/client/src/app/+admin/system/jobs/jobs.component.scss
+++ b/client/src/app/+admin/system/jobs/jobs.component.scss
@@ -1,8 +1,22 @@
1@import '_variables'; 1@import '_variables';
2@import '_mixins'; 2@import '_mixins';
3 3
4.peertube-select-container { 4.admin-sub-header {
5 @include peertube-select-container(auto); 5 align-items: flex-end;
6
7 .select-filter-block {
8 &:not(:last-child) {
9 margin-right: 10px;
10 }
11
12 label {
13 margin-bottom: 2px;
14 }
15
16 .peertube-select-container {
17 @include peertube-select-container(auto);
18 }
19 }
6} 20}
7 21
8pre { 22pre {
diff --git a/client/src/app/+admin/system/jobs/jobs.component.ts b/client/src/app/+admin/system/jobs/jobs.component.ts
index b24353ca6..95ee17023 100644
--- a/client/src/app/+admin/system/jobs/jobs.component.ts
+++ b/client/src/app/+admin/system/jobs/jobs.component.ts
@@ -2,11 +2,12 @@ import { Component, OnInit } from '@angular/core'
2import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' 2import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
3import { Notifier } from '@app/core' 3import { Notifier } from '@app/core'
4import { SortMeta } from 'primeng/api' 4import { SortMeta } from 'primeng/api'
5import { Job } from '../../../../../../shared/index' 5import { Job, JobType } from '../../../../../../shared/index'
6import { JobState } from '../../../../../../shared/models' 6import { JobState } from '../../../../../../shared/models'
7import { RestPagination, RestTable } from '../../../shared' 7import { RestPagination, RestTable } from '../../../shared'
8import { JobService } from './job.service' 8import { JobService } from './job.service'
9import { I18n } from '@ngx-translate/i18n-polyfill' 9import { I18n } from '@ngx-translate/i18n-polyfill'
10import { JobTypeClient } from '../../../../types/job-type-client.type'
10 11
11@Component({ 12@Component({
12 selector: 'my-jobs', 13 selector: 'my-jobs',
@@ -15,9 +16,26 @@ import { I18n } from '@ngx-translate/i18n-polyfill'
15}) 16})
16export class JobsComponent extends RestTable implements OnInit { 17export class JobsComponent extends RestTable implements OnInit {
17 private static JOB_STATE_LOCAL_STORAGE_STATE = 'jobs-list-state' 18 private static JOB_STATE_LOCAL_STORAGE_STATE = 'jobs-list-state'
19 private static JOB_STATE_LOCAL_STORAGE_TYPE = 'jobs-list-type'
18 20
19 jobState: JobState = 'waiting' 21 jobState: JobState = 'waiting'
20 jobStates: JobState[] = [ 'active', 'completed', 'failed', 'waiting', 'delayed' ] 22 jobStates: JobState[] = [ 'active', 'completed', 'failed', 'waiting', 'delayed' ]
23
24 jobType: JobTypeClient = 'all'
25 jobTypes: JobTypeClient[] = [
26 'all',
27 'activitypub-follow',
28 'activitypub-http-broadcast',
29 'activitypub-http-fetcher',
30 'activitypub-http-unicast',
31 'email',
32 'video-transcoding',
33 'video-file-import',
34 'video-import',
35 'videos-views',
36 'activitypub-refresher'
37 ]
38
21 jobs: Job[] = [] 39 jobs: Job[] = []
22 totalRecords: number 40 totalRecords: number
23 rowsPerPage = 10 41 rowsPerPage = 10
@@ -33,20 +51,20 @@ export class JobsComponent extends RestTable implements OnInit {
33 } 51 }
34 52
35 ngOnInit () { 53 ngOnInit () {
36 this.loadJobState() 54 this.loadJobStateAndType()
37 this.initialize() 55 this.initialize()
38 } 56 }
39 57
40 onJobStateChanged () { 58 onJobStateOrTypeChanged () {
41 this.pagination.start = 0 59 this.pagination.start = 0
42 60
43 this.loadData() 61 this.loadData()
44 this.saveJobState() 62 this.saveJobStateAndType()
45 } 63 }
46 64
47 protected loadData () { 65 protected loadData () {
48 this.jobsService 66 this.jobsService
49 .getJobs(this.jobState, this.pagination, this.sort) 67 .getJobs(this.jobState, this.jobType, this.pagination, this.sort)
50 .subscribe( 68 .subscribe(
51 resultList => { 69 resultList => {
52 this.jobs = resultList.data 70 this.jobs = resultList.data
@@ -57,13 +75,16 @@ export class JobsComponent extends RestTable implements OnInit {
57 ) 75 )
58 } 76 }
59 77
60 private loadJobState () { 78 private loadJobStateAndType () {
61 const result = peertubeLocalStorage.getItem(JobsComponent.JOB_STATE_LOCAL_STORAGE_STATE) 79 const state = peertubeLocalStorage.getItem(JobsComponent.JOB_STATE_LOCAL_STORAGE_STATE)
80 if (state) this.jobState = state as JobState
62 81
63 if (result) this.jobState = result as JobState 82 const type = peertubeLocalStorage.getItem(JobsComponent.JOB_STATE_LOCAL_STORAGE_TYPE)
83 if (type) this.jobType = type as JobType
64 } 84 }
65 85
66 private saveJobState () { 86 private saveJobStateAndType () {
67 peertubeLocalStorage.setItem(JobsComponent.JOB_STATE_LOCAL_STORAGE_STATE, this.jobState) 87 peertubeLocalStorage.setItem(JobsComponent.JOB_STATE_LOCAL_STORAGE_STATE, this.jobState)
88 peertubeLocalStorage.setItem(JobsComponent.JOB_STATE_LOCAL_STORAGE_TYPE, this.jobType)
68 } 89 }
69} 90}
diff --git a/client/src/types/job-type-client.type.ts b/client/src/types/job-type-client.type.ts
new file mode 100644
index 000000000..7d51f1db2
--- /dev/null
+++ b/client/src/types/job-type-client.type.ts
@@ -0,0 +1,3 @@
1import { JobType } from '@shared/models'
2
3export type JobTypeClient = 'all' | JobType
diff --git a/server/controllers/api/jobs.ts b/server/controllers/api/jobs.ts
index 1fa662349..05320311e 100644
--- a/server/controllers/api/jobs.ts
+++ b/server/controllers/api/jobs.ts
@@ -24,7 +24,7 @@ jobsRouter.get('/:state',
24 jobsSortValidator, 24 jobsSortValidator,
25 setDefaultSort, 25 setDefaultSort,
26 setDefaultPagination, 26 setDefaultPagination,
27 asyncMiddleware(listJobsValidator), 27 listJobsValidator,
28 asyncMiddleware(listJobs) 28 asyncMiddleware(listJobs)
29) 29)
30 30
@@ -39,8 +39,15 @@ export {
39async function listJobs (req: express.Request, res: express.Response) { 39async function listJobs (req: express.Request, res: express.Response) {
40 const state = req.params.state as JobState 40 const state = req.params.state as JobState
41 const asc = req.query.sort === 'createdAt' 41 const asc = req.query.sort === 'createdAt'
42 const jobType = req.query.jobType
42 43
43 const jobs = await JobQueue.Instance.listForApi(state, req.query.start, req.query.count, asc) 44 const jobs = await JobQueue.Instance.listForApi({
45 state,
46 start: req.query.start,
47 count: req.query.count,
48 asc,
49 jobType
50 })
44 const total = await JobQueue.Instance.count(state) 51 const total = await JobQueue.Instance.count(state)
45 52
46 const result: ResultList<any> = { 53 const result: ResultList<any> = {
diff --git a/server/helpers/custom-validators/jobs.ts b/server/helpers/custom-validators/jobs.ts
index 1cc6e6912..dd33e85a3 100644
--- a/server/helpers/custom-validators/jobs.ts
+++ b/server/helpers/custom-validators/jobs.ts
@@ -1,14 +1,20 @@
1import { JobState } from '../../../shared/models' 1import { JobState } from '../../../shared/models'
2import { exists } from './misc' 2import { exists } from './misc'
3import { jobTypes } from '@server/lib/job-queue/job-queue'
3 4
4const jobStates: JobState[] = [ 'active', 'completed', 'failed', 'waiting', 'delayed' ] 5const jobStates: JobState[] = [ 'active', 'completed', 'failed', 'waiting', 'delayed' ]
5 6
6function isValidJobState (value: JobState) { 7function isValidJobState (value: JobState) {
7 return exists(value) && jobStates.indexOf(value) !== -1 8 return exists(value) && jobStates.includes(value)
9}
10
11function isValidJobType (value: any) {
12 return exists(value) && jobTypes.includes(value)
8} 13}
9 14
10// --------------------------------------------------------------------------- 15// ---------------------------------------------------------------------------
11 16
12export { 17export {
13 isValidJobState 18 isValidJobState,
19 isValidJobType
14} 20}
diff --git a/server/lib/job-queue/job-queue.ts b/server/lib/job-queue/job-queue.ts
index 3c810da98..ec601e9ea 100644
--- a/server/lib/job-queue/job-queue.ts
+++ b/server/lib/job-queue/job-queue.ts
@@ -121,11 +121,20 @@ class JobQueue {
121 return queue.add(obj.payload, jobArgs) 121 return queue.add(obj.payload, jobArgs)
122 } 122 }
123 123
124 async listForApi (state: JobState, start: number, count: number, asc?: boolean): Promise<Bull.Job[]> { 124 async listForApi (options: {
125 state: JobState,
126 start: number,
127 count: number,
128 asc?: boolean,
129 jobType: JobType
130 }): Promise<Bull.Job[]> {
131 const { state, start, count, asc, jobType } = options
125 let results: Bull.Job[] = [] 132 let results: Bull.Job[] = []
126 133
134 const filteredJobTypes = this.filterJobTypes(jobType)
135
127 // TODO: optimize 136 // TODO: optimize
128 for (const jobType of jobTypes) { 137 for (const jobType of filteredJobTypes) {
129 const queue = this.queues[ jobType ] 138 const queue = this.queues[ jobType ]
130 if (queue === undefined) { 139 if (queue === undefined) {
131 logger.error('Unknown queue %s to list jobs.', jobType) 140 logger.error('Unknown queue %s to list jobs.', jobType)
@@ -149,10 +158,12 @@ class JobQueue {
149 return results.slice(start, start + count) 158 return results.slice(start, start + count)
150 } 159 }
151 160
152 async count (state: JobState): Promise<number> { 161 async count (state: JobState, jobType?: JobType): Promise<number> {
153 let total = 0 162 let total = 0
154 163
155 for (const type of jobTypes) { 164 const filteredJobTypes = this.filterJobTypes(jobType)
165
166 for (const type of filteredJobTypes) {
156 const queue = this.queues[ type ] 167 const queue = this.queues[ type ]
157 if (queue === undefined) { 168 if (queue === undefined) {
158 logger.error('Unknown queue %s to count jobs.', type) 169 logger.error('Unknown queue %s to count jobs.', type)
@@ -180,6 +191,12 @@ class JobQueue {
180 }) 191 })
181 } 192 }
182 193
194 private filterJobTypes (jobType?: JobType) {
195 if (!jobType) return jobTypes
196
197 return jobTypes.filter(t => t === jobType)
198 }
199
183 static get Instance () { 200 static get Instance () {
184 return this.instance || (this.instance = new this()) 201 return this.instance || (this.instance = new this())
185 } 202 }
@@ -188,5 +205,6 @@ class JobQueue {
188// --------------------------------------------------------------------------- 205// ---------------------------------------------------------------------------
189 206
190export { 207export {
208 jobTypes,
191 JobQueue 209 JobQueue
192} 210}
diff --git a/server/middlewares/validators/jobs.ts b/server/middlewares/validators/jobs.ts
index 41a8d6899..b57615dbc 100644
--- a/server/middlewares/validators/jobs.ts
+++ b/server/middlewares/validators/jobs.ts
@@ -1,13 +1,17 @@
1import * as express from 'express' 1import * as express from 'express'
2import { param } from 'express-validator' 2import { param, query } from 'express-validator'
3import { isValidJobState } from '../../helpers/custom-validators/jobs' 3import { isValidJobState, isValidJobType } from '../../helpers/custom-validators/jobs'
4import { logger } from '../../helpers/logger' 4import { logger } from '../../helpers/logger'
5import { areValidationErrors } from './utils' 5import { areValidationErrors } from './utils'
6 6
7const listJobsValidator = [ 7const listJobsValidator = [
8 param('state').custom(isValidJobState).not().isEmpty().withMessage('Should have a valid job state'), 8 param('state')
9 .custom(isValidJobState).not().isEmpty().withMessage('Should have a valid job state'),
10 query('jobType')
11 .optional()
12 .custom(isValidJobType).withMessage('Should have a valid job state'),
9 13
10 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 14 (req: express.Request, res: express.Response, next: express.NextFunction) => {
11 logger.debug('Checking listJobsValidator parameters.', { parameters: req.params }) 15 logger.debug('Checking listJobsValidator parameters.', { parameters: req.params })
12 16
13 if (areValidationErrors(req, res)) return 17 if (areValidationErrors(req, res)) return
diff --git a/server/tests/api/check-params/jobs.ts b/server/tests/api/check-params/jobs.ts
index c70139514..22e237964 100644
--- a/server/tests/api/check-params/jobs.ts
+++ b/server/tests/api/check-params/jobs.ts
@@ -51,6 +51,17 @@ describe('Test jobs API validators', function () {
51 }) 51 })
52 }) 52 })
53 53
54 it('Should fail with an incorrect job type', async function () {
55 await makeGetRequest({
56 url: server.url,
57 token: server.accessToken,
58 path,
59 query: {
60 jobType: 'toto'
61 }
62 })
63 })
64
54 it('Should fail with a bad start pagination', async function () { 65 it('Should fail with a bad start pagination', async function () {
55 await checkBadStartPagination(server.url, path, server.accessToken) 66 await checkBadStartPagination(server.url, path, server.accessToken)
56 }) 67 })
@@ -79,6 +90,7 @@ describe('Test jobs API validators', function () {
79 statusCodeExpected: 403 90 statusCodeExpected: 403
80 }) 91 })
81 }) 92 })
93
82 }) 94 })
83 95
84 after(async function () { 96 after(async function () {
diff --git a/server/tests/api/server/handle-down.ts b/server/tests/api/server/handle-down.ts
index a0f505474..7e36067f1 100644
--- a/server/tests/api/server/handle-down.ts
+++ b/server/tests/api/server/handle-down.ts
@@ -184,7 +184,14 @@ describe('Test handle downs', function () {
184 const states: JobState[] = [ 'waiting', 'active' ] 184 const states: JobState[] = [ 'waiting', 'active' ]
185 185
186 for (const state of states) { 186 for (const state of states) {
187 const res = await getJobsListPaginationAndSort(servers[ 0 ].url, servers[ 0 ].accessToken, state,0, 50, '-createdAt') 187 const res = await getJobsListPaginationAndSort({
188 url: servers[ 0 ].url,
189 accessToken: servers[ 0 ].accessToken,
190 state: state,
191 start: 0,
192 count: 50,
193 sort: '-createdAt'
194 })
188 expect(res.body.data).to.have.length(0) 195 expect(res.body.data).to.have.length(0)
189 } 196 }
190 }) 197 })
diff --git a/server/tests/api/server/jobs.ts b/server/tests/api/server/jobs.ts
index ceea47a85..58d8c8c10 100644
--- a/server/tests/api/server/jobs.ts
+++ b/server/tests/api/server/jobs.ts
@@ -41,20 +41,46 @@ describe('Test jobs', function () {
41 expect(res.body.data).to.have.length.above(2) 41 expect(res.body.data).to.have.length.above(2)
42 }) 42 })
43 43
44 it('Should list jobs with sort and pagination', async function () { 44 it('Should list jobs with sort, pagination and job type', async function () {
45 const res = await getJobsListPaginationAndSort(servers[1].url, servers[1].accessToken, 'completed', 1, 2, 'createdAt') 45 {
46 expect(res.body.total).to.be.above(2) 46 const res = await getJobsListPaginationAndSort({
47 expect(res.body.data).to.have.lengthOf(2) 47 url: servers[ 1 ].url,
48 accessToken: servers[ 1 ].accessToken,
49 state: 'completed',
50 start: 1,
51 count: 2,
52 sort: 'createdAt'
53 })
54 expect(res.body.total).to.be.above(2)
55 expect(res.body.data).to.have.lengthOf(2)
56
57 let job: Job = res.body.data[ 0 ]
58 // Skip repeat jobs
59 if (job.type === 'videos-views') job = res.body.data[ 1 ]
60
61 expect(job.state).to.equal('completed')
62 expect(job.type.startsWith('activitypub-')).to.be.true
63 expect(dateIsValid(job.createdAt as string)).to.be.true
64 expect(dateIsValid(job.processedOn as string)).to.be.true
65 expect(dateIsValid(job.finishedOn as string)).to.be.true
66 }
48 67
49 let job = res.body.data[0] 68 {
50 // Skip repeat jobs 69 const res = await getJobsListPaginationAndSort({
51 if (job.type === 'videos-views') job = res.body.data[1] 70 url: servers[ 1 ].url,
71 accessToken: servers[ 1 ].accessToken,
72 state: 'completed',
73 start: 0,
74 count: 100,
75 sort: 'createdAt',
76 jobType: 'activitypub-http-broadcast'
77 })
78 expect(res.body.total).to.be.above(2)
52 79
53 expect(job.state).to.equal('completed') 80 for (const j of res.body.data as Job[]) {
54 expect(job.type.startsWith('activitypub-')).to.be.true 81 expect(j.type).to.equal('activitypub-http-broadcast')
55 expect(dateIsValid(job.createdAt)).to.be.true 82 }
56 expect(dateIsValid(job.processedOn)).to.be.true 83 }
57 expect(dateIsValid(job.finishedOn)).to.be.true
58 }) 84 })
59 85
60 after(async function () { 86 after(async function () {
diff --git a/server/tests/real-world/real-world.ts b/server/tests/real-world/real-world.ts
index 8b070004d..cba5ac311 100644
--- a/server/tests/real-world/real-world.ts
+++ b/server/tests/real-world/real-world.ts
@@ -354,7 +354,14 @@ async function isTherePendingRequests (servers: ServerInfo[]) {
354 // Check if each server has pending request 354 // Check if each server has pending request
355 for (const server of servers) { 355 for (const server of servers) {
356 for (const state of states) { 356 for (const state of states) {
357 const p = getJobsListPaginationAndSort(server.url, server.accessToken, state, 0, 10, '-createdAt') 357 const p = getJobsListPaginationAndSort({
358 url: server.url,
359 accessToken: server.accessToken,
360 state: state,
361 start: 0,
362 count: 10,
363 sort: '-createdAt'
364 })
358 .then(res => { 365 .then(res => {
359 if (res.body.total > 0) pendingRequests = true 366 if (res.body.total > 0) pendingRequests = true
360 }) 367 })
diff --git a/shared/extra-utils/server/jobs.ts b/shared/extra-utils/server/jobs.ts
index b3db885e8..cc1352e14 100644
--- a/shared/extra-utils/server/jobs.ts
+++ b/shared/extra-utils/server/jobs.ts
@@ -1,7 +1,8 @@
1import * as request from 'supertest' 1import * as request from 'supertest'
2import { Job, JobState } from '../../models' 2import { Job, JobState, JobType } from '../../models'
3import { wait } from '../miscs/miscs' 3import { wait } from '../miscs/miscs'
4import { ServerInfo } from './servers' 4import { ServerInfo } from './servers'
5import { makeGetRequest } from '@shared/extra-utils'
5 6
6function getJobsList (url: string, accessToken: string, state: JobState) { 7function getJobsList (url: string, accessToken: string, state: JobState) {
7 const path = '/api/v1/jobs/' + state 8 const path = '/api/v1/jobs/' + state
@@ -14,18 +15,32 @@ function getJobsList (url: string, accessToken: string, state: JobState) {
14 .expect('Content-Type', /json/) 15 .expect('Content-Type', /json/)
15} 16}
16 17
17function getJobsListPaginationAndSort (url: string, accessToken: string, state: JobState, start: number, count: number, sort: string) { 18function getJobsListPaginationAndSort (options: {
19 url: string,
20 accessToken: string,
21 state: JobState,
22 start: number,
23 count: number,
24 sort: string,
25 jobType?: JobType
26}) {
27 const { url, accessToken, state, start, count, sort, jobType } = options
18 const path = '/api/v1/jobs/' + state 28 const path = '/api/v1/jobs/' + state
19 29
20 return request(url) 30 const query = {
21 .get(path) 31 start,
22 .query({ start }) 32 count,
23 .query({ count }) 33 sort,
24 .query({ sort }) 34 jobType
25 .set('Accept', 'application/json') 35 }
26 .set('Authorization', 'Bearer ' + accessToken) 36
27 .expect(200) 37 return makeGetRequest({
28 .expect('Content-Type', /json/) 38 url,
39 path,
40 token: accessToken,
41 statusCodeExpected: 200,
42 query
43 })
29} 44}
30 45
31async function waitJobs (serversArg: ServerInfo[] | ServerInfo) { 46async function waitJobs (serversArg: ServerInfo[] | ServerInfo) {
@@ -44,7 +59,14 @@ async function waitJobs (serversArg: ServerInfo[] | ServerInfo) {
44 // Check if each server has pending request 59 // Check if each server has pending request
45 for (const server of servers) { 60 for (const server of servers) {
46 for (const state of states) { 61 for (const state of states) {
47 const p = getJobsListPaginationAndSort(server.url, server.accessToken, state, 0, 10, '-createdAt') 62 const p = getJobsListPaginationAndSort({
63 url: server.url,
64 accessToken: server.accessToken,
65 state: state,
66 start: 0,
67 count: 10,
68 sort: '-createdAt'
69 })
48 .then(res => res.body.data) 70 .then(res => res.body.data)
49 .then((jobs: Job[]) => jobs.filter(j => j.type !== 'videos-views')) 71 .then((jobs: Job[]) => jobs.filter(j => j.type !== 'videos-views'))
50 .then(jobs => { 72 .then(jobs => {
diff --git a/shared/models/server/job.model.ts b/shared/models/server/job.model.ts
index 1b9aa8a07..b82a633b2 100644
--- a/shared/models/server/job.model.ts
+++ b/shared/models/server/job.model.ts
@@ -17,7 +17,7 @@ export interface Job {
17 type: JobType 17 type: JobType
18 data: any, 18 data: any,
19 error: any, 19 error: any,
20 createdAt: Date 20 createdAt: Date | string
21 finishedOn: Date 21 finishedOn: Date | string
22 processedOn: Date 22 processedOn: Date | string
23} 23}