FIX: issue 1538. After upgrading and before a new version check request has been made, dashboard might still say that an update is available.

This commit is contained in:
Neil Lalonde 2013-11-04 12:51:01 -05:00
parent 5e69b277ea
commit ede59a4386
10 changed files with 133 additions and 75 deletions

View File

@ -13,7 +13,7 @@ Discourse.VersionCheck = Discourse.Model.extend({
}.property('updated_at'), }.property('updated_at'),
dataIsOld: function() { dataIsOld: function() {
return moment().diff(moment(this.get('updated_at')), 'hours') >= 48; return this.get('version_check_pending') || moment().diff(moment(this.get('updated_at')), 'hours') >= 48;
}.property('updated_at'), }.property('updated_at'),
staleData: function() { staleData: function() {

View File

@ -62,16 +62,26 @@
{{#if versionCheck.staleData}} {{#if versionCheck.staleData}}
<td class="version-number">&nbsp;</td> <td class="version-number">&nbsp;</td>
<td class="face"> <td class="face">
<span class="icon critical-updates-available">☹</span> {{#if versionCheck.version_check_pending}}
<span class='icon up-to-date'>☻</span>
{{else}}
<span class="icon critical-updates-available">☹</span>
{{/if}}
</td> </td>
<td class="version-notes"> <td class="version-notes">
<span class="normal-note">{{i18n admin.dashboard.stale_data}}</span> <span class="normal-note">
{{#if versionCheck.version_check_pending}}
{{i18n admin.dashboard.version_check_pending}}
{{else}}
{{i18n admin.dashboard.stale_data}}
{{/if}}
</span>
</td> </td>
{{else}} {{else}}
<td class="version-number">{{ versionCheck.latest_version }}</td> <td class="version-number">{{ versionCheck.latest_version }}</td>
<td class="face"> <td class="face">
{{#if versionCheck.upToDate }} {{#if versionCheck.upToDate }}
<span class='icon update-to-date'>☻</span> <span class='icon up-to-date'>☻</span>
{{else}} {{else}}
<span {{bindAttr class=":icon versionCheck.critical_updates:critical-updates-available:updates-available"}}> <span {{bindAttr class=":icon versionCheck.critical_updates:critical-updates-available:updates-available"}}>
{{#if versionCheck.behindByOneVersion}} {{#if versionCheck.behindByOneVersion}}

View File

@ -382,7 +382,7 @@ table {
font-size: 26px; font-size: 26px;
} }
.update-to-date { .up-to-date {
color: green; color: green;
} }
.updates-available { .updates-available {

View File

@ -11,6 +11,7 @@ module Jobs
should_send_email = (SiteSetting.new_version_emails and DiscourseUpdates.missing_versions_count and DiscourseUpdates.missing_versions_count == 0) should_send_email = (SiteSetting.new_version_emails and DiscourseUpdates.missing_versions_count and DiscourseUpdates.missing_versions_count == 0)
json = DiscourseHub.discourse_version_check json = DiscourseHub.discourse_version_check
DiscourseUpdates.last_installed_version = Discourse::VERSION::STRING
DiscourseUpdates.latest_version = json['latestVersion'] DiscourseUpdates.latest_version = json['latestVersion']
DiscourseUpdates.critical_updates_available = json['criticalUpdates'] DiscourseUpdates.critical_updates_available = json['criticalUpdates']
DiscourseUpdates.missing_versions_count = json['missingVersionsCount'] DiscourseUpdates.missing_versions_count = json['missingVersionsCount']

View File

@ -7,7 +7,7 @@ class DiscourseVersionCheck
include ActiveModel::Serialization include ActiveModel::Serialization
end end
attr_accessor :latest_version, :critical_updates, :installed_version, :installed_sha, :missing_versions_count, :updated_at attr_accessor :latest_version, :critical_updates, :installed_version, :installed_sha, :missing_versions_count, :updated_at, :version_check_pending
unless rails4? unless rails4?
def active_model_serializer def active_model_serializer

View File

@ -1090,6 +1090,7 @@ en:
please_upgrade: "Please upgrade!" please_upgrade: "Please upgrade!"
no_check_performed: "A check for updates has not been performed. Ensure sidekiq is running." no_check_performed: "A check for updates has not been performed. Ensure sidekiq is running."
stale_data: "A check for updates has not been performed lately. Ensure sidekiq is running." stale_data: "A check for updates has not been performed lately. Ensure sidekiq is running."
version_check_pending: "Looks like you upgraded recently. Fantastic!"
installed_version: "Installed" installed_version: "Installed"
latest_version: "Latest" latest_version: "Latest"
problems_found: "Some problems have been found with your installation of Discourse:" problems_found: "Some problems have been found with your installation of Discourse:"

View File

@ -24,20 +24,27 @@ module DiscourseUpdates
# Handle cases when version check data is old so we report something that makes sense # Handle cases when version check data is old so we report something that makes sense
if (version_info.updated_at.nil? or if (version_info.updated_at.nil? or # never performed a version check
(version_info.missing_versions_count == 0 and version_info.latest_version != version_info.installed_version) or last_installed_version != Discourse::VERSION::STRING or # upgraded since the last version check
(version_info.missing_versions_count != 0 and version_info.latest_version == version_info.installed_version)) (version_info.missing_versions_count == 0 and version_info.latest_version != version_info.installed_version) or # old data
(version_info.missing_versions_count != 0 and version_info.latest_version == version_info.installed_version)) # old data
Jobs.enqueue(:version_check, all_sites: true) Jobs.enqueue(:version_check, all_sites: true)
end version_info.version_check_pending = true
unless version_info.updated_at.nil?
if !version_info.updated_at.nil? and version_info.latest_version == version_info.installed_version version_info.missing_versions_count = 0
version_info.missing_versions_count = 0 version_info.critical_updates = false
end
end end
end end
version_info version_info
end end
# last_installed_version is the installed version at the time of the last version check
def last_installed_version
$redis.get last_installed_version_key
end
def latest_version def latest_version
$redis.get latest_version_key $redis.get latest_version_key
end end
@ -59,7 +66,7 @@ module DiscourseUpdates
$redis.set updated_at_key, time_with_zone.as_json $redis.set updated_at_key, time_with_zone.as_json
end end
['latest_version', 'missing_versions_count', 'critical_updates_available'].each do |name| ['last_installed_version', 'latest_version', 'missing_versions_count', 'critical_updates_available'].each do |name|
eval "define_method :#{name}= do |arg| eval "define_method :#{name}= do |arg|
$redis.set #{name}_key, arg $redis.set #{name}_key, arg
end" end"
@ -68,6 +75,10 @@ module DiscourseUpdates
private private
def last_installed_version_key
'last_installed_version'
end
def latest_version_key def latest_version_key
'discourse_latest_version' 'discourse_latest_version'
end end

View File

@ -16,75 +16,103 @@ describe DiscourseUpdates do
subject { DiscourseUpdates.check_version.as_json } subject { DiscourseUpdates.check_version.as_json }
context 'a good version check request happened recently' do context 'version check was done at the current installed version' do
context 'and server is up-to-date' do before do
before { stub_data(Discourse::VERSION::STRING, 0, false, 12.hours.ago) } DiscourseUpdates.stubs(:last_installed_version).returns(Discourse::VERSION::STRING)
end
it 'returns all the version fields' do context 'a good version check request happened recently' do
subject['latest_version'].should == Discourse::VERSION::STRING context 'and server is up-to-date' do
subject['missing_versions_count'].should == 0 before { stub_data(Discourse::VERSION::STRING, 0, false, 12.hours.ago) }
subject['critical_updates'].should == false
it 'returns all the version fields' do
subject['latest_version'].should == Discourse::VERSION::STRING
subject['missing_versions_count'].should == 0
subject['critical_updates'].should == false
subject['installed_version'].should == Discourse::VERSION::STRING
end
it 'returns the timestamp of the last version check' do
subject['updated_at'].should be_within_one_second_of(12.hours.ago)
end
end
context 'and server is not up-to-date' do
before { stub_data('0.9.0', 2, false, 12.hours.ago) }
it 'returns all the version fields' do
subject['latest_version'].should == '0.9.0'
subject['missing_versions_count'].should == 2
subject['critical_updates'].should == false
subject['installed_version'].should == Discourse::VERSION::STRING
end
it 'returns the timestamp of the last version check' do
subject['updated_at'].should be_within_one_second_of(12.hours.ago)
end
end
end
context 'a version check has never been performed' do
before { stub_data(nil, nil, false, nil) }
it 'returns the installed version' do
subject['installed_version'].should == Discourse::VERSION::STRING subject['installed_version'].should == Discourse::VERSION::STRING
end end
it 'returns the timestamp of the last version check' do it 'indicates that version check has not been performed' do
subject['updated_at'].should be_within_one_second_of(12.hours.ago) subject.should have_key('updated_at')
subject['updated_at'].should == nil
end
it 'does not return latest version info' do
subject.should_not have_key('latest_version')
subject.should_not have_key('missing_versions_count')
subject.should_not have_key('critical_updates')
end
it 'queues a version check' do
Jobs.expects(:enqueue).with(:version_check, anything)
subject
end end
end end
context 'and server is not up-to-date' do # These cases should never happen anymore, but keep the specs to be sure
before { stub_data('0.9.0', 2, false, 12.hours.ago) } # they're handled in a sane way.
context 'old version check data' do
shared_examples "queue version check and report that version is ok" do
it 'queues a version check' do
Jobs.expects(:enqueue).with(:version_check, anything)
subject
end
it 'returns all the version fields' do it 'reports 0 missing versions' do
subject['latest_version'].should == '0.9.0' subject['missing_versions_count'].should == 0
subject['missing_versions_count'].should == 2 end
subject['critical_updates'].should == false
subject['installed_version'].should == Discourse::VERSION::STRING it 'reports that a version check will be run soon' do
subject['version_check_pending'].should == true
end
end end
it 'returns the timestamp of the last version check' do context 'installed is latest' do
subject['updated_at'].should be_within_one_second_of(12.hours.ago) before { stub_data(Discourse::VERSION::STRING, 1, false, 8.hours.ago) }
include_examples "queue version check and report that version is ok"
end
context 'installed does not match latest version, but missing_versions_count is 0' do
before { stub_data('0.10.10.123', 0, false, 8.hours.ago) }
include_examples "queue version check and report that version is ok"
end end
end end
end end
context 'a version check has never been performed' do context 'version check was done at a different installed version' do
before { stub_data(nil, nil, false, nil) } before do
DiscourseUpdates.stubs(:last_installed_version).returns('0.9.1')
it 'returns the installed version' do
subject['installed_version'].should == Discourse::VERSION::STRING
end end
it 'indicates that version check has not been performed' do shared_examples "when last_installed_version is old" do
subject.should have_key('updated_at')
subject['updated_at'].should == nil
end
it 'does not return latest version info' do
subject.should_not have_key('latest_version')
subject.should_not have_key('missing_versions_count')
subject.should_not have_key('critical_updates')
end
it 'queues a version check' do
Jobs.expects(:enqueue).with(:version_check, anything)
subject
end
end
context 'installed version is newer' do
before { stub_data('0.9.3', 0, false, 28.hours.ago) }
it 'queues a version check' do
Jobs.expects(:enqueue).with(:version_check, anything)
subject
end
end
context 'old version check data' do
context 'installed is latest' do
before { stub_data(Discourse::VERSION::STRING, 1, false, 8.hours.ago) }
it 'queues a version check' do it 'queues a version check' do
Jobs.expects(:enqueue).with(:version_check, anything) Jobs.expects(:enqueue).with(:version_check, anything)
subject subject
@ -93,16 +121,20 @@ describe DiscourseUpdates do
it 'reports 0 missing versions' do it 'reports 0 missing versions' do
subject['missing_versions_count'].should == 0 subject['missing_versions_count'].should == 0
end end
end
context 'installed is not latest' do it 'reports that a version check will be run soon' do
before { stub_data('0.9.1', 0, false, 8.hours.ago) } subject['version_check_pending'].should == true
it 'queues a version check' do
Jobs.expects(:enqueue).with(:version_check, anything)
subject
end end
end end
end
context 'missing_versions_count is 0' do
before { stub_data('0.9.7', 0, false, 8.hours.ago) }
include_examples "when last_installed_version is old"
end
context 'missing_versions_count is not 0' do
before { stub_data('0.9.7', 1, false, 8.hours.ago) }
include_examples "when last_installed_version is old"
end
end
end end

View File

@ -4,6 +4,7 @@ require_dependency 'version'
describe Admin::VersionsController do describe Admin::VersionsController do
before do before do
Jobs::VersionCheck.any_instance.stubs(:execute).returns(true)
DiscourseUpdates.stubs(:updated_at).returns(2.hours.ago) DiscourseUpdates.stubs(:updated_at).returns(2.hours.ago)
DiscourseUpdates.stubs(:latest_version).returns('1.2.33') DiscourseUpdates.stubs(:latest_version).returns('1.2.33')
DiscourseUpdates.stubs(:critical_updates_available?).returns(false) DiscourseUpdates.stubs(:critical_updates_available?).returns(false)

View File

@ -7,6 +7,7 @@ test('dataIsOld', function() {
dataIsOld({updated_at: moment().subtract('hours', 2).toJSON()}, false, '2 hours ago'); dataIsOld({updated_at: moment().subtract('hours', 2).toJSON()}, false, '2 hours ago');
dataIsOld({updated_at: moment().subtract('hours', 49).toJSON()}, true, '49 hours ago'); dataIsOld({updated_at: moment().subtract('hours', 49).toJSON()}, true, '49 hours ago');
dataIsOld({updated_at: moment().subtract('hours', 2).toJSON(), version_check_pending: true}, true, 'version check pending');
}); });
test('staleData', function() { test('staleData', function() {
@ -21,4 +22,5 @@ test('staleData', function() {
staleData({missing_versions_count: 0, installed_version: '0.9.4', latest_version: '0.9.3', updated_at: updatedAt(2)}, true, 'installed and latest do not match, but missing_versions_count is 0'); staleData({missing_versions_count: 0, installed_version: '0.9.4', latest_version: '0.9.3', updated_at: updatedAt(2)}, true, 'installed and latest do not match, but missing_versions_count is 0');
staleData({missing_versions_count: 1, installed_version: '0.9.3', latest_version: '0.9.3', updated_at: updatedAt(2)}, true, 'installed and latest match, but missing_versions_count is not 0'); staleData({missing_versions_count: 1, installed_version: '0.9.3', latest_version: '0.9.3', updated_at: updatedAt(2)}, true, 'installed and latest match, but missing_versions_count is not 0');
staleData({missing_versions_count: 0, installed_version: '0.9.3', latest_version: '0.9.3', updated_at: updatedAt(50)}, true, 'old version check data'); staleData({missing_versions_count: 0, installed_version: '0.9.3', latest_version: '0.9.3', updated_at: updatedAt(50)}, true, 'old version check data');
staleData({version_check_pending: true, missing_versions_count: 0, installed_version: '0.9.4', latest_version: '0.9.3', updated_at: updatedAt(2)}, true, 'version was upgraded, but no version check has been done since the upgrade');
}); });