@@ -4,9 +4,11 @@ import { stub } from 'sinon';
44import request from 'supertest' ;
55import { v4 as uuid } from 'uuid' ;
66
7+ import { formatDataSize , sizeChangeMessage } from '../../app/frontends/jobs' ;
78import { EXPIRATION_DAYS , Job , JobStatus } from '../../app/models/job' ;
89import JobMessage , { JobMessageLevel } from '../../app/models/job-message' ;
910import { setLabelsForJob } from '../../app/models/label' ;
11+ import { WorkItemStatus } from '../../app/models/work-item-interface' ;
1012import env from '../../app/util/env' ;
1113import { hookDatabaseFailure , hookTransaction } from '../helpers/db' ;
1214import { hookRedirect , hookUrl } from '../helpers/hooks' ;
@@ -19,6 +21,8 @@ import {
1921import { hookRangesetRequest } from '../helpers/ogc-api-coverages' ;
2022import hookServersStartStop from '../helpers/servers' ;
2123import StubService from '../helpers/stub-service' ;
24+ import { buildWorkItem } from '../helpers/work-items' ;
25+ import { buildWorkflowStep } from '../helpers/workflow-steps' ;
2226
2327const aJob = buildJob ( { username : 'joe' } ) ;
2428const pausedJob = buildJob ( { username : 'joe' } ) ;
@@ -32,6 +36,7 @@ const warningMessage = new JobMessage({
3236 message_category : 'nodata' ,
3337} ) ;
3438const warningJob = buildJob ( { username : 'joe' , status : JobStatus . SUCCESSFUL , message : 'Service could not get data' , messages : [ warningMessage ] } ) ;
39+ const successfulJob = buildJob ( { username : 'joe' , status : JobStatus . SUCCESSFUL , message : 'Success' } ) ;
3540
3641const timeStampRegex = / \d { 4 } - \d { 2 } - \d { 2 } T \d { 2 } : \d { 2 } : \d { 2 } \. \d { 3 } Z / ;
3742
@@ -74,16 +79,39 @@ describe('Individual job status route', function () {
7479 hookTransaction ( ) ;
7580 before ( async function ( ) {
7681 await aJob . save ( this . trx ) ;
82+ console . log ( `JOB ID: ${ aJob . jobID } ` ) ;
7783 await setLabelsForJob ( this . trx , aJob . jobID , aJob . username , aJobLabels ) ;
7884 await pausedJob . save ( this . trx ) ;
7985 await previewingJob . save ( this . trx ) ;
8086 await warningJob . save ( this . trx ) ;
87+ await successfulJob . save ( this . trx ) ;
88+ const initialSuccessJobWorkflowStep = buildWorkflowStep ( { jobID : successfulJob . jobID , stepIndex : 1 } ) ;
89+ await initialSuccessJobWorkflowStep . save ( this . trx ) ;
90+ const finalSuccessJobWorkflowStep = buildWorkflowStep ( { jobID : successfulJob . jobID , stepIndex : 2 } ) ;
91+ await finalSuccessJobWorkflowStep . save ( this . trx ) ;
92+ const initialWarningJobWorkflowStep = buildWorkflowStep ( { jobID : warningJob . jobID , stepIndex : 1 } ) ;
93+ await initialWarningJobWorkflowStep . save ( this . trx ) ;
94+ const finalWarningJobWorkflowStep = buildWorkflowStep ( { jobID : warningJob . jobID , stepIndex : 2 } ) ;
95+ await finalWarningJobWorkflowStep . save ( this . trx ) ;
96+ const initialSuccessJobWorkItem1 = buildWorkItem ( { jobID : successfulJob . jobID , workflowStepIndex : 1 , status : WorkItemStatus . SUCCESSFUL , totalItemsSize : 1.3701868057250977 } ) ;
97+ await initialSuccessJobWorkItem1 . save ( this . trx ) ;
98+ const finalSuccessJobWorkItem1 = buildWorkItem ( { jobID : successfulJob . jobID , workflowStepIndex : 2 , status : WorkItemStatus . WARNING , totalItemsSize : 0.09036064147949219 } ) ;
99+ await finalSuccessJobWorkItem1 . save ( this . trx ) ;
100+ const initialSuccessJobWorkItem2 = buildWorkItem ( { jobID : successfulJob . jobID , workflowStepIndex : 1 , status : WorkItemStatus . SUCCESSFUL , totalItemsSize : 1.7018680517250977 } ) ;
101+ await initialSuccessJobWorkItem2 . save ( this . trx ) ;
102+ const finalSuccessJobWorkItem2 = buildWorkItem ( { jobID : successfulJob . jobID , workflowStepIndex : 2 , status : WorkItemStatus . WARNING , totalItemsSize : 0.09361064147949219 } ) ;
103+ await finalSuccessJobWorkItem2 . save ( this . trx ) ;
104+ const initialWarningJobWorkItem = buildWorkItem ( { jobID : warningJob . jobID , workflowStepIndex : 1 , status : WorkItemStatus . SUCCESSFUL , totalItemsSize : 1.3701868057250977 } ) ;
105+ await initialWarningJobWorkItem . save ( this . trx ) ;
106+ const finalWarningJobWorkItem = buildWorkItem ( { jobID : warningJob . jobID , workflowStepIndex : 2 , status : WorkItemStatus . WARNING , totalItemsSize : 0.09036064147949219 } ) ;
107+ await finalWarningJobWorkItem . save ( this . trx ) ;
81108 this . trx . commit ( ) ;
82109 } ) ;
83110 const jobID = aJob . requestId ;
84111 const pausedjobID = pausedJob . requestId ;
85112 const previewingJobID = previewingJob . requestId ;
86113 const warningJobID = warningJob . requestId ;
114+ const successJobID = successfulJob . requestId ;
87115
88116 describe ( 'For a user who is not logged in' , function ( ) {
89117 before ( async function ( ) {
@@ -150,6 +178,13 @@ describe('Individual job status route', function () {
150178 expect ( job . labels ) . deep . equal ( [ '000' , 'bar' , 'foo' , 'z-label' ] ) ;
151179 } ) ;
152180
181+ it ( 'does not include data size reduction information' , function ( ) {
182+ const job = JSON . parse ( this . res . text ) ;
183+ expect ( job . originalDataSize ) . to . be . undefined ;
184+ expect ( job . outputDataSize ) . to . be . undefined ;
185+ expect ( job . dataSizePercentChange ) . to . be . undefined ;
186+ } ) ;
187+
153188 itIncludesADataExpirationField ( ) ;
154189 } ) ;
155190 }
@@ -173,6 +208,13 @@ describe('Individual job status route', function () {
173208 expect ( resumeLinks . length ) . to . equal ( 0 ) ;
174209 } ) ;
175210
211+ it ( 'does not include data size reduction information' , function ( ) {
212+ const job = JSON . parse ( this . res . text ) ;
213+ expect ( job . originalDataSize ) . to . be . undefined ;
214+ expect ( job . outputDataSize ) . to . be . undefined ;
215+ expect ( job . dataSizePercentChange ) . to . be . undefined ;
216+ } ) ;
217+
176218 itIncludesADataExpirationField ( ) ;
177219 } ) ;
178220
@@ -205,6 +247,52 @@ describe('Individual job status route', function () {
205247 expect ( previewSkipLinks . length ) . to . equal ( 0 ) ;
206248 } ) ;
207249
250+ it ( 'does not include data size reduction information' , function ( ) {
251+ const job = JSON . parse ( this . res . text ) ;
252+ expect ( job . originalDataSize ) . to . be . undefined ;
253+ expect ( job . outputDataSize ) . to . be . undefined ;
254+ expect ( job . dataSizePercentChange ) . to . be . undefined ;
255+ } ) ;
256+
257+ itIncludesADataExpirationField ( ) ;
258+ } ) ;
259+
260+ describe ( 'when the job is successful' , function ( ) {
261+ hookJobStatus ( { jobID : successJobID , username : 'joe' } ) ;
262+
263+ it ( 'returns a status field of "successful"' , function ( ) {
264+ const job = JSON . parse ( this . res . text ) ;
265+ expect ( job . status ) . to . eql ( 'successful' ) ;
266+ } ) ;
267+
268+ it ( 'returns a human-readable message field corresponding to its state' , function ( ) {
269+ const job = JSON . parse ( this . res . text ) ;
270+ expect ( job . message ) . to . include ( 'Success' ) ;
271+ } ) ;
272+
273+ it ( 'does not include links for canceling and resuming the job' , function ( ) {
274+ const job = new Job ( JSON . parse ( this . res . text ) ) ;
275+ const resumeLinks = job . getRelatedLinks ( 'resumer' ) ;
276+ expect ( resumeLinks . length ) . to . equal ( 0 ) ;
277+ const cancelLinks = job . getRelatedLinks ( 'canceler' ) ;
278+ expect ( cancelLinks . length ) . to . equal ( 0 ) ;
279+ } ) ;
280+
281+ it ( 'does not include irrelevant state change links' , function ( ) {
282+ const job = new Job ( JSON . parse ( this . res . text ) ) ;
283+ const pauseLinks = job . getRelatedLinks ( 'pauser' ) ;
284+ expect ( pauseLinks . length ) . to . equal ( 0 ) ;
285+ const previewSkipLinks = job . getRelatedLinks ( 'preview-skipper' ) ;
286+ expect ( previewSkipLinks . length ) . to . equal ( 0 ) ;
287+ } ) ;
288+
289+ it ( 'includes data size reduction information' , function ( ) {
290+ const job = JSON . parse ( this . res . text ) ;
291+ expect ( job . originalDataSize ) . to . eql ( '3.07 MiB' ) ;
292+ expect ( job . outputDataSize ) . to . eql ( '188.39 KiB' ) ;
293+ expect ( job . dataSizePercentChange ) . to . eql ( '94.01% reduction' ) ;
294+ } ) ;
295+
208296 itIncludesADataExpirationField ( ) ;
209297 } ) ;
210298
@@ -245,6 +333,13 @@ describe('Individual job status route', function () {
245333 expect ( warnings [ 0 ] . message ) . to . eql ( warningMessage . message ) ;
246334 } ) ;
247335
336+ it ( 'includes data size reduction information' , function ( ) {
337+ const job = JSON . parse ( this . res . text ) ;
338+ expect ( job . originalDataSize ) . to . eql ( '1.37 MiB' ) ;
339+ expect ( job . outputDataSize ) . to . eql ( '92.53 KiB' ) ;
340+ expect ( job . dataSizePercentChange ) . to . eql ( '93.41% reduction' ) ;
341+ } ) ;
342+
248343 itIncludesADataExpirationField ( ) ;
249344 } ) ;
250345
@@ -968,3 +1063,44 @@ describe('Individual job status route', function () {
9681063 } ) ;
9691064 } ) ;
9701065} ) ;
1066+
1067+ describe ( 'unit tests for size reduction calcuation functions' , function ( ) {
1068+ // loop over some test cases for formatDataSize and sizeChangeMessage
1069+ const testCases = [
1070+ [ 1.3701868057250977 , 0.09036064147949219 , '1.37 MiB' , '92.53 KiB' , '93.41% reduction' ] ,
1071+ [ 100.29018617250945 , 10.0149421 , '100.29 MiB' , '10.01 MiB' , '90.01% reduction' ] ,
1072+ [ 1234567890 , 9876543 , '1.15 PiB' , '9.42 TiB' , '99.20% reduction' ] ,
1073+ [ 10241024 , 10024.5 , '9.77 TiB' , '9.79 GiB' , '99.90% reduction' ] ,
1074+ [ 1024 , 10024 , '1.00 GiB' , '9.79 GiB' , '878.91% increase' ] ,
1075+ ] ;
1076+
1077+ for ( const testCase of testCases ) {
1078+ const originalSize = + testCase [ 0 ] ;
1079+ const outputSize = + testCase [ 1 ] ;
1080+ it ( 'formats MiB as a human readable string' , function ( ) {
1081+ expect ( formatDataSize ( originalSize ) ) . to . eql ( testCase [ 2 ] ) ;
1082+ expect ( formatDataSize ( outputSize ) ) . to . eql ( testCase [ 3 ] ) ;
1083+ } ) ;
1084+ it ( 'provides a human-readable message about the size change of the data' , function ( ) {
1085+ expect ( sizeChangeMessage ( { originalSize, outputSize } ) ) . to . eql ( testCase [ 4 ] ) ;
1086+ } ) ;
1087+ }
1088+
1089+ describe ( 'when the size reduction is very large' , function ( ) {
1090+ it ( 'does not claim 100% size reduction' , function ( ) {
1091+ expect ( sizeChangeMessage ( { originalSize : 1234567890 , outputSize : 1 } ) ) . to . eql ( '99.99% reduction' ) ;
1092+ } ) ;
1093+ } ) ;
1094+
1095+ describe ( 'when the original size is zero' , function ( ) {
1096+ it ( 'warns that the percent change does not apply' , function ( ) {
1097+ expect ( sizeChangeMessage ( { originalSize : 0 , outputSize : 0 } ) ) . to . eql ( 'Original size is 0 - percent size change N/A' ) ;
1098+ } ) ;
1099+ } ) ;
1100+
1101+ describe ( 'when the output size is zero' , function ( ) {
1102+ it ( 'warns that the percent change does not apply' , function ( ) {
1103+ expect ( sizeChangeMessage ( { originalSize : 100 , outputSize : 0 } ) ) . to . eql ( 'Output size is 0 - percent size change N/A' ) ;
1104+ } ) ;
1105+ } ) ;
1106+ } ) ;
0 commit comments