From 315f5077b9697f4071e144084499f7a9cfd75162 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Wed, 10 Apr 2013 17:14:19 -0500 Subject: [PATCH] * adding jam-web support for client update. fixing capybara 2.1.0 breaking changes --- Gemfile | 4 +- app/assets/javascripts/clientUpdate.js | 134 ++++++++++++++++++ app/assets/javascripts/fakeJamClient.js | 31 ++++ .../stylesheets/unstyled/progressbar.css | 36 +++++ app/controllers/artifacts_controller.rb | 2 +- app/views/clients/index.html.erb | 6 + app/views/layouts/client.html.erb | 1 + config/application.rb | 20 +-- config/initializers/email.rb | 14 +- spec/controllers/sessions_controller_spec.rb | 2 +- spec/factories.rb | 1 + spec/features/authentication_pages_spec.rb | 16 +-- spec/requests/artifacts_api_spec.rb | 2 +- spec/spec_helper.rb | 7 + 14 files changed, 247 insertions(+), 29 deletions(-) create mode 100644 app/assets/javascripts/clientUpdate.js create mode 100644 app/assets/stylesheets/unstyled/progressbar.css diff --git a/Gemfile b/Gemfile index 00289cb90..f3d665267 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,8 @@ source 'https://rubygems.org' -source 'https://jamjam:blueberryjam@www.jamkazam.com/gems/' +unless ENV["LOCAL_DEV"] == "1" + source 'https://jamjam:blueberryjam@www.jamkazam.com/gems/' +end # Look for $WORKSPACE, otherwise use "workspace" as dev path. workspace = ENV["WORKSPACE"] || "~/workspace" diff --git a/app/assets/javascripts/clientUpdate.js b/app/assets/javascripts/clientUpdate.js new file mode 100644 index 000000000..26c88ada9 --- /dev/null +++ b/app/assets/javascripts/clientUpdate.js @@ -0,0 +1,134 @@ +(function(context,$) { + + "use strict"; + + context.JK = context.JK || {}; + context.JK.ClientUpdate = function() { + var self = this; + var logger = context.JK.logger; + + // updated once a download is started + var updateSize = 0; + + + /***************************************/ + /******** CALLBACKS FROM BACKEND *******/ + /***************************************/ + function clientUpdateDownloadProgress(bytesReceived, bytesTotal, downloadSpeedMegSec, timeRemaining) { + //logger.debug("bytesReceived: " + bytesReceived, ", bytesTotal: " + bytesTotal, ", downloadSpeed: " + downloadSpeedMegSec, ", timeRemaining: " + timeRemaining ); + + // bytesTotal from Qt is not trust worthy; trust server's answer instead + $('#downloadprogressbar div').width( ((bytesReceived/updateSize) * 100).toString() + "%" ) + $("#progres sbar_detail").text(parseInt(bytesReceived) + "/" + parseInt(updateSize)) + } + + function clientUpdateDownloadSuccess(updateLocation) { + logger.debug("client update downloaded successfully to: " + updateLocation); + + startUpdate(updateLocation); + } + + function clientUpdateDownloadFailure(errorMsg) { + logger.error("client update download error: " + errorMsg) + + alert("Unable to download client update due to reason:" + errorMsg); + } + + + function clientUpdateLaunchSuccess(updateLocation) { + logger.debug("client update launched successfully to: " + updateLocation); + + alert("Client updating momentarily..."); + } + + function clientUpdateLaunchFailure(errorMsg) { + logger.error("client update launch error: " + errorMsg) + + alert("Unable to launch client updater due to reason: " + errorMsg) + } + /********************************************/ + /******** END: CALLBACKS FROM BACKEND *******/ + /********************************************/ + + function shouldUpdate(currentVersion, version) { + return true; + } + + // check if updated is needed + function check() { + + var product = "JamClient" + var os = context.jamClient.GetOSAsString() + var currentVersion = context.jamClient.ClientUpdateVersion(); + + if(currentVersion == null || currentVersion.indexOf("Compiled") > -1) { + // this is a developer build; it doesn't make much sense to do an packaged update, so skip + logger.debug("skipping client update check because this is a development build") + return; + } + + $.ajax({ + type: "GET", + url: "/api/versioncheck?product=" + product + "&os=" + os, + success: function(response) { + var version = response.version; + logger.debug("our client version: " + currentVersion + ", server client version: " + version); + + // test url in lieu of having a configured server with a client-update available + //response.url = "http://localhost:8000/winimager/QtGui4.dll" + + if(shouldUpdate(currentVersion, version)) { + updateSize = response.size; + + // test metadata in lieu of having a configured server with a client-update available + // updateSize = 10000; + // version = "1.2.3" + if (confirm("The client will update to version " + version + " momentarily.")) + { + startDownload(response.url) + } + } + }, + error: function(jqXHR, textStatus, errorThrown) { + logger.error("Unable to do a client update check against /api/versioncheck"); + } + }); + } + + function startDownload(url) { + logger.debug("starting client updater download from: " + url); + + // initialize div in page so that we have something to update. temporary until real styles come + $('body').append($("
Downloading Client Update...
")) + + context.jamClient.ClientUpdateStartDownload(url, + "JK.ClientUpdate.DownloadProgressCallback", + "JK.ClientUpdate.DownloadSuccessCallback", + "JK.ClientUpdate.DownloadFailureCallback"); + } + + function startUpdate(updaterFilePath) { + logger.debug("starting client update from: " + updaterFilePath) + + context.jamClient.ClientUpdateStartUpdate(updaterFilePath, + "JK.ClientUpdate.LaunchUpdateSuccessCallback", + "JK.ClientUpdate.LaunchUpdateFailureCallback"); + + } + + function initialize() { + context.JK.ClientUpdate.DownloadProgressCallback = clientUpdateDownloadProgress; + context.JK.ClientUpdate.DownloadSuccessCallback = clientUpdateDownloadSuccess; + context.JK.ClientUpdate.DownloadFailureCallback = clientUpdateDownloadFailure; + context.JK.ClientUpdate.LaunchUpdateSuccessCallback = clientUpdateLaunchSuccess; + context.JK.ClientUpdate.LaunchUpdateFailureCallback = clientUpdateLaunchFailure; + + return self; + } + + // Expose publics + this.initialize = initialize; + this.check = check; + } + +})(window,jQuery); \ No newline at end of file diff --git a/app/assets/javascripts/fakeJamClient.js b/app/assets/javascripts/fakeJamClient.js index 0d8ca9f93..422bb8c6a 100644 --- a/app/assets/javascripts/fakeJamClient.js +++ b/app/assets/javascripts/fakeJamClient.js @@ -25,6 +25,7 @@ function GetFTUE() { return ftue; } function SetFTUE(b) { ftue = b; } function GetOS() { return 100000000; } + function GetOSAsString() { return "Win32"; } function LatencyUpdated(map) { dbg('LatencyUpdated:' + JSON.stringify(map)); } function LeaveSession(map) { dbg('LeaveSession:' + JSON.stringify(map)); } @@ -245,12 +246,38 @@ // Method which sets volume function UpdateMixer(mixerId) {} + // Client Update Functions + function ClientUpdateVersion() { return "Compiled 1.2.3"; } + function ClientUpdateStartDownload(url, progressCallback, successCallback, failureCallback) { + + // simulate a bunch of download callbacks + var count = 0; + var max = 100; + var bytesReceived = 0; + var bytesTotal = 10000; + + function fire() { + count++; + setTimeout(function() { + bytesReceived = ( count / max ) * bytesTotal; + JK.ClientUpdate.DownloadProgressCallback(bytesReceived, bytesTotal, 0, 0) + + if(count < max) { + fire() + } + }, 50) + } + fire() + + } + function ClientUpdateStartUpdate(path, successCallback, failureCallback) {} // Javascript Bridge seems to camel-case // Set the instance functions: this.GetASIODevices = GetASIODevices; this.GetFTUE = GetFTUE; this.GetOS = GetOS; + this.GetOSAsString = GetOSAsString; this.JoinSession = JoinSession; this.LatencyUpdated = LatencyUpdated; this.LeaveSession = LeaveSession; @@ -299,6 +326,10 @@ this.TrackSetInstrument = TrackSetInstrument; this.TrackGetInstrument = TrackGetInstrument; + // Client Update + this.ClientUpdateVersion = ClientUpdateVersion; + this.ClientUpdateStartDownload = ClientUpdateStartDownload; + this.ClientUpdateStartUpdate = ClientUpdateStartUpdate; }; })(window,jQuery); \ No newline at end of file diff --git a/app/assets/stylesheets/unstyled/progressbar.css b/app/assets/stylesheets/unstyled/progressbar.css new file mode 100644 index 000000000..ac42856f8 --- /dev/null +++ b/app/assets/stylesheets/unstyled/progressbar.css @@ -0,0 +1,36 @@ +#downloadprogressbar_container { + position:fixed; + width: 400px; + top:0; + bottom: 0; + left: 0; + right: 0; + + height:42px; + margin: auto; + + background-color: black; + border:2px solid #ddd; + padding:5px; +} + +#downloadprogressbar_container span#progressbar_info { + height:20px; +} + +#downloadprogressbar_container span#progressbar_detail { + +} + +#downloadprogressbar { + height:22px; + border-radius: 13px; + padding: 3px; +} + +#downloadprogressbar div { + background-color: orange; + width: 0; + height: 20px; + border-radius: 10px; +} \ No newline at end of file diff --git a/app/controllers/artifacts_controller.rb b/app/controllers/artifacts_controller.rb index 11ec4f149..9fc992047 100644 --- a/app/controllers/artifacts_controller.rb +++ b/app/controllers/artifacts_controller.rb @@ -29,7 +29,7 @@ class ArtifactsController < ApiController if @artifact.nil? render :json => {}, :status => :ok else - render :json => { "version" => @artifact.version, "uri" => @artifact.uri.path }, :status => :ok + render :json => { "version" => @artifact.version, "uri" => @artifact.uri.path, "sha1" => @artifact.sha1, "size" => @artifact.size }, :status => :ok end end diff --git a/app/views/clients/index.html.erb b/app/views/clients/index.html.erb index b96ab5dcd..1d4cd15fc 100644 --- a/app/views/clients/index.html.erb +++ b/app/views/clients/index.html.erb @@ -69,6 +69,11 @@ JK.currentUserId = null; <% end %> + + // do a client update check upon initialization + var clientUpdate = new JK.ClientUpdate() + clientUpdate.initialize().check() + // Some things can't be initialized until we're connected. Put them here. function _initAfterConnect() { @@ -130,6 +135,7 @@ testConnected(); } + }) diff --git a/app/views/layouts/client.html.erb b/app/views/layouts/client.html.erb index cfbb629f8..634e75e91 100644 --- a/app/views/layouts/client.html.erb +++ b/app/views/layouts/client.html.erb @@ -24,6 +24,7 @@ <%= stylesheet_link_tag "client/genreSelector", media: "all" %> <%= stylesheet_link_tag "client/sessionList", media: "all" %> <%= stylesheet_link_tag "client/searchResults", media: "all" %> + <%= stylesheet_link_tag "unstyled/progressbar", media: "all" %> <%= include_gon %> <%= javascript_include_tag "application" %> <%= csrf_meta_tags %> diff --git a/config/application.rb b/config/application.rb index 34845d06e..fe994eba1 100644 --- a/config/application.rb +++ b/config/application.rb @@ -13,19 +13,19 @@ require "sprockets/railtie" ActiveRecord::Base.establish_connection(YAML::load(File.open('config/database.yml'))[Rails.env]) if defined?(Bundler) - # If you precompile assets before deploying to production, use this line - Bundler.require(*Rails.groups(:assets => %w(development test))) - # If you want your assets lazily compiled in production, use this line - # Bundler.require(:default, :assets, Rails.env) -end + # If you precompile assets before deploying to production, use this line + Bundler.require(*Rails.groups(:assets => %w(development test))) + # If you want your assets lazily compiled in production, use this line + # Bundler.require(:default, :assets, Rails.env) + end -include JamRuby + include JamRuby # require "rails/test_unit/railtie" -module SampleApp - class Application < Rails::Application - # Settings in config/environments/* take precedence over those specified here. - # Application configuration should go into files in config/initializers + module SampleApp + class Application < Rails::Application + # Settings in config/environments/* take precedence over those specified here. + # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. # Custom directories with classes and modules you want to be autoloadable. diff --git a/config/initializers/email.rb b/config/initializers/email.rb index 818dc6e67..8b6bb118f 100644 --- a/config/initializers/email.rb +++ b/config/initializers/email.rb @@ -1,11 +1,11 @@ ActionMailer::Base.raise_delivery_errors = true ActionMailer::Base.delivery_method = Rails.env == "test" ? :test : :smtp ActionMailer::Base.smtp_settings = { - :address => "smtp.sendgrid.net", - :port => 587, - :domain => "www.jamkazam.com", - :authentication => :plain, - :user_name => "jamkazam", - :password => "jamjamblueberryjam", - :enable_starttls_auto => true + :address => "smtp.sendgrid.net", + :port => 587, + :domain => "www.jamkazam.com", + :authentication => :plain, + :user_name => "jamkazam", + :password => "jamjamblueberryjam", + :enable_starttls_auto => true } \ No newline at end of file diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index ec84d6e5f..ec3d2428c 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -11,7 +11,7 @@ describe SessionsController do it "should have the right title" do get :new - response.body.should have_selector('title', :text => "Jamkazam | Sign in") + response.body.should have_title("Jamkazam | Sign in") end end diff --git a/spec/factories.rb b/spec/factories.rb index 4d6a27e2e..432ce091b 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -99,6 +99,7 @@ FactoryGirl.define do product { "JamClient/Win32" } environment { "public" } sha1 { "blurp" } + size { 20 } end factory :musician_instrument, :class=> JamRuby::MusicianInstrument do diff --git a/spec/features/authentication_pages_spec.rb b/spec/features/authentication_pages_spec.rb index 3e662bd32..f0ebd903b 100644 --- a/spec/features/authentication_pages_spec.rb +++ b/spec/features/authentication_pages_spec.rb @@ -8,7 +8,7 @@ describe "Authentication" do before { visit signin_path } it { should have_selector('h1', text: 'sign in or register') } - it { expect(first('title').native.text).to eq "Jamkazam | Sign in" } + it { page.should have_title("Jamkazam | Sign in") } end describe "signin" do @@ -17,7 +17,7 @@ describe "Authentication" do describe "with invalid information" do before { click_button "SIGN IN" } - it { expect(first('title').native.text).to eq "Jamkazam | Sign in" } + it { page.should have_title("Jamkazam | Sign in") } it { should have_selector('div.alert.alert-error', text: 'Invalid') } #describe "after visiting another page" do @@ -35,7 +35,7 @@ describe "Authentication" do end # Successful sign-in goes to the client - it { expect(first('title').native.text).to eq "Jamkazam" } + it { page.should have_title("Jamkazam") } it { should have_selector('h1', text: "Audio Gear Setup") } end end @@ -56,7 +56,7 @@ describe "Authentication" do describe "after signing in" do it "should render the desired protected page" do - expect(first('title').native.text).to eq "Jamkazam | Edit user" + page.should have_title("Jamkazam | Edit user") end describe "when signing in again" do @@ -69,7 +69,7 @@ describe "Authentication" do it "should render the signed-in client page" do # it now goes to /music_sessions - expect(first('title').native.text).to eq "Jamkazam" + page.should have_title("Jamkazam") page.should have_selector('h1', text: "Audio Gear Setup") end end @@ -80,12 +80,12 @@ describe "Authentication" do describe "visiting the edit page" do before { visit edit_user_path(user) } - it { expect(first('title').native.text).to eq "Jamkazam | Sign in" } + it { page.should have_title("Jamkazam | Sign in") } end describe "visiting user index" do before { visit users_path } - it { expect(first('title').native.text).to eq "Jamkazam | Sign in" } + it { page.should have_title("Jamkazam | Sign in") } end end end @@ -99,7 +99,7 @@ describe "Authentication" do before { visit edit_user_path(wrong_user) } it { pending "this should work, but right now you get redirected to ftue" - expect(first('title').native.text).to eq'Action Controller: Exception caught' + page.should have_title('Action Controller: Exception caught') } end end diff --git a/spec/requests/artifacts_api_spec.rb b/spec/requests/artifacts_api_spec.rb index 1c75f1d0a..5a021bbe6 100644 --- a/spec/requests/artifacts_api_spec.rb +++ b/spec/requests/artifacts_api_spec.rb @@ -14,7 +14,7 @@ describe "Artifact API ", :type => :api do it "matches an artifact" do get '/api/versioncheck.json', { :os=>'Win32', :product=>'JamClient'} last_response.status.should eql(200) - JSON.parse(last_response.body).should eql({ "version" => @artifact.version, "uri" => @artifact.uri.path}) + JSON.parse(last_response.body).should eql({ "version" => @artifact.version, "uri" => @artifact.uri.path, "size" => @artifact.size, "sha1" => @artifact.sha1}) end it "matches no artifact" do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 1aad90291..a1ea8a34d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -25,6 +25,7 @@ include JamRuby # put ActionMailer into test mode ActionMailer::Base.delivery_method = :test + Spork.prefork do # Loading more in this block will cause your tests to run faster. However, # if you change any configuration or code from libraries loaded here, you'll @@ -45,6 +46,12 @@ Spork.prefork do end Capybara.javascript_driver = :poltergeist end + Capybara.configure do |config| + config.match = :one + config.exact_options = true + config.ignore_hidden_elements = true + config.visible_text_only = true + end # Requires supporting ruby files with custom matchers and macros, etc, # in spec/support/ and its subdirectories.