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 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