木曜日 4:20 p.m.–4:50 p.m.
Room 202 #pyconjp_202Pausable Unittest on EFI Stackless Python
Masamitsu Murase
- 対象レベル:
- 中級
- カテゴリ:
- Embedded Systems
- スライド:
- https://docs.com/user564329/6866/pausable-unittest-on-efi-stackless-python-pycon-jp
- ビデオ:
- https://youtu.be/ddsHRXpShfw?list=PLMkWB0UjwFGlYvIcvKsGhJ7SJIODj_zJZ
説明
組込み機器などのテストでは「再起動を繰り返しながらテストを実行する」ことが多くあります。今回開発したPausable Unittestライブラリを使うと、標準ライブラリのunittestのようにテストを記述でき、かつ、「Pythonインタプリタを一度終了し、再起動後に続きを実行する」場合のテストも、簡単に記述できます。実例をEFI上に移植したStackless Pythonを用いて説明します。
概要
# Pausable Unittest on EFI Stackless Python
家電機器などの組込みデバイスやPCなどのテストでは、「システムの再起動を途中にはさみながら、テストを継続する」ことが多くあります。
こういった場合、Python でテストスクリプトを書こうとすると、再起動によって Python インタプリタが終了してしまうので、再起動後に続きからテストを実行するのは困難です。
しかし、例えば下記のテストスクリプトのように、 (\*1) でレジスタの値を読み、 (\*2) でシステムを再起動し、再起動後に (\*3) から実行してくれると便利です。
また、再起動後の (\*4) では、再起動前に (\*1) で保存した変数も、特別にセーブ/ロードしなくても参照できると便利です。
def test():
a = read_register() # (*1)
reboot() # (*2)
b = read_register() # (*3)
assertEqual(a, b) # (*4)
Pausable Unittest ライブラリは、 Stackless Python もしくは PyPy の機能を活用することで、このようなテストスクリプトの記述を可能とします。
発表では、EFI 仕様に準拠した最近の PC で起動できる「EFI Shell」環境に移植した Stackless Python の説明とともに、実際の挙動を含め、下記について説明します。
* 「再起動を途中にはさみながらテストを継続する」際の問題点
変数の退避と復旧、関数を途中から実行させることの必要性について、説明します。
* Stackless Python の tasklet と、PyPy の continulet でできること
それぞれを使ってできる「関数の途中状態の保存と復旧」について、説明します。
* Pausable Unittest が可能とすること
再起動にまつわるテストの問題点を解決する Pausable Unittest について、説明します。
特に、 unittest の pickle 対応について説明します。
* Stackless Python の EFI Shell 上への移植
実際の適用例として用いた、PC の Pre-OS 環境である EFI Shell 上への Stackless Python の移植について、説明します。
移植するうえで一部アセンブラの知識が必要な個所についても簡単に触れる予定です。
* 上記を用いた実例
実際に VirtualBox/VMWare 上で実挙動を実演します。
### サンプルデモ
なお、 EFI Shell 上で、「3回の再起動を行い、起動速度を測定し、それが 8秒未満かをテストする」という (やや恣意的な) シナリオの場合、下記のようにテストスクリプトを書くことができます。
下記のスクリプトでは、 (\*1) のループの中で、 (\*2) で再起動を行い、平均を求めて一回の再起動にかかる時間を測定しています。
動作の様子は [YouTube][1] で見ることができます。
import pausable_unittest
import pausable_unittest.efipauser
import time
class Sample(pausable_unittest.TestCase):
def test_reboot(self):
reboot_time = []
for i in range(3): # (*1)
print("Reboot %d..." % i)
time.sleep(3)
start = time.time()
self.reboot() # (*2)
end = time.time()
reboot_time.append(end - start)
avg_time = sum(reboot_time) / len(reboot_time)
self.assertLess(avg_time, 8)
if __name__ == "__main__":
pausable_unittest.main(pausable_unittest.efipauser.Pauser())
## Pausable Unittest と EFI Stackless Python の入手先
現在開発中の Pausable Unittest は以下の URL で公開しています。
[https://github.com/masamitsu-murase/pausable_unittest][2]
日本語の README は以下にあります。
[https://github.com/masamitsu-murase/pausable_unittest/blob/master/README.ja.md][3]
また、EFI Shell 上に移植した Stackless Python は、以下のブランチにあります。
[https://github.com/masamitsu-murase/edk2_for_mruby/tree/stackless_python279_release][4]
[1]: https://youtu.be/gb7-UKnkjrM
[2]: https://github.com/masamitsu-murase/pausable_unittest
[3]:https://github.com/masamitsu-murase/pausable_unittest/blob/master/README.ja.md
[4]: https://github.com/masamitsu-murase/edk2_for_mruby/tree/stackless_python279_release