モト
moto という AWS SDK のレスポンスを模倣する Python ライブラリについて引き続きです。
Stand-alone Server Mode
moto には Stand-alone Server Mode という Flask で実装された Mock サーバーが提供されていて、HTTP サーバーなので Python に限らず、他の言語ライブラリからも利用出来るのがスーパーメリットだと思いました。
実際に GitHub リポジトリにも https://github.com/spulec/moto/tree/master/other_langs というディレクトリに Ruby や Java から利用するサンプルが提供されています。
example
Install moto server
$ cat requirements.txt moto[server] $ pip install -r requirements.txt
Start moto server
まずは Help
$ moto_server --help usage: moto_server [-h] [-H HOST] [-p PORT] [service] positional arguments: service optional arguments: -h, --help show this help message and exit -H HOST, --host HOST Which host to bind -p PORT, --port PORT Port number to use for connection
EC2 用サーバーを起動
$ moto_server ec2 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Ruby Script
以下のようにインスタンス一覧を取得するだけのライブラリをサンプルとして利用します。
require 'aws-sdk' class MyEc2 def ec2 @ec2 ||= Aws::EC2::Client.new(profile: 'mock_profile', region: 'us-west-2', endpoint: 'http://127.0.0.1:5000') end def list_ec2_instances instance_ids = [] ec2.describe_instances.reservations.each do |res| res.instances.each do |instance| instance_ids << instance.instance_id end end instance_ids end def main list_ec2_instances.each do |instance| instance end end end # myec2 = MyEc2.new # p myec2.main
moto_server の URL とポートを Aws::EC2::Client
のインスタンスを生成する際の引数として endpoint
を指定するだけで moto_server が利用出来ます。
最後の 2 行のコメントアウトを外して実行すると以下のようなレスポンスが得られます。
$ bundle exec ruby my_ec2.rb []
moto_server を起動したコンソールでは以下のようにログが出力されていることを確認出来るかと思います。
$ moto_server ec2 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) 127.0.0.1 - - [21/Apr/2017 00:37:27] "POST / HTTP/1.1" 200 -
Rspec で moto を利用してテストを行う
上記の Ruby スクリプト(ライブラリ)を moto と Rspec でテストしてみたいと思いますので、以下のようなテストを書きます。
$LOAD_PATH.push('./') require "spec_helper" require "my_ec2" require "pty" describe 'MyEc2' do let(:myec2) { MyEc2.new } before(:all) do @output, @input = PTY.spawn("moto_server ec2") client = Aws::EC2::Client.new(region: 'us-west-2', endpoint: 'http://127.0.0.1:5000', profile: 'mock_profile') res = client.run_instances({ image_id: 'ami-20d1c544', min_count: 3, max_count: 3 }) @instance_ids = res.instances.map { |instance| instance.instance_id } end it "#ec2" do res = myec2.ec2 expect(res).to be_an_instance_of(Aws::EC2::Client) end it '#list_ec2_instances' do res = myec2.list_ec2_instances expect(res).to eq @instance_ids end it '#main' do res = myec2.main expect(res).to eq @instance_ids end end
ポイントは before
句で moto_server にアクセスして EC2 インスタンス 3 台を Run Instance している部分です。
実際にテストを走らせてみると…
moto_server が実行出来る環境にて、以下のように rspec を実行してみます。
$ bundle exec rspec spec MyEc2 #ec2 #list_ec2_instances #main Finished in 1.47 seconds (files took 0.16527 seconds to load) 3 examples, 0 failures
うまくテストが通ったようです。
以上
Rspec の書き方がだいぶん怪しいですが、moto_server を使うことでリアルな AWS リソースにアクセスすることなく、スクリプトやライブラリのテストやデバッグが言語に関係無く出来るといのは嬉しい限りです。
有難うございました。
おまけ
moto については 4/22(土)に厳かに執り行われる「JAWS-UG福岡:Reboot#4、荒木さんとAWSの話をしてみたり JAWS DAYS 参加者から話をきいてみたりしよう」にて語らせて頂く予定でござります。