Contribute Media
A thank you to everyone who has made this possible: Read More

Pausable Unittest on EFI Stackless Python

Description

組込み機器などのテストでは「再起動を繰り返しながらテストを実行する」ことが多くあります。今回開発したPausable Unittestライブラリを使うと、標準ライブラリのunittestのようにテストを記述でき、かつ、「Pythonインタプリタを一度終了し、再起動後に続きを実行する」場合のテストも、簡単に記述できます。実例をEFI上に移植したStackless Pythonを用いて説明します。

Abstract

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 で見ることができます。

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

日本語の README は以下にあります。 https://github.com/masamitsu-murase/pausable_unittest/blob/master/README.ja.md

また、EFI Shell 上に移植した Stackless Python は、以下のブランチにあります。 https://github.com/masamitsu-murase/edk2formruby/tree/stacklesspython279release

Improve this page