tem_multi_updater 0.1 → 0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +2 -0
- data/Manifest +2 -0
- data/Rakefile +2 -0
- data/lib/tem_multi_updater/updater.rb +37 -15
- data/tem_multi_updater.gemspec +9 -2
- data/test/integration_test.rb +52 -0
- data/test/updater_test.rb +106 -0
- metadata +26 -3
data/CHANGELOG
CHANGED
data/Manifest
CHANGED
data/Rakefile
CHANGED
@@ -19,6 +19,8 @@ Echoe.new('tem_multi_updater') do |p|
|
|
19
19
|
p.dependencies = ['smartcard >=0.4.7',
|
20
20
|
'tem_multi_proxy >=0.2.5',
|
21
21
|
'tem_ruby >=0.12.0']
|
22
|
+
p.development_dependencies = ['echoe >=3.2',
|
23
|
+
'flexmock >=0.8.6']
|
22
24
|
|
23
25
|
p.need_tar_gz = !Gem.win_platform?
|
24
26
|
p.need_zip = !Gem.win_platform?
|
@@ -29,11 +29,16 @@ class Updater
|
|
29
29
|
def run
|
30
30
|
return unless @pending.nil?
|
31
31
|
|
32
|
-
@logger.info "Querying #{@server_addr}"
|
32
|
+
@logger.info "Querying tem_multi_proxy at #{@server_addr}"
|
33
33
|
@transport_configs = Tem::MultiProxy::Client.query_tems @server_addr
|
34
|
+
if @transport_configs.nil? || @transport_configs.empty?
|
35
|
+
@logger.error "No response from tem_multi_proxy at #{@server_addr}"
|
36
|
+
return false
|
37
|
+
end
|
34
38
|
|
35
39
|
spawn_threads
|
36
40
|
wait_for_threads
|
41
|
+
return true
|
37
42
|
end
|
38
43
|
|
39
44
|
# Spawns one updating thread for each smart-card transport configuration.
|
@@ -61,40 +66,57 @@ class Updater
|
|
61
66
|
# Args:
|
62
67
|
# transport_config:: configuration for the TEM's smart-card transport
|
63
68
|
def update_thread(transport_config)
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
@
|
69
|
+
begin
|
70
|
+
transport = transport_for_config transport_config
|
71
|
+
if transport
|
72
|
+
@logger.info "Connected to #{transport.inspect}"
|
73
|
+
update_transport transport
|
74
|
+
transport.disconnect
|
75
|
+
else
|
76
|
+
@logger.warn "Failed connecting to #{transport_config.inspect}"
|
77
|
+
end
|
78
|
+
ensure
|
79
|
+
@pending_mx.synchronize do
|
80
|
+
@pending -= 1
|
81
|
+
@pending_cv.signal
|
82
|
+
end
|
75
83
|
end
|
76
84
|
end
|
77
85
|
|
86
|
+
# Creates a ISO smart-card transport out of a configuration.
|
87
|
+
#
|
88
|
+
# Args:
|
89
|
+
# transport_config:: configuration for the TEM's smart-card transport
|
90
|
+
#
|
91
|
+
# Returns a transport.
|
92
|
+
def transport_for_config(transport_config)
|
93
|
+
Smartcard::Iso::AutoConfigurator.try_transport transport_config
|
94
|
+
end
|
95
|
+
|
78
96
|
# Installs or updates TEM firmware on a smart-card.
|
79
97
|
#
|
98
|
+
# No firmware will be uploaded if the smart-card already has the latest
|
99
|
+
# version of the TEM software.
|
100
|
+
#
|
80
101
|
# Args:
|
81
102
|
# transport_config:: smart-card transport connecting to the TEM card
|
82
103
|
#
|
83
|
-
#
|
84
|
-
# version of the TEM software.
|
104
|
+
# Returns
|
85
105
|
def update_transport(transport)
|
86
106
|
if !needs_update? transport
|
87
107
|
@logger.info "No update needed at #{transport.inspect}"
|
88
|
-
return
|
108
|
+
return false
|
89
109
|
end
|
90
110
|
|
91
111
|
@logger.info "Uploading TEM firmware to #{transport.inspect}"
|
92
112
|
begin
|
93
113
|
Tem::Firmware::Uploader.upload_cap transport
|
114
|
+
return true
|
94
115
|
rescue Exception => e
|
95
116
|
@logger.error "Error while uploading TEM firmware to " +
|
96
117
|
"#{transport.inspect} - #{e.class.name}: #{e.message}"
|
97
118
|
@logger.info e.backtrace.join("\n")
|
119
|
+
return false
|
98
120
|
end
|
99
121
|
end
|
100
122
|
|
data/tem_multi_updater.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{tem_multi_updater}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.2"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Victor Costan"]
|
@@ -12,13 +12,14 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.email = %q{victor@costan.us}
|
13
13
|
s.executables = ["tem_multi_update_fw"]
|
14
14
|
s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README", "bin/tem_multi_update_fw", "lib/tem_multi_updater.rb", "lib/tem_multi_updater/updater.rb"]
|
15
|
-
s.files = ["CHANGELOG", "LICENSE", "Manifest", "README", "Rakefile", "bin/tem_multi_update_fw", "lib/tem_multi_updater.rb", "lib/tem_multi_updater/updater.rb", "tem_multi_updater.gemspec"]
|
15
|
+
s.files = ["CHANGELOG", "LICENSE", "Manifest", "README", "Rakefile", "bin/tem_multi_update_fw", "lib/tem_multi_updater.rb", "lib/tem_multi_updater/updater.rb", "test/integration_test.rb", "test/updater_test.rb", "tem_multi_updater.gemspec"]
|
16
16
|
s.homepage = %q{http://tem.rubyforge.org}
|
17
17
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Tem_multi_updater", "--main", "README"]
|
18
18
|
s.require_paths = ["lib"]
|
19
19
|
s.rubyforge_project = %q{tem}
|
20
20
|
s.rubygems_version = %q{1.3.5}
|
21
21
|
s.summary = %q{Updates the firmware on all TEMs connected to a tem_multi_proxy.}
|
22
|
+
s.test_files = ["test/integration_test.rb", "test/updater_test.rb"]
|
22
23
|
|
23
24
|
if s.respond_to? :specification_version then
|
24
25
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
@@ -28,14 +29,20 @@ Gem::Specification.new do |s|
|
|
28
29
|
s.add_runtime_dependency(%q<smartcard>, [">= 0.4.7"])
|
29
30
|
s.add_runtime_dependency(%q<tem_multi_proxy>, [">= 0.2.5"])
|
30
31
|
s.add_runtime_dependency(%q<tem_ruby>, [">= 0.12.0"])
|
32
|
+
s.add_development_dependency(%q<echoe>, [">= 3.2"])
|
33
|
+
s.add_development_dependency(%q<flexmock>, [">= 0.8.6"])
|
31
34
|
else
|
32
35
|
s.add_dependency(%q<smartcard>, [">= 0.4.7"])
|
33
36
|
s.add_dependency(%q<tem_multi_proxy>, [">= 0.2.5"])
|
34
37
|
s.add_dependency(%q<tem_ruby>, [">= 0.12.0"])
|
38
|
+
s.add_dependency(%q<echoe>, [">= 3.2"])
|
39
|
+
s.add_dependency(%q<flexmock>, [">= 0.8.6"])
|
35
40
|
end
|
36
41
|
else
|
37
42
|
s.add_dependency(%q<smartcard>, [">= 0.4.7"])
|
38
43
|
s.add_dependency(%q<tem_multi_proxy>, [">= 0.2.5"])
|
39
44
|
s.add_dependency(%q<tem_ruby>, [">= 0.12.0"])
|
45
|
+
s.add_dependency(%q<echoe>, [">= 3.2"])
|
46
|
+
s.add_dependency(%q<flexmock>, [">= 0.8.6"])
|
40
47
|
end
|
41
48
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# Author:: Victor Costan
|
2
|
+
# Copyright:: Copyright (C) 2009 Massachusetts Institute of Technology
|
3
|
+
# License:: MIT
|
4
|
+
|
5
|
+
require 'tem_multi_updater'
|
6
|
+
|
7
|
+
require 'logger'
|
8
|
+
require 'stringio'
|
9
|
+
require 'test/unit'
|
10
|
+
|
11
|
+
class IntegrationTest < Test::Unit::TestCase
|
12
|
+
def setup
|
13
|
+
super
|
14
|
+
@server_addr = 'localhost'
|
15
|
+
logger = Logger.new StringIO.new
|
16
|
+
@updater = Tem::MultiUpdater::Updater.new logger, @server_addr
|
17
|
+
|
18
|
+
@old_abort = Thread.abort_on_exception
|
19
|
+
Thread.abort_on_exception = true
|
20
|
+
end
|
21
|
+
|
22
|
+
def teardown
|
23
|
+
Thread.abort_on_exception = @old_abort
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_live
|
28
|
+
# Remove the TEM firmware from the first card to force an update.
|
29
|
+
transport_configs = Tem::MultiProxy::Client.query_tems @server_addr
|
30
|
+
assert transport_configs, "#{@server_addr} test proxy is not live"
|
31
|
+
assert !transport_configs.empty?, "#{@server_addr} test proxy has no cards"
|
32
|
+
card = @updater.transport_for_config transport_configs[0]
|
33
|
+
assert card,
|
34
|
+
"Cannot connect to the first card on the #{@server_addr} test proxy"
|
35
|
+
class <<card; include Smartcard::Gp::GpCardMixin; end
|
36
|
+
card.delete_application Tem::Firmware::Uploader.applet_aid
|
37
|
+
card.disconnect
|
38
|
+
|
39
|
+
# Run the whole update code against a live proxy.
|
40
|
+
assert_equal true, @updater.run,
|
41
|
+
'Integration test needs a live tem_multi_proxy at localhost'
|
42
|
+
|
43
|
+
# Check that the first card has the TEM firmware now.
|
44
|
+
card = @updater.transport_for_config transport_configs[0]
|
45
|
+
assert card, 'Transport error on the card whose TEM firmware was removed'
|
46
|
+
tem = Tem::Session.new card
|
47
|
+
assert_equal Tem::Firmware::Uploader.fw_version, tem.fw_version,
|
48
|
+
'Incorrect TEM firmware version'
|
49
|
+
tem.disconnect
|
50
|
+
card.disconnect
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# Author:: Victor Costan
|
2
|
+
# Copyright:: Copyright (C) 2009 Massachusetts Institute of Technology
|
3
|
+
# License:: MIT
|
4
|
+
|
5
|
+
require 'tem_multi_updater'
|
6
|
+
|
7
|
+
require 'logger'
|
8
|
+
require 'stringio'
|
9
|
+
require 'test/unit'
|
10
|
+
|
11
|
+
require 'rubygems'
|
12
|
+
require 'flexmock/test_unit'
|
13
|
+
|
14
|
+
class UpdaterTest < Test::Unit::TestCase
|
15
|
+
def setup
|
16
|
+
super
|
17
|
+
@server_addr = :server_addr
|
18
|
+
@updater = Tem::MultiUpdater::Updater.new Logger.new(StringIO.new),
|
19
|
+
@server_addr
|
20
|
+
@old_abort = Thread.abort_on_exception
|
21
|
+
Thread.abort_on_exception = true
|
22
|
+
end
|
23
|
+
|
24
|
+
def teardown
|
25
|
+
Thread.abort_on_exception = @old_abort
|
26
|
+
super
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_dead_proxy
|
30
|
+
flexmock(Tem::MultiProxy::Client).should_receive(:query_tems).
|
31
|
+
with(@server_addr).and_return(nil)
|
32
|
+
assert_equal false, @updater.run
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_threading
|
36
|
+
flexmock(Tem::MultiProxy::Client).should_receive(:query_tems).
|
37
|
+
with(@server_addr).and_return([:transport1, :transport2, :transport3])
|
38
|
+
['1', '2', '3'].each do |suffix|
|
39
|
+
tem = Object.new
|
40
|
+
flexmock(Smartcard::Iso::AutoConfigurator).should_receive(:try_transport).
|
41
|
+
with(:"transport#{suffix}").and_return(tem).once
|
42
|
+
flexmock(@updater).should_receive(:update_transport).once.
|
43
|
+
with(tem).and_return { Kernel.sleep 0.4 + 0.1 * suffix.to_i; true }
|
44
|
+
flexmock(tem).should_receive(:disconnect).once
|
45
|
+
end
|
46
|
+
|
47
|
+
time0 = Time.now
|
48
|
+
assert_equal true, @updater.run, 'run return value'
|
49
|
+
assert_operator 0.9, :>, Time.now - time0, 'Updates happened in parallel'
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_update_transport
|
53
|
+
flexmock(@updater).should_receive(:needs_update?).with(:new_transport).
|
54
|
+
and_return(false).once
|
55
|
+
flexmock(Tem::Firmware::Uploader).should_receive(:upload_cap).
|
56
|
+
with(:new_transport).never
|
57
|
+
assert_equal false, @updater.update_transport(:new_transport),
|
58
|
+
'Up-to-date smartcard'
|
59
|
+
|
60
|
+
flexmock(@updater).should_receive(:needs_update?).with(:old_transport).
|
61
|
+
and_return(true).once
|
62
|
+
flexmock(Tem::Firmware::Uploader).should_receive(:upload_cap).
|
63
|
+
with(:old_transport).once
|
64
|
+
assert_equal true, @updater.update_transport(:old_transport),
|
65
|
+
'Outdated smartcard'
|
66
|
+
|
67
|
+
flexmock(@updater).should_receive(:needs_update?).with(:err_transport).
|
68
|
+
and_return(true).once
|
69
|
+
flexmock(Tem::Firmware::Uploader).should_receive(:upload_cap).
|
70
|
+
with(:err_transport).once.
|
71
|
+
and_raise(Smartcard::Iso::ApduError, {:data => [], :status => 0x6A88})
|
72
|
+
assert_equal false, @updater.update_transport(:err_transport),
|
73
|
+
'Flaly smartcard'
|
74
|
+
end
|
75
|
+
|
76
|
+
def _test_needs_update(version, answer)
|
77
|
+
session = Object.new
|
78
|
+
if version.has_key? :status
|
79
|
+
flexmock(Tem::Session).should_receive(:new).
|
80
|
+
and_raise(Smartcard::Iso::ApduError, version).once
|
81
|
+
else
|
82
|
+
flexmock(Tem::Session).should_receive(:new).with(:transport).
|
83
|
+
and_return(session).once
|
84
|
+
flexmock(session).should_receive(:fw_version).and_return(version).once
|
85
|
+
end
|
86
|
+
|
87
|
+
assert_equal answer, @updater.needs_update?(:transport), version.inspect
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_needs_update
|
91
|
+
fw_version = Tem::Firmware::Uploader.fw_version
|
92
|
+
|
93
|
+
[
|
94
|
+
[{:major => fw_version[:major] + 1, :minor => 0}, false],
|
95
|
+
[{:major => fw_version[:major] - 1, :minor => 256}, true],
|
96
|
+
[{:major => fw_version[:major], :minor => 0}, true],
|
97
|
+
[{:major => fw_version[:major], :minor => 256}, false],
|
98
|
+
[{:major => fw_version[:major], :minor => fw_version[:minor] - 1}, true],
|
99
|
+
[{:major => fw_version[:major], :minor => fw_version[:minor]}, false],
|
100
|
+
[{:major => fw_version[:major], :minor => fw_version[:minor] + 1}, false],
|
101
|
+
[{:data => [], :status => 0x6A88}, true],
|
102
|
+
].each do |test_case|
|
103
|
+
_test_needs_update *test_case
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tem_multi_updater
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "0.
|
4
|
+
version: "0.2"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Victor Costan
|
@@ -42,6 +42,26 @@ dependencies:
|
|
42
42
|
- !ruby/object:Gem::Version
|
43
43
|
version: 0.12.0
|
44
44
|
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: echoe
|
47
|
+
type: :development
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "3.2"
|
54
|
+
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: flexmock
|
57
|
+
type: :development
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 0.8.6
|
64
|
+
version:
|
45
65
|
description: Updates the firmware on all TEMs connected to a tem_multi_proxy.
|
46
66
|
email: victor@costan.us
|
47
67
|
executables:
|
@@ -64,6 +84,8 @@ files:
|
|
64
84
|
- bin/tem_multi_update_fw
|
65
85
|
- lib/tem_multi_updater.rb
|
66
86
|
- lib/tem_multi_updater/updater.rb
|
87
|
+
- test/integration_test.rb
|
88
|
+
- test/updater_test.rb
|
67
89
|
- tem_multi_updater.gemspec
|
68
90
|
has_rdoc: true
|
69
91
|
homepage: http://tem.rubyforge.org
|
@@ -98,5 +120,6 @@ rubygems_version: 1.3.5
|
|
98
120
|
signing_key:
|
99
121
|
specification_version: 3
|
100
122
|
summary: Updates the firmware on all TEMs connected to a tem_multi_proxy.
|
101
|
-
test_files:
|
102
|
-
|
123
|
+
test_files:
|
124
|
+
- test/integration_test.rb
|
125
|
+
- test/updater_test.rb
|