2018-05-25 16:13:18 +00:00
import EmberObject from '@ember/object' ;
2018-07-05 20:49:27 +00:00
import { getOwner } from '@ember/application' ;
2018-02-17 02:59:40 +00:00
import { run } from '@ember/runloop' ;
import { assign } from '@ember/polyfills' ;
2018-02-20 20:05:34 +00:00
import { test } from 'ember-qunit' ;
2018-02-17 02:59:40 +00:00
import wait from 'ember-test-helpers/wait' ;
2017-09-19 14:47:10 +00:00
import { startMirage } from 'nomad-ui/initializers/ember-cli-mirage' ;
2018-02-20 20:05:34 +00:00
import moduleForAdapter from '../../helpers/module-for-adapter' ;
2017-09-19 14:47:10 +00:00
2018-02-20 20:05:34 +00:00
moduleForAdapter ( 'job' , 'Unit | Adapter | Job' , {
2018-02-16 02:55:59 +00:00
needs : [
2018-07-05 20:49:27 +00:00
'adapter:application' ,
2018-02-20 20:05:34 +00:00
'adapter:job' ,
2018-07-05 20:49:27 +00:00
'adapter:namespace' ,
'model:task-group' ,
2018-05-25 16:13:18 +00:00
'model:allocation' ,
'model:deployment' ,
'model:evaluation' ,
2018-03-01 00:34:27 +00:00
'model:job-summary' ,
2018-05-25 16:13:18 +00:00
'model:job-version' ,
'model:namespace' ,
2018-07-05 20:49:27 +00:00
'model:task-group-summary' ,
'serializer:namespace' ,
'serializer:job' ,
'serializer:job-summary' ,
'service:token' ,
'service:system' ,
2018-02-16 02:55:59 +00:00
'service:watchList' ,
2018-07-05 20:49:27 +00:00
'transform:fragment' ,
'transform:fragment-array' ,
2018-02-16 02:55:59 +00:00
] ,
2017-09-19 14:47:10 +00:00
beforeEach ( ) {
window . sessionStorage . clear ( ) ;
2018-07-05 19:29:29 +00:00
window . localStorage . clear ( ) ;
2017-09-19 14:47:10 +00:00
this . server = startMirage ( ) ;
2018-07-05 20:49:27 +00:00
this . server . create ( 'namespace' ) ;
this . server . create ( 'namespace' , { id : 'some-namespace' } ) ;
2017-09-19 14:47:10 +00:00
this . server . create ( 'node' ) ;
2018-07-05 20:49:27 +00:00
this . server . create ( 'job' , { id : 'job-1' , namespaceId : 'default' } ) ;
2017-10-23 17:22:58 +00:00
this . server . create ( 'job' , { id : 'job-2' , namespaceId : 'some-namespace' } ) ;
2018-07-05 20:49:27 +00:00
this . system = getOwner ( this ) . lookup ( 'service:system' ) ;
2018-08-09 22:35:25 +00:00
// Namespace, default region, and all regions are requests that all
// job requests depend on. Fetching them ahead of time means testing
// job adapter behavior in isolation.
2018-07-05 20:49:27 +00:00
this . system . get ( 'namespaces' ) ;
2018-08-09 22:35:25 +00:00
this . system . get ( 'shouldIncludeRegion' ) ;
this . system . get ( 'defaultRegion' ) ;
2018-07-05 20:49:27 +00:00
// Reset the handledRequests array to avoid accounting for this
// namespaces request everywhere.
this . server . pretender . handledRequests . length = 0 ;
2017-09-19 14:47:10 +00:00
} ,
afterEach ( ) {
this . server . shutdown ( ) ;
} ,
} ) ;
2018-07-05 19:29:29 +00:00
test ( 'The job endpoint is the only required endpoint for fetching a job' , function ( assert ) {
2017-09-19 14:47:10 +00:00
const { pretender } = this . server ;
2017-10-23 17:22:58 +00:00
const jobName = 'job-1' ;
const jobNamespace = 'default' ;
const jobId = JSON . stringify ( [ jobName , jobNamespace ] ) ;
2017-09-19 14:47:10 +00:00
2018-08-07 01:33:57 +00:00
return wait ( ) . then ( ( ) => {
this . subject ( ) . findRecord ( null , { modelName : 'job' } , jobId ) ;
2017-09-19 14:47:10 +00:00
2018-08-07 01:33:57 +00:00
assert . deepEqual (
pretender . handledRequests . mapBy ( 'url' ) ,
[ ` /v1/job/ ${ jobName } ` ] ,
'The only request made is /job/:id'
) ;
} ) ;
2018-07-05 19:29:29 +00:00
} ) ;
2018-07-05 20:49:27 +00:00
test ( 'When a namespace is set in localStorage but a job in the default namespace is requested, the namespace query param is not present' , function ( assert ) {
window . localStorage . nomadActiveNamespace = 'some-namespace' ;
const { pretender } = this . server ;
const jobName = 'job-1' ;
const jobNamespace = 'default' ;
const jobId = JSON . stringify ( [ jobName , jobNamespace ] ) ;
this . system . get ( 'namespaces' ) ;
return wait ( ) . then ( ( ) => {
this . subject ( ) . findRecord ( null , { modelName : 'job' } , jobId ) ;
assert . deepEqual (
pretender . handledRequests . mapBy ( 'url' ) ,
2018-08-09 22:35:25 +00:00
[ ` /v1/job/ ${ jobName } ` ] ,
'The only request made is /job/:id with no namespace query param'
2018-07-05 20:49:27 +00:00
) ;
} ) ;
} ) ;
2018-07-05 19:29:29 +00:00
test ( 'When a namespace is in localStorage and the requested job is in the default namespace, the namespace query param is left out' , function ( assert ) {
window . localStorage . nomadActiveNamespace = 'red-herring' ;
const { pretender } = this . server ;
const jobName = 'job-1' ;
const jobNamespace = 'default' ;
const jobId = JSON . stringify ( [ jobName , jobNamespace ] ) ;
2018-08-07 01:33:57 +00:00
return wait ( ) . then ( ( ) => {
this . subject ( ) . findRecord ( null , { modelName : 'job' } , jobId ) ;
2018-07-05 19:29:29 +00:00
2018-08-07 01:33:57 +00:00
assert . deepEqual (
pretender . handledRequests . mapBy ( 'url' ) ,
[ ` /v1/job/ ${ jobName } ` ] ,
'The request made is /job/:id with no namespace query param'
) ;
} ) ;
2017-09-19 14:47:10 +00:00
} ) ;
2017-10-23 17:22:58 +00:00
test ( 'When the job has a namespace other than default, it is in the URL' , function ( assert ) {
const { pretender } = this . server ;
const jobName = 'job-2' ;
const jobNamespace = 'some-namespace' ;
const jobId = JSON . stringify ( [ jobName , jobNamespace ] ) ;
2018-08-07 01:33:57 +00:00
return wait ( ) . then ( ( ) => {
this . subject ( ) . findRecord ( null , { modelName : 'job' } , jobId ) ;
2017-10-23 17:22:58 +00:00
2018-08-07 01:33:57 +00:00
assert . deepEqual (
pretender . handledRequests . mapBy ( 'url' ) ,
[ ` /v1/job/ ${ jobName } ?namespace= ${ jobNamespace } ` ] ,
'The only request made is /job/:id?namespace=:namespace'
) ;
} ) ;
2017-10-23 17:22:58 +00:00
} ) ;
2018-02-16 02:55:59 +00:00
test ( 'When there is no token set in the token service, no x-nomad-token header is set' , function ( assert ) {
2017-09-19 14:47:10 +00:00
const { pretender } = this . server ;
2017-10-23 17:22:58 +00:00
const jobId = JSON . stringify ( [ 'job-1' , 'default' ] ) ;
2017-09-19 14:47:10 +00:00
2018-08-07 01:33:57 +00:00
return wait ( ) . then ( ( ) => {
this . subject ( ) . findRecord ( null , { modelName : 'job' } , jobId ) ;
2017-09-19 14:47:10 +00:00
2018-08-07 01:33:57 +00:00
assert . notOk (
pretender . handledRequests . mapBy ( 'requestHeaders' ) . some ( headers => headers [ 'X-Nomad-Token' ] ) ,
'No token header present on either job request'
) ;
} ) ;
2017-09-19 14:47:10 +00:00
} ) ;
2018-02-16 02:55:59 +00:00
test ( 'When a token is set in the token service, then x-nomad-token header is set' , function ( assert ) {
2017-09-19 14:47:10 +00:00
const { pretender } = this . server ;
2017-10-23 17:22:58 +00:00
const jobId = JSON . stringify ( [ 'job-1' , 'default' ] ) ;
2017-09-19 14:47:10 +00:00
const secret = 'here is the secret' ;
2018-08-07 01:33:57 +00:00
return wait ( ) . then ( ( ) => {
this . subject ( ) . set ( 'token.secret' , secret ) ;
this . subject ( ) . findRecord ( null , { modelName : 'job' } , jobId ) ;
2017-09-19 14:47:10 +00:00
2018-08-07 01:33:57 +00:00
assert . ok (
pretender . handledRequests
. mapBy ( 'requestHeaders' )
. every ( headers => headers [ 'X-Nomad-Token' ] === secret ) ,
'The token header is present on both job requests'
) ;
} ) ;
2017-09-19 14:47:10 +00:00
} ) ;
2018-02-17 02:59:40 +00:00
test ( 'findAll can be watched' , function ( assert ) {
const { pretender } = this . server ;
const request = ( ) =>
this . subject ( ) . findAll ( null , { modelName : 'job' } , null , {
reload : true ,
adapterOptions : { watch : true } ,
} ) ;
request ( ) ;
assert . equal (
2018-08-09 22:35:25 +00:00
pretender . handledRequests [ 0 ] . url ,
2018-03-21 20:28:56 +00:00
'/v1/jobs?index=1' ,
2018-02-17 02:59:40 +00:00
'Second request is a blocking request for jobs'
) ;
return wait ( ) . then ( ( ) => {
request ( ) ;
assert . equal (
2018-08-09 22:35:25 +00:00
pretender . handledRequests [ 1 ] . url ,
2018-03-21 20:28:56 +00:00
'/v1/jobs?index=2' ,
2018-02-17 02:59:40 +00:00
'Third request is a blocking request with an incremented index param'
) ;
return wait ( ) ;
} ) ;
} ) ;
test ( 'findRecord can be watched' , function ( assert ) {
const jobId = JSON . stringify ( [ 'job-1' , 'default' ] ) ;
const { pretender } = this . server ;
const request = ( ) =>
this . subject ( ) . findRecord ( null , { modelName : 'job' } , jobId , {
reload : true ,
adapterOptions : { watch : true } ,
} ) ;
request ( ) ;
assert . equal (
pretender . handledRequests [ 0 ] . url ,
2018-03-21 20:28:56 +00:00
'/v1/job/job-1?index=1' ,
2018-02-17 02:59:40 +00:00
'Second request is a blocking request for job-1'
) ;
return wait ( ) . then ( ( ) => {
request ( ) ;
assert . equal (
2018-07-05 19:29:29 +00:00
pretender . handledRequests [ 1 ] . url ,
2018-03-21 20:28:56 +00:00
'/v1/job/job-1?index=2' ,
2018-02-17 02:59:40 +00:00
'Third request is a blocking request with an incremented index param'
) ;
return wait ( ) ;
} ) ;
} ) ;
test ( 'relationships can be reloaded' , function ( assert ) {
const { pretender } = this . server ;
const plainId = 'job-1' ;
const mockModel = makeMockModel ( plainId ) ;
this . subject ( ) . reloadRelationship ( mockModel , 'summary' ) ;
2018-07-05 20:49:27 +00:00
return wait ( ) . then ( ( ) => {
assert . equal (
pretender . handledRequests [ 0 ] . url ,
` /v1/job/ ${ plainId } /summary ` ,
'Relationship was reloaded'
) ;
} ) ;
2018-02-17 02:59:40 +00:00
} ) ;
test ( 'relationship reloads can be watched' , function ( assert ) {
const { pretender } = this . server ;
const plainId = 'job-1' ;
const mockModel = makeMockModel ( plainId ) ;
this . subject ( ) . reloadRelationship ( mockModel , 'summary' , true ) ;
assert . equal (
pretender . handledRequests [ 0 ] . url ,
2018-03-21 20:28:56 +00:00
'/v1/job/job-1/summary?index=1' ,
2018-02-17 02:59:40 +00:00
'First request is a blocking request for job-1 summary relationship'
) ;
return wait ( ) . then ( ( ) => {
this . subject ( ) . reloadRelationship ( mockModel , 'summary' , true ) ;
assert . equal (
pretender . handledRequests [ 1 ] . url ,
2018-03-21 20:28:56 +00:00
'/v1/job/job-1/summary?index=2' ,
2018-02-17 02:59:40 +00:00
'Second request is a blocking request with an incremented index param'
) ;
} ) ;
} ) ;
test ( 'findAll can be canceled' , function ( assert ) {
const { pretender } = this . server ;
pretender . get ( '/v1/jobs' , ( ) => [ 200 , { } , '[]' ] , true ) ;
2018-03-01 00:34:27 +00:00
this . subject ( )
. findAll ( null , { modelName : 'job' } , null , {
reload : true ,
adapterOptions : { watch : true } ,
} )
. catch ( ( ) => { } ) ;
2018-02-17 02:59:40 +00:00
const { request : xhr } = pretender . requestReferences [ 0 ] ;
assert . equal ( xhr . status , 0 , 'Request is still pending' ) ;
// Schedule the cancelation before waiting
run . next ( ( ) => {
this . subject ( ) . cancelFindAll ( 'job' ) ;
} ) ;
return wait ( ) . then ( ( ) => {
assert . ok ( xhr . aborted , 'Request was aborted' ) ;
} ) ;
} ) ;
test ( 'findRecord can be canceled' , function ( assert ) {
const { pretender } = this . server ;
const jobId = JSON . stringify ( [ 'job-1' , 'default' ] ) ;
pretender . get ( '/v1/job/:id' , ( ) => [ 200 , { } , '{}' ] , true ) ;
this . subject ( ) . findRecord ( null , { modelName : 'job' } , jobId , {
reload : true ,
adapterOptions : { watch : true } ,
} ) ;
const { request : xhr } = pretender . requestReferences [ 0 ] ;
assert . equal ( xhr . status , 0 , 'Request is still pending' ) ;
// Schedule the cancelation before waiting
run . next ( ( ) => {
this . subject ( ) . cancelFindRecord ( 'job' , jobId ) ;
} ) ;
return wait ( ) . then ( ( ) => {
assert . ok ( xhr . aborted , 'Request was aborted' ) ;
} ) ;
} ) ;
test ( 'relationship reloads can be canceled' , function ( assert ) {
const { pretender } = this . server ;
const plainId = 'job-1' ;
const mockModel = makeMockModel ( plainId ) ;
pretender . get ( '/v1/job/:id/summary' , ( ) => [ 200 , { } , '{}' ] , true ) ;
this . subject ( ) . reloadRelationship ( mockModel , 'summary' , true ) ;
const { request : xhr } = pretender . requestReferences [ 0 ] ;
assert . equal ( xhr . status , 0 , 'Request is still pending' ) ;
// Schedule the cancelation before waiting
run . next ( ( ) => {
this . subject ( ) . cancelReloadRelationship ( mockModel , 'summary' ) ;
} ) ;
return wait ( ) . then ( ( ) => {
assert . ok ( xhr . aborted , 'Request was aborted' ) ;
} ) ;
} ) ;
2018-03-29 18:44:26 +00:00
test ( 'requests can be canceled even if multiple requests for the same URL were made' , function ( assert ) {
const { pretender } = this . server ;
const jobId = JSON . stringify ( [ 'job-1' , 'default' ] ) ;
pretender . get ( '/v1/job/:id' , ( ) => [ 200 , { } , '{}' ] , true ) ;
this . subject ( ) . findRecord ( null , { modelName : 'job' } , jobId , {
reload : true ,
adapterOptions : { watch : true } ,
} ) ;
this . subject ( ) . findRecord ( null , { modelName : 'job' } , jobId , {
reload : true ,
adapterOptions : { watch : true } ,
} ) ;
const { request : xhr } = pretender . requestReferences [ 0 ] ;
assert . equal ( xhr . status , 0 , 'Request is still pending' ) ;
assert . equal ( pretender . requestReferences . length , 2 , 'Two findRecord requests were made' ) ;
assert . equal (
pretender . requestReferences . mapBy ( 'url' ) . uniq ( ) . length ,
1 ,
'The two requests have the same URL'
) ;
// Schedule the cancelation before waiting
run . next ( ( ) => {
this . subject ( ) . cancelFindRecord ( 'job' , jobId ) ;
} ) ;
return wait ( ) . then ( ( ) => {
assert . ok ( xhr . aborted , 'Request was aborted' ) ;
} ) ;
} ) ;
2018-05-25 16:13:18 +00:00
test ( 'canceling a find record request will never cancel a request with the same url but different method' , function ( assert ) {
const { pretender } = this . server ;
const jobId = JSON . stringify ( [ 'job-1' , 'default' ] ) ;
pretender . get ( '/v1/job/:id' , ( ) => [ 200 , { } , '{}' ] , true ) ;
pretender . delete ( '/v1/job/:id' , ( ) => [ 204 , { } , '' ] , 200 ) ;
this . subject ( ) . findRecord ( null , { modelName : 'job' } , jobId , {
reload : true ,
adapterOptions : { watch : true } ,
} ) ;
this . subject ( ) . stop ( EmberObject . create ( { id : jobId } ) ) ;
const { request : getXHR } = pretender . requestReferences [ 0 ] ;
const { request : deleteXHR } = pretender . requestReferences [ 1 ] ;
assert . equal ( getXHR . status , 0 , 'Get request is still pending' ) ;
assert . equal ( deleteXHR . status , 0 , 'Delete request is still pending' ) ;
// Schedule the cancelation before waiting
run . next ( ( ) => {
this . subject ( ) . cancelFindRecord ( 'job' , jobId ) ;
} ) ;
return wait ( ) . then ( ( ) => {
assert . ok ( getXHR . aborted , 'Get request was aborted' ) ;
assert . notOk ( deleteXHR . aborted , 'Delete request was aborted' ) ;
} ) ;
} ) ;
2018-02-17 02:59:40 +00:00
function makeMockModel ( id , options ) {
return assign (
{
relationshipFor ( name ) {
return {
kind : 'belongsTo' ,
type : 'job-summary' ,
key : name ,
} ;
} ,
belongsTo ( name ) {
return {
link ( ) {
return ` /v1/job/ ${ id } / ${ name } ` ;
} ,
} ;
} ,
} ,
options
) ;
}