This commit is contained in:
Seth Call 2015-01-21 15:22:31 -06:00
parent 4d8a7a9bc1
commit 698f4ba648
9 changed files with 507 additions and 66 deletions

View File

@ -2,6 +2,24 @@ $ = jQuery
context = window
context.JK ||= {};
# This is the sequence of how this widget works:
# checkState() is the heart of the state machine; it is called to get things going, and is called whenevr a state ends
# checkState() checks first against what the client thinks about the state of the JamTrack;
# if it on the disk then the state machine may enter one of:
# * synchronized
# * keying
#
# if it's still on the server, then the state machine may be:
# * packaging
# * downloading
#
# errored state can be entered from @jamTrackRightId
#
# other state; you augment the error to the user by suppling @errorMessage before transitioning
#
# no-client is the way the widget behaves when you are in a normal browser (i.e., nothing happens other than tell the user to use the client)
#
# Discussion of the different states:
# There are different states that a JamTrack can be in.
# The final success state is that the JamTrack is on disk and loadable. (show synchronized state)
# But there are others until you get there:
@ -18,21 +36,25 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
@jamTrackId = jamTrackId
@jamTrackRightId = jamTrackRightId
@attemptedEnqueue = false
@errorReason = null
@errorMessage = null
@transitionTimer = null
@downloadTimer = null
@trackDetail = null
@stateHolder = null
@active = false
@startTime = null
@path = []
@errorSupportMsg = "Press RETRY, or if you have already retried, please contact support@jamkazam.com."
@states = {
no_client: { name: 'no-client', show: @showNoClient },
synchronized: { name: 'synchronized', show: @showSynchronized },
no_client: { name: 'no-client', show: @showNoClient, leaf: true },
synchronized: { name: 'synchronized', show: @showSynchronized, leaf: true},
packaging: { name: 'packaging', show: @showPackaging },
downloading: { name: 'downloading', show: @showDownloading },
keying: { name: 'keying', show: @showKeying },
keying: { name: 'keying', show: @showKeying, max_time: 10000 },
initial: { name: 'initial', show: @showInitial },
errored: { name: 'errored', show: @showError }
errored: { name: 'errored', show: @showError, leaf: true}
}
@state = @states.initial
context.JK.DownloadJamTracks[@jamTrackId] = this
@ -40,7 +62,14 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
# after you've created the DownloadJamTrack widget, call synchronize which will begin ensuring that the jamtrack
# is downloaded and ready to open
init: () =>
@root = $($('#template-download-jamtrack').html())
@active = true
this.reset()
downloadJamTrackTemplate = $('#template-download-jamtrack')
throw "no download jamtrack template" if not downloadJamTrackTemplate.exists()
@root = $(downloadJamTrackTemplate.html())
@stateHolder = @root.find('.state')
# populate in template and visual transition functions
for state, data of @states
@ -48,55 +77,104 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
# check if we are in a browser or client
if !gon.isNativeClient
@states.no_client.show()
this.transition(@states.no_client)
else
@states.initial.show()
this.synchronize()
@attemptedEnqueue = false
this.checkState()
# when done with the widget, call destroy; this ensures it's not still active
destroy: () =>
@active = false
this.reset()
reset: () =>
@path = []
@startTime = new Date()
@state = @states.initial
# reset attemptedEnqueue to false, to allow one attempt to enqueue
@attemptedEnqueue = false
this.clearDownloadTimer()
this.clearTransitionTimer()
for state, data of @states
if data.timer?
clearInterval(data.timer)
data.timer = null
showPackaging: () =>
@logger.debug("showing #{@states.name}")
@logger.debug("showing #{@state.name}")
this.expectTransition()
showDownloading: () =>
@logger.debug("showing #{@states.name}")
@logger.debug("showing #{@state.name}")
# while downloading, we don't run the transition timer, because the download API is guaranteed to call success, or failure, eventually
this.clearTransitionTimer()
context.jamClient.StartFileDownload(context.JK.makeAbsolute('/api/jamtracks/download/' + @jamTrackId), this.makeDownloadProgressCallback(), this.makeDownloadSuccessCallback(), this.makeDownloadFailureCallback(), true)
showKeying: () =>
@logger.debug("showing #{@states.name}")
this.clearTransitionTimer()
@logger.debug("showing #{@state.name}")
context.jamClient.requestJamTrackKeys()
this.expectKeyed()
this.waitForState()
showInitial: () =>
@logger.debug("showing #{@states.name}")
@logger.debug("showing #{@state.name}")
this.expectTransition()
context.JK.SubscriptionUtils.subscribe('jam_track_right', @jamTrackRightId).on(context.JK.EVENTS.SUBSCRIBE_NOTIFICATION, this.onJamTrackRightEvent)
this.checkState()
showError: () =>
@logger.debug("showing #{@states.name}")
clearTransitionTimer()
@logger.debug("showing #{@state.name}")
context.JK.SubscriptionUtils.unsubscribe('jam_track_right', @jamTrackRightId)
@stateHolder.find('.msg').text(@errorMessage)
@stateHolder.find('.retry-button').click(this.retry)
showSynchronized: () =>
@logger.debug("showing #{@states.name}")
clearTransitionTimer()
@logger.debug("showing #{@state.name}")
context.JK.SubscriptionUtils.unsubscribe('jam_track_right', @jamTrackRightId)
showNoClient: () =>
@logger.debug("showing #{@states.name}")
@logger.debug("showing #{@state.name}")
downloadCheck: () =>
@logger.debug "downloadcheck"
@logger.debug "downloadCheck"
# sets an interval timer for every 3 seconds, waiting for the status to change
expectKeyed: () =>
retry: () =>
# just switch to the initial state again, causing the loop to start again
this.transition(@states.initial)
return false
clearStateTimer: () =>
if @state.timer?
clearInterval(@state.timer)
@state.timer = null
stateIntervalCheck: () =>
this.checkState()
# if the timer is null now, then it must have been whacked due to a state change
# if not, then let's see if we have timed out
if @state.timer?
if (new Date()).getTime() - @state.stateStartTime.getTime() > @state.max_time
@logger.debug("The current step (#{@state.name}) took too long")
if @state == @states.keying
# specific message
this.transitionError("#{@state.name}-timeout", "It took too long for the JamTrack to be keyed.")
else
# generic message
this.transitionError("#{@state.name}-timeout", "The current step (#{@state.name}) took too long")
# sets an interval timer for every second, waiting for the status to change
waitForState: () =>
unless @active
@logger.error("DownloadJamTrack: ignoring waitForState because we are not active")
@state.timer = setInterval(this.stateIntervalCheck, 1000)
# unused atm; the backend is good about always signalling. we still should though
expectDownload: () =>
unless @downloadTimer?
return
unless @active
@logger.error("DownloadJamTrack: ignoring expectDownload because we are not active")
# every 10 seconds, wake up and check the server and see if we missed a state transition
this.clearDownloadTimer()
@ -107,6 +185,10 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
clearTimeout(@downloadTimer)
@downloadTimer = null
transitionError: (reasonCode, errorMessage) =>
@errorReason = reasonCode
@errorMessage = errorMessage
this.transition(@states.errored)
transitionCheck: () =>
this.checkState()
@ -117,8 +199,8 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
# we don't get an event, so that's why, after 12 seconds, we'll still go to the server and check.
# exception: this should not be runngi
expectTransition: () =>
unless @transitionTimer?
return
unless @active
@logger.error("DownloadJamTrack: ignoring expectTransition because we are not active")
# every 12 seconds, wake up and check the server and see if we missed a state transition
this.clearTransitionTimer()
@ -130,23 +212,54 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
@transitionTimer = null
transition: (newState) =>
unless @active
@logger.error("DownloadJamTrack: ignoring state change because we are not active")
if newState == @state
@logger.debug("DownloadJamTrack: ignoring state change #{@state}")
@logger.debug("DownloadJamTrack: ignoring state change #{@state.name}")
return
@logger.debug("DownloadJamTrack: state change: #{@state} => #{newState}")
@logger.debug("DownloadJamTrack: state change: #{@state.name} => #{newState.name}")
# make sure there is no timer running on the old state
this.clearTransitionTimer()
this.clearStateTimer()
@state = newState
@states[newState].show()
# track which states were taken
@path.push(@state.name)
if @state.leaf
# report a stat now that we've reached the end of this widget's journey
flattened_path = @path.join('-')
data = {value: 1, path: flattened_path, duration: (new Date().getTime() - @startTime.getTime()) / 1000}
if @state == @states.errored
data.result = 'error'
data.detail = @errorDetail
else
data.result = 'success'
context.JK.stats.write('web.jamtrack.downloader', data)
@state.stateStartTime = new Date();
@stateHolder.children().remove()
@stateHolder.append(@state.template.html())
@state.show()
checkState: () =>
# check for the success state against the local state of the client... if it's playable, then we should be OK
@trackDetail = context.jamClient.JamTrackGetTrackDetail(@jamTrackId)
@trackDetail = context.jamClient.JamTrackGetTrackDetail (@jamTrackId)
@logger.debug("DownloadJamTrack: JamTrackGetTrackDetail.key_state: " + @trackDetail.key_state)
switch @trackDetail.key_state
when 'pending'
this.transition(@states.keying)
when 'not authorized'
# TODO: if not authorized, do we need to re-initiate a keying attempt?
this.transition(@states.keying)
when 'ready'
this.transition(@states.synchronized)
@ -157,57 +270,54 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
processSigningState: (signingState) =>
@logger.debug("DownloadJamTrack: processSigningState: " + signingState)
switch signingState
when 'QUIET'
if @attemptedEnqueue
# this means we've already tried to poke the server. something is wrong
@errorMessage = "The server has not begun building your JamTrack. #{@errorSupportMsg}"
this.transition(@states.errored)
this.transitionError("enqueue-timeout", "The server has not begun building your JamTrack.")
else
this.expectTransition()
@attemptedEnqueue = true
@rest.enqueueJamTrack({id: @jamTrackId})
.done(this.processEnqueueJamTrack)
.fail(this.processEnqueueJamTrackFail)
when 'QUEUED'
# when it's queued, there is nothing to do except wait.
this.expectTransition()
this.transition(@states.packaging)
when 'QUEUED_TIMEOUT'
@errorMessage = "The server took too long to begin processing your JamTrack. #{@errorSupportMsg}"
this.transition(@states.errored)
this.transitionError("queued-timeout", "The server took too long to begin processing your JamTrack.")
when 'SIGNING'
this.expectTransition()
this.transition(@states.packaging)
when 'SIGNING_TIMEOUT'
@errorMessage = "The server took too long to create your JamTrack. #{@errorSupportMsg}"
this.transition(@states.errored)
this.transitionError("signing-timeout", "The server took too long to create your JamTrack.")
when 'SIGNED'
this.transition(@states.downloading)
when 'ERROR'
if @attemptedEnqueue
# this means we've already tried to poke the server. something is wrong
@errorMessage = "The server failed to create your package. #{@errorSupportMsg}"
this.transition(@states.errored)
this.transitionError("package-error", "The server failed to create your package.")
else
this.expectTransition()
@attemptedEnqueue = true
@rest.enqueueJamTrack({id: @jamTrackId})
.done(this.processEnqueueJamTrack)
.fail(this.processEnqueueJamTrackFail)
else
@logger.error("unknown state: " + signingState)
this.transitionError("unknown-state-#{signingState}", "The server sent an unknown state message: " + signingState)
processJamTrackRightFail: () =>
@errorMessage = "Unable to check with the server on the status of your JamTrack. #{@errorSupportMsg}"
this.transition(@states.errored)
this.transitionError("status-check-error", "Unable to check with the server on the status of your JamTrack.")
processEnqueueJamTrack: (enqueueResponse) =>
this.expectTransition() # the act of enqueuing should send down events to the client. we wait...
processEnqueueJamTrackFail: () =>
@errorMessage = "Unable to ask the server to build your JamTrack. #{@errorSupportMsg}"
this.transition(@states.errored)
this.transitionError("enqueue-error", "Unable to ask the server to build your JamTrack.")
processJamTrackRight: (myJamTrack) =>
this.processSigningState(myJamTrack.signing_state)
@ -230,8 +340,7 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
this.transition(@states.keying)
downloadFailureCallback: (errorMsg) =>
@errorMessage = errorMessage
this.transition(@states.errored)
this.transitionError("download-error", errorMsg)
# makes a function name for the backend
makeDownloadProgressCallback: () =>

View File

@ -682,6 +682,9 @@
function JamTrackIsPlayable() {
return true;
}
function JamTrackGetTrackDetail() {
return {key_state: 'ready'}
}
// Method which sets volume
function UpdateMixer(mixerId) {}
@ -977,6 +980,7 @@
this.TrackSetChatUsesMusic = TrackSetChatUsesMusic;
this.JamTrackIsPlayable = JamTrackIsPlayable;
this.JamTrackGetTrackDetail = JamTrackGetTrackDetail;
// Scoring Knobs
this.GetScoreWorkTimingInterval = GetScoreWorkTimingInterval;

View File

@ -1606,6 +1606,7 @@
this.getJamtracks = getJamtracks;
this.getPurchasedJamTracks = getPurchasedJamTracks;
this.getJamTrackRight = getJamTrackRight;
this.enqueueJamTrack = enqueueJamTrack;
this.addJamtrackToShoppingCart = addJamtrackToShoppingCart;
this.getShoppingCarts = getShoppingCarts;
this.removeShoppingCart = removeShoppingCart;

View File

@ -39,4 +39,16 @@ class SpikesController < ApplicationController
Notification.send_subscription_message('test', '2', '{"msg": "oh hai 2"}')
render text: 'oh hai'
end
def download_jam_track
jamTrack = JamTrack.find(params[:jam_track_id])
jamTrackRight = jamTrack.right_for_user(current_user)
gon.jamTrackId = jamTrack.id
gon.jamTrackRightId = jamTrackRight.id
gon.switchState = params[:state]
render :layout => 'web'
end
end

View File

@ -1,30 +1,41 @@
script type="text/template" id='template-download-jamtrack'
.download-jamtrack
.state
script type="text/template" id="template-download-jamtrack-state-no-client"
.state-no-client
| To download this JamTrack, launch the JamKazam application and open it while in a session.
| To play this JamTrack, launch the JamKazam application and open it while in a session.
script type="text/template" id="template-download-jamtrack-state-synchronized"
.state-success
.state-synchronized
| This JamTrack is on your system and ready to play.
script type="text/template" id="template-download-jamtrack-state-packaging"
.state-packaging
| Your JamTrack is currently being created on the JamKazam server.
.msg
| Your JamTrack is currently being created on the JamKazam server.
.spinner-small
script type="text/template" id="template-download-jamtrack-state-downloading"
.state-downloading
| Your JamTrack is currently being downloaded.
.msg
| Your JamTrack is currently being downloaded.
.spinner-small
script type="text/template" id="template-download-jamtrack-state-keying"
.state-keying
| Your JamTrack is being authenticated.
.msg
| Your JamTrack is being authenticated.
.spinner-small
script type="text/template" id="template-download-jamtrack-state-initial"
.state-initial
| Initializing...
.msg
| Initializing...
script type="text/template" id="template-download-jamtrack-state-errored"
.state-errored
.msg
.msg
.retry
| Press RETRY, or if you have already retried, please contact support@jamkazam.com.
.a.button-orange.retry-button RETRY

View File

@ -64,6 +64,7 @@
<%= render "overlay_small" %>
<%= render "listenBroadcast" %>
<%= render "sync_viewer_templates" %>
<%= render "download_jamtrack_templates" %>
<%= render "help" %>
<%= render 'dialogs/dialogs' %>
<div id="fb-root"></div>

View File

@ -0,0 +1,28 @@
= javascript_include_tag "download_jamtrack"
= render "clients/download_jamtrack_templates"
- provide(:title, 'Download Jam Track Widget')
.content-wrapper
h2 Jam Track State Widget
ul
li synchronized
li no_client
li packaging
li downloading
li keying
li initial
li errored
#widget
javascript:
$(document).on('JAMKAZAM_READY', function() {
window.downloadJamTrack = new JK.DownloadJamTrack(gon.jamTrackId, gon.jamTrackRightId)
downloadJamTrack.init()
$('#widget').append(window.downloadJamTrack.root)
console.log("gon.switchstate", gon.switchState)
if(gon.switchState) {
downloadJamTrack.transition(downloadJamTrack.states[gon.switchState]);
}
})

View File

@ -92,6 +92,7 @@ SampleApp::Application.routes.draw do
match '/launch_app', to: 'spikes#launch_app'
match '/websocket', to: 'spikes#websocket'
match '/test_subscription', to: 'spikes#subscription'
match '/widgets/download_jam_track', to: 'spikes#download_jam_track'
# junk pages
match '/help', to: 'static_pages#help'

View File

@ -1,15 +1,289 @@
describe "DownloadJamTrack", ->
beforeEach ->
this.fixtures = fixture.load("downoadJamTrack.html"); # append these fixtures which were already cached
this.fixtures = fixture.load("downloadJamTrack.html"); # append these fixtures which were already cached
this.server = sinon.fakeServer.create();
window.jamClient = sinon.stub()
this.downloadJamTrack = new JK.DownloadJamTrack()
this.downloadJamTrack.init()
$('body').append(this.downloadJamTrack.root)
this.app = sinon.stub()
this.jamTrackId = '1'
window.gon = {}
window.JK.JamServer = {}
window.JK.stats = {}
@statsSpy = window.JK.stats.write = sinon.spy()
window.JK.JamServer.send = sinon.stub(); # attempts to subscribe to the socket will need this
afterEach ->
this.server.restore();
window.JK.stats.write.reset()
describe "normal browser", ->
beforeEach ->
window.gon.isNativeClient = false
@showNoClientSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showNoClient')
this.downloadJamTrack = new JK.DownloadJamTrack(@app, @jamTrackId, '1')
$('body').append(this.downloadJamTrack.root)
afterEach ->
@showNoClientSpy.restore()
it "switches to 'no client' correctly", ->
window.jamClient.JamTrackGetTrackDetail = sinon.stub()
#window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'ready'})
@downloadJamTrack.init();
expect(window.jamClient.JamTrackGetTrackDetail.callCount).toBe(0)
expect(@showNoClientSpy.calledOnce).toBe(true)
expect(@downloadJamTrack.stateHolder.find('.state-no-client')).toHaveLength(1)
expect(@statsSpy.calledOnce).toBe(true)
describe "client", ->
beforeEach ->
window.gon.isNativeClient = true
describe "already synchronized", ->
beforeEach ->
@showSynchronizedSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showSynchronized')
@downloadJamTrack = new JK.DownloadJamTrack(@app, @jamTrackId, '1')
$('body').append(@downloadJamTrack.root)
afterEach ->
@showSynchronizedSpy.restore()
@downloadJamTrack.destroy()
it "shows synchronized state", ->
window.jamClient.JamTrackGetTrackDetail = sinon.stub()
window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'ready'})
@downloadJamTrack.init();
expect(window.jamClient.JamTrackGetTrackDetail.callCount).toBe(1)
expect(@showSynchronizedSpy.calledOnce).toBe(true)
expect(@downloadJamTrack.transitionTimer).toBe(null)
expect(@downloadJamTrack.downloadTimer).toBe(null)
expect(@statsSpy.calledOnce).toBe(true)
expect(@downloadJamTrack.stateHolder.find('.state-synchronized')).toHaveLength(1)
describe "pending", ->
beforeEach ->
window.jamClient.requestJamTrackKeys = sinon.stub()
@showSynchronizedSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showSynchronized')
@showErrorSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showError')
@showKeyingSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showKeying')
@downloadJamTrack = new JK.DownloadJamTrack(@app, @jamTrackId, '1')
@downloadJamTrack.states.keying.max_time = -1 # hurry up the test, instead of waiting 10 seconds
$('body').append(@downloadJamTrack.root)
afterEach ->
@showSynchronizedSpy.restore()
@showErrorSpy.restore()
@showKeyingSpy.restore()
@downloadJamTrack.destroy()
it "shows errored state due to timeout", ->
window.jamClient.JamTrackGetTrackDetail = sinon.stub()
window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'pending'})
@downloadJamTrack.init();
expect(window.jamClient.JamTrackGetTrackDetail.callCount).toBe(1)
expect(@showKeyingSpy.calledOnce).toBe(true)
expect(@downloadJamTrack.states.keying.timer).toNotBe(null)
@downloadJamTrack.stateIntervalCheck()
expect(window.jamClient.JamTrackGetTrackDetail.callCount).toBe(2)
expect(@showErrorSpy.calledOnce).toBe(true)
expect(@downloadJamTrack.states.keying.timer).toBe(null)
expect(@downloadJamTrack.stateHolder.find('.state-errored')).toHaveLength(1)
expect(@downloadJamTrack.stateHolder.find('.state-errored .msg')).toContainText('It took too long for the JamTrack to be keyed.')
expect(@statsSpy.calledOnce).toBe(true)
it "shows synchronized", ->
window.jamClient.JamTrackGetTrackDetail = sinon.stub()
window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'pending'})
@downloadJamTrack.init()
expect(window.jamClient.JamTrackGetTrackDetail.callCount).toBe(1)
expect(@showKeyingSpy.calledOnce).toBe(true)
# keying timer should be firing
expect(@downloadJamTrack.states.keying.timer).toNotBe(null)
# say the keys have been fetched
window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'ready'})
# then do a check
@downloadJamTrack.stateIntervalCheck()
expect(@showSynchronizedSpy.calledOnce).toBe(true)
expect(@downloadJamTrack.states.keying.timer).toBe(null)
expect(@downloadJamTrack.stateHolder.find('.state-synchronized')).toHaveLength(1)
expect(@statsSpy.calledOnce).toBe(true)
describe "JamTrack needs downloading", ->
beforeEach ->
window.jamClient.requestJamTrackKeys = sinon.stub()
@showSynchronizedSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showSynchronized')
@showErrorSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showError')
@showKeyingSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showKeying')
@showDownloadingSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showDownloading')
@showPackagingSpy = sinon.spy(JK.DownloadJamTrack.prototype, 'showPackaging')
@downloadJamTrack = new JK.DownloadJamTrack(@app, @jamTrackId, '1')
@downloadJamTrack.states.keying.max_time = -1 # hurry up the test, instead of waiting 10 seconds
$('body').append(@downloadJamTrack.root)
afterEach ->
@showSynchronizedSpy.restore()
@showErrorSpy.restore()
@showKeyingSpy.restore()
@showDownloadingSpy.restore()
@showPackagingSpy.restore()
@downloadJamTrack.destroy()
it "shows downloading for signed package", ->
window.jamClient.JamTrackGetTrackDetail = sinon.stub()
window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'unknown'})
spyOn(@downloadJamTrack.rest, 'getJamTrackRight').andCallFake((data) =>
d = $.Deferred();
d.resolve({signing_state: 'SIGNED'});
d.promise();
)
window.jamClient.StartFileDownload = sinon.stub()
@downloadJamTrack.init()
expect(window.jamClient.JamTrackGetTrackDetail.callCount).toBe(1)
expect(window.jamClient.StartFileDownload.callCount).toBe(1)
expect(@showDownloadingSpy.calledOnce).toBe(true)
expect(@downloadJamTrack.stateHolder.find('.state-downloading')).toHaveLength(1)
eval(@downloadJamTrack.makeDownloadSuccessCallback() + '()')
expect(@showKeyingSpy.calledOnce).toBe(true)
expect(@downloadJamTrack.stateHolder.find('.state-keying')).toHaveLength(1)
# keying timer should be firing
expect(@downloadJamTrack.states.keying.timer).toNotBe(null)
# say the keys have been fetched
window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'ready'})
# check state again
@downloadJamTrack.stateIntervalCheck()
# we should now be synchronized
expect(@showSynchronizedSpy.calledOnce).toBe(true)
expect(@downloadJamTrack.states.keying.timer).toBe(null)
expect(@downloadJamTrack.stateHolder.find('.state-synchronized')).toHaveLength(1)
expect(@statsSpy.calledOnce).toBe(true)
it "is not yet packaged", ->
window.jamClient.JamTrackGetTrackDetail = sinon.stub()
window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'unknown'})
spyOn(@downloadJamTrack.rest, 'getJamTrackRight').andCallFake((data) =>
d = $.Deferred();
d.resolve({signing_state: 'QUIET'});
d.promise();
)
spyOn(@downloadJamTrack.rest, 'enqueueJamTrack').andCallFake((data) =>
d = $.Deferred();
d.resolve({});
d.promise();
)
window.jamClient.StartFileDownload = sinon.stub()
@downloadJamTrack.init()
expect(@downloadJamTrack.attemptedEnqueue).toBe(true)
expect(@downloadJamTrack.transitionTimer?).toBe(true)
# simulate poke from server saying the track has been queued
@downloadJamTrack.onJamTrackRightEvent(null, {body: {signing_state: 'QUEUED'}})
# the frontend should be saying that it's packaging now
expect(@downloadJamTrack.transitionTimer?).toBe(true)
expect(@showPackagingSpy.calledOnce).toBe(true)
expect(@downloadJamTrack.stateHolder.find('.state-packaging')).toHaveLength(1)
# simulate poke from server saying the track is currently signing
@downloadJamTrack.onJamTrackRightEvent(null, {body: {signing_state: 'SIGNING'}})
# the frontend still be saying it's packaging
expect(@downloadJamTrack.transitionTimer?).toBe(true)
expect(@showPackagingSpy.calledOnce).toBe(true)
# simulate poke from server saying the track is signed
@downloadJamTrack.onJamTrackRightEvent(null, {body: {signing_state: 'SIGNED'}})
expect(@downloadJamTrack.transitionTimer?).toBe(false)
# downloading has started; other test covers this, so we stop testing
expect(@showDownloadingSpy.calledOnce).toBe(true)
expect(@downloadJamTrack.stateHolder.find('.state-downloading')).toHaveLength(1)
# since we haven't yet made it to a leave node, make sure we haven't reported a stat
expect(@statsSpy.callCount).toBe(0)
it "queue time out when packaging", ->
window.jamClient.JamTrackGetTrackDetail = sinon.stub()
window.jamClient.JamTrackGetTrackDetail.returns({'key_state' : 'unknown'})
getJamTrackRightSpy = spyOn(@downloadJamTrack.rest, 'getJamTrackRight')
getJamTrackRightSpy.andCallFake((data) =>
d = $.Deferred();
d.resolve({signing_state: 'QUIET'});
d.promise();
)
spyOn(@downloadJamTrack.rest, 'enqueueJamTrack').andCallFake((data) =>
d = $.Deferred();
d.resolve({});
d.promise();
)
window.jamClient.StartFileDownload = sinon.stub()
@downloadJamTrack.init()
expect(@downloadJamTrack.attemptedEnqueue).toBe(true)
expect(@downloadJamTrack.transitionTimer?).toBe(true)
getJamTrackRightSpy.reset()
# simulate timer running out, and server check resulting in QUEUED_TIMEOUT
getJamTrackRightSpy.andCallFake((data) =>
d = $.Deferred();
d.resolve({signing_state: 'QUEUED_TIMEOUT'});
d.promise();
)
@downloadJamTrack.transitionCheck()
# the frontend should be saying that it's packaging now
expect(@downloadJamTrack.transitionTimer?).toBe(false)
expect(@showErrorSpy.calledOnce).toBe(true)
expect(@downloadJamTrack.stateHolder.find('.state-errored')).toHaveLength(1)
expect(@downloadJamTrack.stateHolder.find('.state-errored .msg')).toContainText('The server took too long to begin processing your JamTrack.')
expect(@statsSpy.calledOnce).toBe(true)
it "display state correctly", ->
//$track = this.downloadJamTrack.createTrack()