Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
ipsecondary_test.py
1 #!/usr/bin/env python3
2 
3 import logging
4 import argparse
5 
6 from os import getcwd, chdir, path
7 
8 from test_fixtures import with_aktualizr, with_uptane_backend, KeyStore, with_secondary, with_treehub,\
9  with_sysroot, with_director
10 
11 logger = logging.getLogger("IPSecondaryTest")
12 
13 
14 # The following is a test suit intended for IP Secondary integration testing
15 @with_uptane_backend()
16 @with_secondary(start=True)
17 @with_aktualizr(start=False, output_logs=False)
18 def test_secondary_update_if_secondary_starts_first(uptane_repo, secondary, aktualizr, **kwargs):
19  '''Test Secondary update if Secondary is booted before Primary'''
20 
21  # add a new image to the repo in order to update the secondary with it
22  secondary_image_filename = "secondary_image_filename_001.img"
23  secondary_image_hash = uptane_repo.add_image(id=secondary.id, image_filename=secondary_image_filename)
24 
25  logger.debug("Trying to update ECU {} with the image {}".
26  format(secondary.id, (secondary_image_hash, secondary_image_filename)))
27 
28  with aktualizr:
29  # run aktualizr once, secondary has been already running
30  aktualizr.wait_for_completion()
31 
32  test_result = secondary_image_hash == aktualizr.get_current_image_info(secondary.id)
33  logger.debug("Update result: {}".format("success" if test_result else "failed"))
34  return test_result
35 
36 
37 @with_uptane_backend()
38 @with_secondary(start=False)
39 @with_aktualizr(start=True, output_logs=False)
40 def test_secondary_update_if_primary_starts_first(uptane_repo, secondary, aktualizr, **kwargs):
41  '''Test Secondary update if Secondary is booted after Primary'''
42 
43  # add a new image to the repo in order to update the secondary with it
44  secondary_image_filename = "secondary_image_filename_001.img"
45  secondary_image_hash = uptane_repo.add_image(id=secondary.id, image_filename=secondary_image_filename)
46 
47  logger.debug("Trying to update ECU {} with the image {}".
48  format(secondary.id, (secondary_image_hash, secondary_image_filename)))
49  with secondary:
50  # start secondary, aktualizr has been already started in 'once' mode
51  aktualizr.wait_for_completion()
52 
53  test_result = secondary_image_hash == aktualizr.get_current_image_info(secondary.id)
54  logger.debug("Update result: {}".format("success" if test_result else "failed"))
55  return test_result
56 
57 
58 @with_uptane_backend()
59 @with_director()
60 @with_secondary(start=False)
61 @with_aktualizr(start=False, output_logs=False)
62 def test_secondary_update(uptane_repo, secondary, aktualizr, director, **kwargs):
63  '''Test Secondary update if a boot order of Secondary and Primary is undefined'''
64 
65  test_result = True
66  # add a new image to the repo in order to update the secondary with it
67  secondary_image_filename = "secondary_image_filename.img"
68  secondary_image_hash = uptane_repo.add_image(id=secondary.id, image_filename=secondary_image_filename)
69 
70  logger.debug("Trying to update ECU {} with the image {}".
71  format(secondary.id, (secondary_image_hash, secondary_image_filename)))
72 
73  # start Secondary and Aktualizr processes, aktualizr is started in 'once' mode
74  with secondary, aktualizr:
75  aktualizr.wait_for_completion()
76 
77  if not director.get_install_result():
78  logger.error("Installation result is not successful")
79  return False
80 
81  # check currently installed hash
82  if secondary_image_hash != aktualizr.get_current_image_info(secondary.id):
83  logger.error("Target image hash doesn't match the currently installed hash")
84  return False
85 
86  # check updated file
87  update_file = path.join(secondary.storage_dir.name, "firmware.txt")
88  if not path.exists(update_file):
89  logger.error("Expected updated file does not exist: {}".format(update_file))
90  return False
91 
92  if secondary_image_filename != director.get_ecu_manifest_filepath(secondary.id[1]):
93  logger.error("Target name doesn't match a filepath value of the reported manifest: {}".format(director.get_manifest()))
94  return False
95 
96  return True
97 
98 
99 @with_treehub()
100 @with_uptane_backend()
101 @with_director()
102 @with_sysroot()
103 @with_secondary(start=False)
104 @with_aktualizr(start=False, run_mode='once', output_logs=True)
105 def test_secondary_ostree_update(uptane_repo, secondary, aktualizr, treehub, sysroot, director, **kwargs):
106  """Test Secondary ostree update if a boot order of Secondary and Primary is undefined"""
107 
108  target_rev = treehub.revision
109  expected_targetname = uptane_repo.add_ostree_target(secondary.id, target_rev, "GARAGE_TARGET_NAME")
110 
111  with secondary:
112  with aktualizr:
113  aktualizr.wait_for_completion()
114 
115  pending_rev = aktualizr.get_current_pending_image_info(secondary.id)
116 
117  if pending_rev != target_rev:
118  logger.error("Pending version {} != the target one {}".format(pending_rev, target_rev))
119  return False
120 
121  sysroot.update_revision(pending_rev)
122  secondary.emulate_reboot()
123 
124  with secondary:
125  with aktualizr:
126  aktualizr.wait_for_completion()
127 
128  if not director.get_install_result():
129  logger.error("Installation result is not successful")
130  return False
131 
132  installed_rev = aktualizr.get_current_image_info(secondary.id)
133 
134  if installed_rev != target_rev:
135  logger.error("Installed version {} != the target one {}".format(installed_rev, target_rev))
136  return False
137 
138  if expected_targetname != director.get_ecu_manifest_filepath(secondary.id[1]):
139  logger.error(
140  "Target name doesn't match a filepath value of the reported manifest: expected: {}, actual: {}".
141  format(expected_targetname, director.get_ecu_manifest_filepath(secondary.id[1])))
142  return False
143 
144  return True
145 
146 
147 @with_uptane_backend()
148 @with_secondary(start=False)
149 @with_aktualizr(start=False, output_logs=False, wait_timeout=0.1)
150 def test_primary_timeout_during_first_run(uptane_repo, secondary, aktualizr, **kwargs):
151  """Test Aktualizr's timeout of waiting for Secondaries during initial boot"""
152 
153  secondary_image_filename = "secondary_image_filename_001.img"
154  secondary_image_hash = uptane_repo.add_image(id=secondary.id, image_filename=secondary_image_filename)
155 
156  logger.debug("Checking Aktualizr behaviour if it timeouts while waiting for a connection from the secondary")
157 
158  # just start the aktualizr and expect that it timeouts on waiting for a connection from the secondary
159  # so the secondary is not registered at the device and backend
160  with aktualizr:
161  aktualizr.wait_for_completion()
162 
163  info = aktualizr.get_info()
164  if info is None:
165  return False
166  not_provisioned = 'Provisioned on server: no' in info
167 
168  return not_provisioned and not aktualizr.is_ecu_registered(secondary.id)
169 
170 
171 @with_uptane_backend()
172 @with_secondary(start=False)
173 @with_aktualizr(start=False, output_logs=False)
174 def test_primary_timeout_after_device_is_registered(uptane_repo, secondary, aktualizr, **kwargs):
175  '''Test Aktualizr's timeout of waiting for Secondaries after the device/aktualizr was registered at the backend'''
176 
177  # run aktualizr and secondary and wait until the device/aktualizr is registered
178  with aktualizr, secondary:
179  aktualizr.wait_for_completion()
180 
181  # the secondary must be registered
182  if not aktualizr.is_ecu_registered(secondary.id):
183  return False
184 
185  # make sure that the secondary is not running
186  if secondary.is_running():
187  return False
188 
189  # run just aktualizr, the previously registered secondary is off
190  # and check if the primary ECU is updatable if the secondary is not connected
191  primary_image_filename = "primary_image_filename_001.img"
192  primary_image_hash = uptane_repo.add_image(id=aktualizr.id, image_filename=primary_image_filename)
193 
194  # if a new image for the not-connected secondary is specified in the target
195  # then nothing is going to be updated, including the image intended for
196  # healthy primary ECU
197  # secondary_image_filename = "secondary_image_filename_001.img"
198  # secondary_image_hash = uptane_repo.add_image(id=secondary.id, image_filename=secondary_image_filename)
199 
200  aktualizr.update_wait_timeout(0.1)
201  with aktualizr:
202  aktualizr.wait_for_completion()
203 
204  return (aktualizr.get_current_primary_image_info() == primary_image_hash)\
205  and not aktualizr.is_ecu_registered(secondary.id)
206 
207 
208 # test suit runner
209 if __name__ == '__main__':
210  logging.basicConfig(level=logging.INFO)
211 
212  parser = argparse.ArgumentParser(description='Test IP Secondary')
213  parser.add_argument('-b', '--build-dir', help='build directory', default='build')
214  parser.add_argument('-s', '--src-dir', help='source directory', default='.')
215  parser.add_argument('-o', '--ostree', help='ostree support', default='OFF')
216 
217  input_params = parser.parse_args()
218 
219  KeyStore.base_dir = path.abspath(input_params.src_dir)
220  initial_cwd = getcwd()
221  chdir(input_params.build_dir)
222 
223  test_suite = [
224  test_secondary_update,
225  test_secondary_update_if_secondary_starts_first,
226  test_secondary_update_if_primary_starts_first,
227  test_primary_timeout_during_first_run,
228  test_primary_timeout_after_device_is_registered
229  ]
230 
231  if input_params.ostree == 'ON':
232  test_suite.append(test_secondary_ostree_update)
233 
234  test_suite_run_result = True
235  for test in test_suite:
236  logger.info('>>> Running {}...'.format(test.__name__))
237  test_run_result = test()
238  logger.info('>>> {}: {}\n'.format('OK' if test_run_result else 'FAILED', test.__name__))
239  test_suite_run_result = test_suite_run_result and test_run_result
240 
241  chdir(initial_cwd)
242  exit(0 if test_suite_run_result else 1)