You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					83 lines
				
				2.5 KiB
			
		
		
			
		
	
	
					83 lines
				
				2.5 KiB
			| 
								 
											5 years ago
										 
									 | 
							
								#!/usr/bin/env python3
							 | 
						||
| 
								 | 
							
								import os
							 | 
						||
| 
								 | 
							
								import shutil
							 | 
						||
| 
								 | 
							
								import subprocess
							 | 
						||
| 
								 | 
							
								import tempfile
							 | 
						||
| 
								 | 
							
								import time
							 | 
						||
| 
								 | 
							
								import unittest
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from common.basedir import BASEDIR
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								UPDATER_PATH = os.path.join(BASEDIR, "installer/updater")
							 | 
						||
| 
								 | 
							
								UPDATER = os.path.join(UPDATER_PATH, "updater")
							 | 
						||
| 
								 | 
							
								UPDATE_MANIFEST = os.path.join(UPDATER_PATH, "update.json")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class TestUpdater(unittest.TestCase):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  @classmethod
							 | 
						||
| 
								 | 
							
								  def setUpClass(cls):
							 | 
						||
| 
								 | 
							
								    # test that the updater builds
							 | 
						||
| 
								 | 
							
								    cls.assertTrue(f"cd {UPDATER_PATH} && make clean && make", "updater failed to build")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # restore the checked-in version, since that's what actually runs on devices
							 | 
						||
| 
								 | 
							
								    os.system(f"git reset --hard {UPDATER_PATH}")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def setUp(self):
							 | 
						||
| 
								 | 
							
								    self._clear_dir()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def tearDown(self):
							 | 
						||
| 
								 | 
							
								    self._clear_dir()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def _clear_dir(self):
							 | 
						||
| 
								 | 
							
								    if os.path.isdir("/data/neoupdate"):
							 | 
						||
| 
								 | 
							
								      shutil.rmtree("/data/neoupdate")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def _assert_ok(self, cmd, msg=None):
							 | 
						||
| 
								 | 
							
								    self.assertTrue(os.system(cmd) == 0, msg)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def _assert_fails(self, cmd):
							 | 
						||
| 
								 | 
							
								    self.assertFalse(os.system(cmd) == 0)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def test_background_download(self):
							 | 
						||
| 
								 | 
							
								    self._assert_ok(f"{UPDATER} bgcache 'file://{UPDATE_MANIFEST}'")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def test_background_download_bad_manifest(self):
							 | 
						||
| 
								 | 
							
								    # update with bad manifest should fail
							 | 
						||
| 
								 | 
							
								    with tempfile.NamedTemporaryFile(mode="w", suffix=".json") as f:
							 | 
						||
| 
								 | 
							
								      f.write("{}")
							 | 
						||
| 
								 | 
							
								      self._assert_fails(f"{UPDATER} bgcache 'file://{f.name}'")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def test_cache_resume(self):
							 | 
						||
| 
								 | 
							
								    self._assert_ok(f"{UPDATER} bgcache 'file://{UPDATE_MANIFEST}'")
							 | 
						||
| 
								 | 
							
								    # a full download takes >1m, but resuming from fully cached should only be a few seconds
							 | 
						||
| 
								 | 
							
								    start_time = time.monotonic()
							 | 
						||
| 
								 | 
							
								    self._assert_ok(f"{UPDATER} bgcache 'file://{UPDATE_MANIFEST}'")
							 | 
						||
| 
								 | 
							
								    self.assertLess(time.monotonic() - start_time, 10)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  # make sure we can recover from corrupt downloads
							 | 
						||
| 
								 | 
							
								  def test_recover_from_corrupt(self):
							 | 
						||
| 
								 | 
							
								    # download the whole update
							 | 
						||
| 
								 | 
							
								    self._assert_ok(f"{UPDATER} bgcache 'file://{UPDATE_MANIFEST}'")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # write some random bytes
							 | 
						||
| 
								 | 
							
								    for f in os.listdir("/data/neoupdate"):
							 | 
						||
| 
								 | 
							
								      with open(os.path.join("/data/neoupdate", f), "ab") as f:
							 | 
						||
| 
								 | 
							
								        f.write(b"\xab"*20)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # this attempt should fail, then it unlinks
							 | 
						||
| 
								 | 
							
								    self._assert_fails(f"{UPDATER} bgcache 'file://{UPDATE_MANIFEST}'")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # now it should pass
							 | 
						||
| 
								 | 
							
								    self._assert_ok(f"{UPDATER} bgcache 'file://{UPDATE_MANIFEST}'")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  # simple test that the updater doesn't crash in UI mode
							 | 
						||
| 
								 | 
							
								  def test_ui_init(self):
							 | 
						||
| 
								 | 
							
								    with subprocess.Popen(UPDATER) as proc:
							 | 
						||
| 
								 | 
							
								      time.sleep(5)
							 | 
						||
| 
								 | 
							
								      self.assertTrue(proc.poll() is None)
							 | 
						||
| 
								 | 
							
								      proc.terminate()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if __name__ == "__main__":
							 | 
						||
| 
								 | 
							
								  unittest.main()
							 |