# Infrataster [![Gem Version](https://badge.fury.io/rb/infrataster.png)](http://badge.fury.io/rb/infrataster) [![Build Status](http://ci.ryotarai.info/buildStatus/icon?job=infrataster)](http://ci.ryotarai.info/job/infrataster/) [![Code Climate](https://codeclimate.com/github/ryotarai/infrataster.png)](https://codeclimate.com/github/ryotarai/infrataster) Infrastructure Behavior Testing Framework. ## Basic Usage with Vagrant First, create `Gemfile`: ```ruby source 'https://rubygems.org' gem 'infrataster' ``` Install gems: ``` $ bundle install ``` Install Vagrant: [Official Docs](http://docs.vagrantup.com/v2/installation/index.html) Create Vagrantfile: ```ruby # Vagrantfile Vagrant.configure("2") do |config| config.vm.box = "hashicorp/precise64" config.vm.define :proxy do |c| c.vm.network "private_network", ip: "192.168.33.10" c.vm.network "private_network", ip: "171.16.33.10", virtualbox__intnet: "infrataster-example" end config.vm.define :app do |c| c.vm.network "private_network", ip: "171.16.33.11", virtualbox__intnet: "infrataster-example" end end ``` Start VMs: ``` $ vagrant up ``` Initialize rspec directory: ``` $ rspec --init create spec/spec_helper.rb create .rspec ``` `require 'infrataster/rspec'` and define target servers for testing in `spec/spec_helper.rb`: ```ruby # spec/spec_helper.rb require 'infrataster/rspec' Infrataster::Server.define( :proxy, # name '192.168.0.0/16', # ip address vagrant: true # for vagrant VM ) Infrataster::Server.define( :app, # name '172.16.0.0/16', # ip address vagrant: true, # for vagrant VM from: :proxy # access to this machine via SSH port forwarding from proxy ) # Code generated by `rspec --init` is following... ``` Then, you can write spec files: ```ruby # spec/example_spec.rb require 'spec_helper' describe server(:app) do describe http('http://app') do it "responds content including 'Hello Sinatra'" do expect(response.body).to include('Hello Sinatra') end it "responds as 'text/html'" do expect(response.headers['content-type']).to match(%r{^text/html}) end end end ``` Run tests: ``` $ bundle exec rspec 2 examples, 2 failures ``` Currently, the tests failed because the VM doesn't respond to HTTP request. It's time to write provisioning instruction like Chef's cookbooks or Puppet's manifests! ## Server "Server" is a server you tests. This supports Vagrant, which is very useful to run servers for testing. Of course, you can test real servers. You should define servers in `spec_helper.rb` like the following: ```ruby Infrataster::Server.define( # Name of the server, this will be used in the spec files. :proxy, # IP address of the server '192.168.0.0/16', # If the server is provided by vagrant and this option is true, # SSH configuration to connect to this server is got from `vagrant ssh-config` command automatically. vagrant: true, ) Infrataster::Server.define( # Name of the server, this will be used in the spec files. :app, # IP address of the server '172.16.0.0/16', # If the server is provided by vagrant and this option is true, # SSH configuration to connect to this server is got from `vagrant ssh-config` command automatically. vagrant: true, # Which gateway is used to connect to this server by SSH port forwarding? from: :proxy, # options for resources mysql: {user: 'app', password: 'app'}, ) ``` You can specify SSH configuration manually too: ```ruby Infrataster::Server.define( # ... ssh: {host_name: 'hostname', user: 'testuser', keys: ['/path/to/id_rsa']} ) ``` ### fuzzy IP address Infrataster has "fuzzy IP address" feature. You can pass IP address which has netmask (= CIDR) to `Infrataster::Server#define`. This needs `vagrant` option or `ssh` option which has `host_name` because this fetches all IP address via SSH and find the matching one. ```ruby Infrataster::Server.define( :app, # find IP address matching 172.16.0.0 ~ 172.16.255.255 '172.16.0.0/16', ``` Of course, you can set fully-specified IP address too. ```ruby Infrataster::Server.define( :app, '172.16.11.22', # or '172.16.11.22/32', ``` ### #ssh_exec You can execute a command on the server like the following: ```ruby describe server(:proxy) do let(:time) { Time.now } before do current_server.ssh_exec "echo 'Hello' > /tmp/test-#{time.to_i}" end it "executes a command on the current server" do result = current_server.ssh_exec("cat /tmp/test-#{time.to_i}") expect(result.chomp).to eq('Hello') end end ``` This is useful to test cases which depends on the status of the server. ## Resources "Resource" is what you test by Infrataster. For instance, the following code describes `http` resource. ```ruby describe server(:app) do describe http('http://example.com') do it "responds content including 'Hello Sinatra'" do expect(response.body).to include('Hello Sinatra') end end end ``` ### `http` resource `http` resource tests HTTP response when sending HTTP request. It accepts `method`, `params` and `header` as options. ```ruby describe server(:app) do describe http( 'http://app.example.com', method: :post, params: {'foo' => 'bar'}, headers: {'USER' => 'VALUE'} ) do it "responds with content including 'app'" do expect(response.body).to include('app') # `response` is a instance of `Faraday::Response` # See: https://github.com/lostisland/faraday/blob/master/lib/faraday/response.rb end end end ``` ### `capybara` resource `capybara` resource tests your web application by simulating real user's interaction. ```ruby describe server(:app) do describe capybara('http://app.example.com') do it 'shows food list' do visit '/' click_link 'Foods' expect(page).to have_content 'Yummy Soup' end end end ``` ### `mysql_query` resource `mysql_query` resource is now in [infrataster-plugin-mysql](https://github.com/ryotarai/infrataster-plugin-mysql). ## Example * [example](example) * [spec/integration](spec/integration) ## Tests ### Unit Tests Unit tests are under `spec/unit` directory. ``` $ bundle exec rake spec:unit ``` ### Integration Tests Integration tests are under `spec/integration` directory. ``` $ bundle exec rake spec:integration:prepare $ bundle exec rake spec:integration ``` ## Presentations * https://speakerdeck.com/ryotarai/infrataster-infra-behavior-testing-framework-number-oedo04 ## Changelog [Changelog](CHANGELOG.md) ## Contributing 1. Fork it ( http://github.com/ryotarai/infrataster/fork ) 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create new Pull Request