tem_multi_updater 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1 +1,3 @@
1
+ v0.2. Complete test coverage.
2
+
1
3
  v0.1. Initial release.
data/Manifest CHANGED
@@ -6,3 +6,5 @@ Rakefile
6
6
  bin/tem_multi_update_fw
7
7
  lib/tem_multi_updater.rb
8
8
  lib/tem_multi_updater/updater.rb
9
+ test/integration_test.rb
10
+ test/updater_test.rb
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
- transport = Smartcard::Iso::AutoConfigurator.try_transport transport_config
65
- if transport
66
- @logger.info "Connected to #{transport.inspect}"
67
- update_transport transport
68
- else
69
- @logger.warn "Failed connecting to #{transport_config.inspect}"
70
- end
71
-
72
- @pending_mx.synchronize do
73
- @pending -= 1
74
- @pending_cv.signal
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
- # No firmware will be uploaded if the smart-card already has the latest
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
 
@@ -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.1"
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.1"
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