読者です 読者をやめる 読者になる 読者になる

テストステ論

高テス協会会長が, テストステロンに関する情報をお届けします.

(dmtest report) reloadをデコレータで解決した

github.com

dmtestとは, 今私が開発している, device-mapperをテストするためのフレームワークのことである. ライトブーストのテストをより簡単に書けることが, ライトブーストの今後につながる. コアコードの開発は私がするしかないのが, テストならばコアコードよりは書きやすいだろう. 型で守ってあげればなおさらだ.

以下は, loopbackデバイスを作って, それをbackingにしたlinearデバイスを作り, それをbackingにしたLuks(暗号化)デバイスを作り, そしてXFSでformatしてマウントして何かするという処理をdmtestを使って書いたコードである. マウントポイントやdmデバイスの名前は自動的に一意なものを生成する. また, ブロックを抜けたあとにはリソース終了処理をする.

Loopback(Sector.M(128)) { s1 =>
  EmptyStack().reload(Linear.Table(s1, Sector(0), Sector.M(16))) { s2 =>
    Luks(s) { s3 =>
      XFS.format(s3)
      XFS.mount(s3) { mp =>
        // do something
      }
    }
  }
}

tableを上書きすることで変質させるというreloadをベースにしてデバイスを作成していくために, EmptyStackというのを作り, それに対してreloadごとにdecorateしていくという設計とした. これには, 「reloadをするごとにデバイスのコアな状態を引き継いでいなければいけない」という要求があるからだ. さらに, reloadをチェイン出来るようにするためには, 再帰的な型構造を持たせるしかない.

重要なコードを抜粋:

case class EmptyStack() extends DMStack {
  val dm = new DMState(name = RandName.alloc) // dmsetup xxxを実行するマン
  dm.create() // dmsetup create --no-tableを実行する
}
trait DMStackDecorator[S <: DMStackDecorator[S]] extends DMStack {
  def table: DMTable[S]
  def delegate: DMStack
  override def dm = delegate.dm
  dm.reload(table.line) // dmsetup reloadを実行する
}
trait DMTable[S <: DMStackDecorator[S]] {
  def f: DMStack => S
  def line: String
}
trait DMStack extends Stack {
  def dm: DMState
  def path = Paths.get(s"/dev/mapper/${dm.name}")
  def reload[S <: DMStackDecorator[S]](table: DMTable[S]): S = {
    dm.suspend()
    val res = table.f(this) // does reload on creating the new stack
    dm.resume()
    res
  }
  def terminate = dm.remove() // purge = 自分のterminate + 自分の下にあるデバイスのpurgeという再帰構造
}
trait Stack {
  protected def path: Path // e.g. /dev/sdb
  def apply[A](f: this.type => A): A = {
    val resource: this.type = this
    lock
    try {
      f(resource)
    } finally {
      unlock
      purge
    }
  }
}

おそらく, LinuxカーネルモジュールのテストをScalaで構築するというのはあまりない試みではないかな. Linuxカーネルコミュニティはおじさんばかりだから彼ら使うのは未だにperlだし, Scalaなんか書いてるやつは大抵はLinuxカーネルなんか書かないし, たぶんあまり興味もないから. そういう意味でも, いいものを作ってアピールしていきたいと思う. Scalaはいいぜ.