モト
inokara.hateblo.jp
moto という AWS SDK のレスポンスを模倣する Python ライブラリについて引き続きです。
Stand-alone Server Mode
moto には Stand-alone Server Mode という Flask で実装された Mock サーバーが提供されていて、HTTP サーバーなので Python に限らず、他の言語ライブラリからも利用出来るのがスーパーメリットだと思いました。
github.com
実際に 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)
以下のようにインスタンス一覧を取得するだけのライブラリをサンプルとして利用します。
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
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
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 参加者から話をきいてみたりしよう」にて語らせて頂く予定でござります。
speakerdeck.com