@@ -31,6 +31,15 @@ function FakeServiceObject() {
3131
3232nodeutil . inherits ( FakeServiceObject , ServiceObject ) ;
3333
34+ var utilOverrides = { } ;
35+ var fakeUtil = Object . keys ( util ) . reduce ( function ( fakeUtil , methodName ) {
36+ fakeUtil [ methodName ] = function ( ) {
37+ var method = utilOverrides [ methodName ] || util [ methodName ] ;
38+ return method . apply ( this , arguments ) ;
39+ } ;
40+ return fakeUtil ;
41+ } , { } ) ;
42+
3443describe ( 'BigQuery/Job' , function ( ) {
3544 var BIGQUERY = {
3645 projectId : 'my-project'
@@ -44,6 +53,8 @@ describe('BigQuery/Job', function() {
4453 '../../lib/common/service-object.js' ,
4554 FakeServiceObject
4655 ) ;
56+ mockery . registerMock ( '../../lib/common/util.js' , fakeUtil ) ;
57+
4758 mockery . enable ( {
4859 useCleanCache : true ,
4960 warnOnUnregistered : false
@@ -58,6 +69,7 @@ describe('BigQuery/Job', function() {
5869 } ) ;
5970
6071 beforeEach ( function ( ) {
72+ utilOverrides = { } ;
6173 job = new Job ( BIGQUERY , JOB_ID ) ;
6274 } ) ;
6375
@@ -81,6 +93,11 @@ describe('BigQuery/Job', function() {
8193 } ) ;
8294 } ) ;
8395
96+ it ( 'should correctly initialize variables' , function ( ) {
97+ assert . strictEqual ( job . completeListeners , 0 ) ;
98+ assert . strictEqual ( job . hasActiveListeners , false ) ;
99+ } ) ;
100+
84101 describe ( 'request interceptor' , function ( ) {
85102 it ( 'should assign a request interceptor for /cancel' , function ( ) {
86103 var requestInterceptor = job . interceptors . pop ( ) . request ;
@@ -219,4 +236,212 @@ describe('BigQuery/Job', function() {
219236 job . getQueryResults ( ) . done ( ) ;
220237 } ) ;
221238 } ) ;
239+
240+ describe ( 'listenForEvents_' , function ( ) {
241+ beforeEach ( function ( ) {
242+ job . startPolling_ = util . noop ;
243+ } ) ;
244+
245+ it ( 'should start polling when complete listener is bound' , function ( done ) {
246+ job . startPolling_ = function ( ) {
247+ done ( ) ;
248+ } ;
249+
250+ job . on ( 'complete' , util . noop ) ;
251+ } ) ;
252+
253+ it ( 'should track the number of listeners' , function ( ) {
254+ assert . strictEqual ( job . completeListeners , 0 ) ;
255+
256+ job . on ( 'complete' , util . noop ) ;
257+ assert . strictEqual ( job . completeListeners , 1 ) ;
258+
259+ job . removeListener ( 'complete' , util . noop ) ;
260+ assert . strictEqual ( job . completeListeners , 0 ) ;
261+ } ) ;
262+
263+ it ( 'should only run a single pulling loop' , function ( ) {
264+ var startPollingCallCount = 0 ;
265+
266+ job . startPolling_ = function ( ) {
267+ startPollingCallCount ++ ;
268+ } ;
269+
270+ job . on ( 'complete' , util . noop ) ;
271+ job . on ( 'complete' , util . noop ) ;
272+
273+ assert . strictEqual ( startPollingCallCount , 1 ) ;
274+ } ) ;
275+
276+ it ( 'should close when no more message listeners are bound' , function ( ) {
277+ job . on ( 'complete' , util . noop ) ;
278+ job . on ( 'complete' , util . noop ) ;
279+ assert . strictEqual ( job . hasActiveListeners , true ) ;
280+
281+ job . removeListener ( 'complete' , util . noop ) ;
282+ assert . strictEqual ( job . hasActiveListeners , true ) ;
283+
284+ job . removeListener ( 'complete' , util . noop ) ;
285+ assert . strictEqual ( job . hasActiveListeners , false ) ;
286+ } ) ;
287+ } ) ;
288+
289+ describe ( 'startPolling_' , function ( ) {
290+ var listenForEvents_ ;
291+ var job ;
292+
293+ before ( function ( ) {
294+ listenForEvents_ = Job . prototype . listenForEvents_ ;
295+ } ) ;
296+
297+ after ( function ( ) {
298+ Job . prototype . listenForEvents_ = listenForEvents_ ;
299+ } ) ;
300+
301+ beforeEach ( function ( ) {
302+ Job . prototype . listenForEvents_ = util . noop ;
303+ job = new Job ( BIGQUERY , JOB_ID ) ;
304+ job . hasActiveListeners = true ;
305+ } ) ;
306+
307+ afterEach ( function ( ) {
308+ job . hasActiveListeners = false ;
309+ } ) ;
310+
311+ it ( 'should not call getMetadata if no listeners' , function ( done ) {
312+ job . hasActiveListeners = false ;
313+
314+ job . getMetadata = done ; // if called, test will fail.
315+
316+ job . startPolling_ ( ) ;
317+ done ( ) ;
318+ } ) ;
319+
320+ it ( 'should call getMetadata if listeners are registered' , function ( done ) {
321+ job . hasActiveListeners = true ;
322+
323+ job . getMetadata = function ( ) {
324+ done ( ) ;
325+ } ;
326+
327+ job . startPolling_ ( ) ;
328+ } ) ;
329+
330+ describe ( 'API error' , function ( ) {
331+ var error = new Error ( 'Error.' ) ;
332+ var apiResponse = { } ;
333+
334+ beforeEach ( function ( ) {
335+ job . getMetadata = function ( callback ) {
336+ callback ( error , null , apiResponse ) ;
337+ } ;
338+ } ) ;
339+
340+ it ( 'should emit the error' , function ( done ) {
341+ job . on ( 'error' , function ( err ) {
342+ assert . strictEqual ( err , error ) ;
343+ done ( ) ;
344+ } ) ;
345+
346+ job . startPolling_ ( ) ;
347+ } ) ;
348+ } ) ;
349+
350+ describe ( 'job failure' , function ( ) {
351+ var error = new Error ( 'Error.' ) ;
352+ var apiResponse = {
353+ status : {
354+ errors : error
355+ }
356+ } ;
357+
358+ beforeEach ( function ( ) {
359+ job . getMetadata = function ( callback ) {
360+ callback ( null , apiResponse , apiResponse ) ;
361+ } ;
362+ } ) ;
363+
364+ it ( 'should detect and emit an error from the response' , function ( done ) {
365+ utilOverrides . ApiError = function ( body ) {
366+ assert . strictEqual ( body , apiResponse . status ) ;
367+
368+ return error ;
369+ } ;
370+
371+ job . on ( 'error' , function ( err ) {
372+ assert . strictEqual ( err , error ) ;
373+ done ( ) ;
374+ } ) ;
375+
376+ job . startPolling_ ( ) ;
377+ } ) ;
378+ } ) ;
379+
380+ describe ( 'job pending' , function ( ) {
381+ var apiResponse = {
382+ status : {
383+ state : 'PENDING'
384+ }
385+ } ;
386+ var setTimeoutCached = global . setTimeout ;
387+
388+ beforeEach ( function ( ) {
389+ job . getMetadata = function ( callback ) {
390+ callback ( null , apiResponse , apiResponse ) ;
391+ } ;
392+ } ) ;
393+
394+ after ( function ( ) {
395+ global . setTimeout = setTimeoutCached ;
396+ } ) ;
397+
398+ it ( 'should call startPolling_ after 500 ms' , function ( done ) {
399+ var startPolling_ = job . startPolling_ ;
400+ var startPollingCalled = false ;
401+
402+ global . setTimeout = function ( fn , timeoutMs ) {
403+ fn ( ) ; // should call startPolling_
404+ assert . strictEqual ( timeoutMs , 500 ) ;
405+ } ;
406+
407+ job . startPolling_ = function ( ) {
408+ if ( ! startPollingCalled ) {
409+ // Call #1.
410+ startPollingCalled = true ;
411+ startPolling_ . apply ( this , arguments ) ;
412+ return ;
413+ }
414+
415+ // This is from the setTimeout call.
416+ assert . strictEqual ( this , job ) ;
417+ done ( ) ;
418+ } ;
419+
420+ job . startPolling_ ( ) ;
421+ } ) ;
422+ } ) ;
423+
424+ describe ( 'job complete' , function ( ) {
425+ var apiResponse = {
426+ status : {
427+ state : 'DONE'
428+ }
429+ } ;
430+
431+ beforeEach ( function ( ) {
432+ job . getMetadata = function ( callback ) {
433+ callback ( null , apiResponse , apiResponse ) ;
434+ } ;
435+ } ) ;
436+
437+ it ( 'should emit complete with metadata' , function ( done ) {
438+ job . on ( 'complete' , function ( metadata ) {
439+ assert . strictEqual ( metadata , apiResponse ) ;
440+ done ( ) ;
441+ } ) ;
442+
443+ job . startPolling_ ( ) ;
444+ } ) ;
445+ } ) ;
446+ } ) ;
222447} ) ;
0 commit comments