Publié par
Il y a 4 années · 36 minutes · DevOps

Test Driven Infrastructure avec Chef (Episode 2)

Dans le premier article de cette série – Test Driven Infrastructure avec Chef (Episode 1) – nous avons mis en place :

  • un environnement sain et isolé
  • les outils de base (Berkshelf et Test-Kitchen) pour travailler avec des cookbooks sur votre machine de développement
  • un squelette de cookbook prêt à utiliser.

Ce second article montre comment écrire et lancer :

  • des tests d’acceptance avec Cucumber.
  • des tests d’intégration avec ServerSpec.
  • des tests unitaires avec ChefSpec.

Lancer des tests à l’intérieur d’un noeud avec Busser

Busser (garçon/serveur de restaurant en français) est un framework de setup et d’exécution de tests sur les nœuds créés par Test-Kitchen. Il utilise une architecture de plugin permettant d’ajouter le support de différents outils/stratégies de test tels que MiniTest, Cucumber, Bash, etc.

L’installation de Busser sur le nœud et l’exécution des tests sont complètement prises en charge par Test-Kitchen. Par défaut, Test-Kitchen va regarder dans le répertoire test/integration pour trouver les fichiers de test à lancer. Ce répertoire est organisé comme suit :

  • Directement sous test/integration se trouveront des répertoires dont les noms définiront les suites de tests. Les suites de tests à lancer sont déclarées dans le .kitchen.yml sous suites: - name: <nom de la suite>. Pour plus d’informations sur .kitchen.yml se référer à http://docs.opscode.com/config_yml_kitchen.html.
  • Sous chaque répertoire de suite de tests se trouveront des répertoires dont les noms sont ceux des plugins Busser utilisés.
  • Sous chaque répertoire de plugin Busser se trouveront les fichiers de tests à lancer sur les nœuds.
test/integration
  |_ do_something <-- suite name (more on this later)
     |_ cucumber <-- busser (AKA the "tester")
        |_ my_test_files <-- a test

Pour plus d’informations sur Busser, se référer à https://github.com/test-kitchen/test-kitchen/wiki/Getting-Started#structure.

Ecriture d’un test d’acceptance (BDD) utilisant Cucumber

Note :

Dans le livre Test-Driven Infrastructure with Chef, 2nd Edition, Stephen Nelson-Smith utilise l’outil Leibniz pour lancer ses tests Cucumber. Nous n’allons pas utiliser cet outil ici pour deux raisons :

  • La première est que l’outil n’a pas été activement développé depuis le Nov 28, 2013 au moment de l’écriture de cet article et ne supporte que Test-Kitchen 1.0.0.alpha .
  • La seconde est que l’outil ne fait pas partie du cycle de vie de Test-Kitchen lui même. Il monte de nouveaux nœuds avec Test-Kitchen en utilisant sa propre configuration, puis lance les tests cucumber contre ces nœuds… Ce qui veut dire que pour faire tous les tests, les nœuds sont lancés deux fois (une fois pas Leibniz pour le BDD, et une fois par Test-Kitchen pour les autres tests). Il faut également maintenir deux ensembles séparés de fichiers de configuration. Ceci n’est pas efficace et augmente la complexité dans l’organisation et la maintenance des tests…

L’idéal serait que Test-Kitchen inclue un équivalent de Busser pour lancer des tests à l’extérieur des nœuds une fois que ceux-ci sont créés, en donnant au code de test l’accès aux informations relatives aux nœuds (addresse IP, hostname, etc). Cela n’étant pas le cas actuellement, deux approches sont possibles :

  1. Lancer les tests Cucumber après que chaque nœud ait convergé (avec un test-kitchen converge <os-plateform>) ou ait convergé et terminé ses tests Busser (avec un test-kitchen verify <os-plateform>)
  2. Lancer les tests Cucumber à l’intérieur même du nœud en utilisant busser-cucumber.

C’est la deuxième option qui a été choisie dans cet article. Elle permet la prise en charge complète du lancement des tests par Test-Kitchen pour chaque nœud/plateforme testé.


Introduction à Cucumber

Cucumber permet aux équipes de développement de décrire comment l’application qu’ils développent doit se comporter, et ceci en langage naturel. Le texte est écrit dans un langage spécifique au domaine d’application de manière lisible pour le métier. Il sert en même temps de documentation, de test automatisé et d’aide au développement… Tout cela en un seul format.

Pour plus d’informations, se reporter sur http://cukes.info/.

Écriture du test Cucumber

Créer le répertoire de test Cucumber :

$ mkdir -p test/integration/default/cucumber/

Créer le fichier wonderstuff_up.feature :

$ vim test/integration/default/cucumber/wonderstuff_up.feature

Décrire le test d’acceptance dans le fichier wonderstuff_up.feature :


Note :

Le scénario utilisé ici est plus élaboré que celui présenté par le bouquin afin de pouvoir trouver plus facilement l’origine du problème. Il demande, en plus, de vérifier que la connexion a pu être établie, et qu’une page a bien été retournée.


Feature: Potential customer can read about services

  In order to generate more leads for my business
  As a business owner
  I want web users to be able to read about my services


  Scenario: User visits home page
    Given the url of Wonderstuff's home page
    When a web user browses to the URL
    Then the connection should be successful
    Then the page status should be OK
    Then the user should see "Wonderstuff Design is a boutique graphics design agency." 

Note :

Pas d’ajout de Gem pour Cucumber dans le fichier Gemfile ??!? Normal, puisque les tests sont effectués à l’intérieur du nœud. Les Gems y seront installés par Busser.


Lancer le test :

$ bundle exec kitchen verify ubuntu
-----> Starting Kitchen (v1.2.1)
-----> Creating <default-ubuntu-1204>...
       Bringing machine 'default' up with 'virtualbox' provider...
       ==> default: Importing base box 'opscode-ubuntu-12.04'...
       ==> default: Matching MAC address for NAT networking...
       ==> default: Setting the name of the VM: default-ubuntu-1204_default_1404574723288_18847
       Skipping Berkshelf with --no-provision
       ==> default: Clearing any previously set network interfaces...
       ==> default: Preparing network interfaces based on configuration...
           default: Adapter 1: nat
       ==> default: Forwarding ports...
           default: 22 => 2222 (adapter 1)
       ==> default: Booting VM...
       ==> default: Waiting for machine to boot. This may take a few minutes...
           default: SSH address: 127.0.0.1:2222
           default: SSH username: vagrant
           default: SSH auth method: private key
           default: Warning: Connection timeout. Retrying...
       ==> default: Machine booted and ready!
       ==> default: Checking for guest additions in VM...
       ==> default: Setting hostname...
       Vagrant instance <default-ubuntu-1204> created.
       Finished creating <default-ubuntu-1204> (0m39.85s).
-----> Converging <default-ubuntu-1204>...
       Preparing files for transfer
       Resolving cookbook dependencies with Berkshelf 3.1.3...
       Removing non-cookbook files before transfer
       Transfering files to <default-ubuntu-1204>
[2014-07-05T15:39:08+00:00] INFO: Forking chef instance to converge...
[2014-07-05T15:39:08+00:00] WARN:
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
SSL validation of HTTPS requests is disabled. HTTPS connections are still
encrypted, but chef is not able to detect forged replies or man in the middle
attacks.

To fix this issue add an entry like this to your configuration file:

```
  # Verify all HTTPS connections (recommended)
  ssl_verify_mode :verify_peer
  # OR, Verify only connections to chef-server
  verify_api_cert true
```

To check your SSL configuration, or troubleshoot errors, you can use the
`knife ssl check` command like so:

```
         knife ssl check -c /tmp/kitchen/solo.rb
       ```

       * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Starting Chef Client, version 11.12.4
[2014-07-05T15:39:08+00:00] INFO: *** Chef 11.12.4 ***
[2014-07-05T15:39:08+00:00] INFO: Chef-client pid: 1184
[2014-07-05T15:39:10+00:00] INFO: Setting the run_list to ["recipe[wonderstuff::default]"] from CLI options
[2014-07-05T15:39:10+00:00] INFO: Run List is [recipe[wonderstuff::default]]
[2014-07-05T15:39:10+00:00] INFO: Run List expands to [wonderstuff::default]
[2014-07-05T15:39:10+00:00] INFO: Starting Chef Run for default-ubuntu-1204
[2014-07-05T15:39:10+00:00] INFO: Running start handlers
[2014-07-05T15:39:10+00:00] INFO: Start handlers complete.
Compiling Cookbooks...
Converging 0 resources
[2014-07-05T15:39:10+00:00] INFO: Chef Run complete in 0.005109498 seconds

Running handlers:
[2014-07-05T15:39:10+00:00] INFO: Running report handlers
Running handlers complete

[2014-07-05T15:39:10+00:00] INFO: Report handlers complete
Chef Client finished, 0/0 resources updated in 2.305749507 seconds
       Finished converging <default-ubuntu-1204> (0m3.72s).
-----> Setting up <default-ubuntu-1204>...
Fetching: thor-0.19.0.gem (100%)
Fetching: busser-0.6.2.gem (100%)
Successfully installed thor-0.19.0
Successfully installed busser-0.6.2
2 gems installed
-----> Setting up Busser
       Creating BUSSER_ROOT in /tmp/busser
       Creating busser binstub
       Plugin cucumber installed (version 0.1.0)
-----> Running postinstall for cucumber plugin
       Finished setting up <default-ubuntu-1204> (4m2.30s).
-----> Verifying <default-ubuntu-1204>...
       Suite path directory /tmp/busser/suites does not exist, skipping.
Uploading /tmp/busser/suites/cucumber/wonderstuff_up.feature (mode=0644)
-----> Running cucumber test suite
Feature: Potential customer can read about services

  In order to generate more leads for my business
  As a business owner
  I want web users to be able to read about my services

  Scenario: User visits home page                                                       # /tmp/busser/suites/cucumber/wonderstuff_up.feature:7
    Given the url of Wonderstuff's home page                                            # /tmp/busser/suites/cucumber/wonderstuff_up.feature:8
    When a web user browses to the url                                                  # /tmp/busser/suites/cucumber/wonderstuff_up.feature:9
    Then the connection should be successful                                            # /tmp/busser/suites/cucumber/wonderstuff_up.feature:10
    Then the page status should be OK                                                   # /tmp/busser/suites/cucumber/wonderstuff_up.feature:11
    Then the user should see "Wonderstuff Design is a boutique graphics design agency." # /tmp/busser/suites/cucumber/wonderstuff_up.feature:12

1 scenario (1 undefined)
5 steps (5 undefined)
0m0.011s

You can implement step definitions for undefined steps with these snippets:

Given(/^the url of Wonderstuff's home page$/) do
  pending # express the regexp above with the code you wish you had
end

When(/^a web user browses to the url$/) do
  pending # express the regexp above with the code you wish you had
end

Then(/^the connection should be successful$/) do
  pending # express the regexp above with the code you wish you had
end

       Then(/^the page status should be OK$/) do
         pending # express the regexp above with the code you wish you had
       end

       Then(/^the user should see "(.*?)"$/) do |arg1|
         pending # express the regexp above with the code you wish you had
       end
 
       Finished verifying <default-ubuntu-1204> (0m1.05s).
-----> Kitchen is finished. (4m47.56s)

Cucumber indique ici qu’il a trouvé la définition du test d’acceptance, mais que son implémentation reste à faire. Il donne les snippets qui permettront cette implémentation en Ruby.

Créer le fichier contenant les "steps definitions" en reportant les snippets dans test/integration/default/cucumber/step_definitions/wonderstuff_up_steps.rb :

$ mkdir test/integration/default/cucumber/step_definitions
$ vim test/integration/default/cucumber/step_definitions/wonderstuff_up_steps.rb

Contenu du fichier wonderstuff_up_steps.rb :

# encoding: UTF-8
 
Given(/^the url of Wonderstuff's home page$/) do
  pending # express the regexp above with the code you wish you had
end

When(/^a web user browses to the url$/) do
  pending # express the regexp above with the code you wish you had
end
 
Then(/^the connection should be successful$/) do
  pending # express the regexp above with the code you wish you had
end

Then(/^the page status should be OK$/) do
  pending # express the regexp above with the code you wish you had
end

Then(/^the user should see "(.*?)"$/) do |arg1|
  pending # express the regexp above with the code you wish you had
end

 

Maintenant, il ne reste plus qu’à écrire dans wonderstuff_up_steps.rb le code qui fera effectivement les tests :

# encoding: UTF-8
 
# Faraday is a simple, but flexible HTTP client library, with support for
# multiple backends. We will use it here to read the server's response 
# that we want to verify.
require 'faraday'
# We use the Socket library to find out the IP of the server in order to
# form the url to test.
require 'socket'

Given(/^the url of Wonderstuff's home page$/) do
  @local_ip = Socket.ip_address_list[2].ip_address
  @url = "http://#{@local_ip}:8080"
end

When(/^a web user browses to the url$/) do
  connection = Faraday.new(:url => @url) do |faraday|
    faraday.adapter Faraday.default_adapter
  end
  @response = connection.get('/')
end
 
Then(/^the connection should be successful$/) do
  @response.success?.should be_true
end

Then(/^the page status should be OK$/) do
  @response.status.should == 200
end
 
Then(/^the user should see "(.*?)"$/) do |arg1|
  expect(@response.body).to match(arg1)
end

 

Lancer les tests :

$ bundle exec kitchen verify ubuntu
-----> Starting Kitchen (v1.2.1)
-----> Verifying <default-ubuntu-1204>...
       Removing /tmp/busser/suites/cucumber
Uploading /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb (mode=0644)
Uploading /tmp/busser/suites/cucumber/wonderstuff_up.feature (mode=0644)
-----> Running cucumber test suite
cannot load such file -- faraday (LoadError)
/opt/chef/embedded/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
/opt/chef/embedded/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
/tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:6:in `<top (required)>'
/tmp/busser/gems/gems/cucumber-1.3.15/lib/cucumber/rb_support/rb_language.rb:95:in `load'
/tmp/busser/gems/gems/cucumber-1.3.15/lib/cucumber/rb_support/rb_language.rb:95:in `load_code_file'
/tmp/busser/gems/gems/cucumber-1.3.15/lib/cucumber/runtime/support_code.rb:180:in `load_file'
/tmp/busser/gems/gems/cucumber-1.3.15/lib/cucumber/runtime/support_code.rb:83:in `block in load_files!'
/tmp/busser/gems/gems/cucumber-1.3.15/lib/cucumber/runtime/support_code.rb:82:in `each'
/tmp/busser/gems/gems/cucumber-1.3.15/lib/cucumber/runtime/support_code.rb:82:in `load_files!'
/tmp/busser/gems/gems/cucumber-1.3.15/lib/cucumber/runtime.rb:184:in `load_step_definitions'
/tmp/busser/gems/gems/cucumber-1.3.15/lib/cucumber/runtime.rb:42:in `run!'
/tmp/busser/gems/gems/cucumber-1.3.15/lib/cucumber/cli/main.rb:47:in `execute!'
       /tmp/busser/gems/gems/busser-cucumber-0.1.0/lib/busser/cucumber/runner.rb:22:in `<main>'
Ruby Script [/tmp/busser/gems/gems/busser-cucumber-0.1.0/lib/busser/cucumber/runner.rb /tmp/busser/suites/cucumber] exit code was 1
>>>>>> Verify failed on instance <default-ubuntu-1204>.
>>>>>> Please see .kitchen/logs/default-ubuntu-1204.log for more details
>>>>>> ------Exception-------
>>>>>> Class: Kitchen::ActionFailed
>>>>>> Message: SSH exited (1) for command: [sh -c 'BUSSER_ROOT="/tmp/busser" GEM_HOME="/tmp/busser/gems" GEM_PATH="/tmp/busser/gems" GEM_CACHE="/tmp/busser/gems/cache" ; export BUSSER_ROOT GEM_HOME GEM_PATH GEM_CACHE; sudo -E /tmp/busser/bin/busser test']
>>>>>> ----------------------

Test-Kitchen nous informe qu’il n’a pas pu loader le Gem faraday. C’est tout à fait normal : autant Busser installe les Gems des frameworks de test, autant les Gems utilisés dans les tests mais ne faisant pas partie de la distribution Ruby doivent être installés explicitement. (pour plus d’information, consultez https://github.com/test-kitchen/busser-cucumber#usage)

Nous allons nous assurer que les Gems additionnels sont bien installés sur le noeud grace au fichier spec_helper.rb :

$ vim test/integration/default/cucumber/spec_helper.rb

Contenu du fichier spec_helper.rb :

# encoding: UTF-8

begin
  require 'faraday'
rescue LoadError
  require 'rubygems/dependency_installer'
  Gem::DependencyInstaller.new.install('faraday')
  require 'faraday'
end
 

Relancer les tests :

$ bundle exec kitchen verify ubuntu
-----> Starting Kitchen (v1.2.1)
-----> Verifying <default-ubuntu-1204>...
       Removing /tmp/busser/suites/cucumber
Uploading /tmp/busser/suites/cucumber/spec_helper.rb (mode=0644)
Uploading /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb (mode=0644)
Uploading /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb.old (mode=0644)
Uploading /tmp/busser/suites/cucumber/wonderstuff_up.feature (mode=0644)
-----> Running cucumber test suite
Feature: Potential customer can read about services

  In order to generate more leads for my business
  As a business owner
  I want web users to be able to read about my services

  Scenario: User visits home page                                                       # /tmp/busser/suites/cucumber/wonderstuff_up.feature:7
    Given the url of Wonderstuff's home page                                            # /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:11
    When a web user browses to the url                                                  # /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:16
      the scheme http does not accept registry part: ::1:8080 (or bad hostname?) (URI::InvalidURIError)
      /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:17:in `/^a web user browses to the url$/'
      /tmp/busser/suites/cucumber/wonderstuff_up.feature:9:in `When a web user browses to the url'
    Then the connection should be successful                                            # /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:23
    Then the page status should be OK                                                   # /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:27
    Then the user should see "Wonderstuff Design is a boutique graphics design agency." # /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:31

Failing Scenarios:
cucumber /tmp/busser/suites/cucumber/wonderstuff_up.feature:7 # Scenario: User visits home page

1 scenario (1 failed)
5 steps (1 failed, 3 skipped, 1 passed)
0m0.030s
Ruby Script [/tmp/busser/gems/gems/busser-cucumber-0.1.0/lib/busser/cucumber/runner.rb /tmp/busser/suites/cucumber] exit code was 1
>>>>>> Verify failed on instance <default-ubuntu-1204>.
>>>>>> Please see .kitchen/logs/default-ubuntu-1204.log for more details
>>>>>> ------Exception-------
>>>>>> Class: Kitchen::ActionFailed
>>>>>> Message: SSH exited (1) for command: [sh -c 'BUSSER_ROOT="/tmp/busser" GEM_HOME="/tmp/busser/gems" GEM_PATH="/tmp/busser/gems" GEM_CACHE="/tmp/busser/gems/cache" ; export BUSSER_ROOT GEM_HOME GEM_PATH GEM_CACHE; sudo -E /tmp/busser/bin/busser test']
>>>>>> ----------------------

Ici, nous rencontrons un autre problème. Concentrons nous sur le message d’erreur :

    When a web user browses to the url                                                  # /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:16
      the scheme http does not accept registry part: ::1:8080 (or bad hostname?) (URI::InvalidURIError)
      /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:17:in `/^a web user browses to the url$/'
      /tmp/busser/suites/cucumber/wonderstuff_up.feature:9:in `When a web user browses to the url'

L’adresse IP n’a pas été trouvé. En effet, le code de test requiert que le noeud ait une IP privée à laquelle le test puisse accéder au futur serveur web en local.

Pour cela nous devons faire changer les caractéristiques du noeud créé avec Vagrant en éditant le .kitchen.yml :

---
driver:
  name: vagrant

provisioner:
  name: chef_solo

platforms:
  - name: ubuntu-12.04
  - name: centos-6.4

suites:
  - name: default
    driver:
      network:
        - ["private_network", {ip: "192.168.33.40"}]
    run_list:
      - recipe[wonderstuff::default]
    attributes:

Ce changement nécessite de détruire le noeud créé par Test-Kitchen, puis de le recréer et relancer les tests :

$ bundle exec kitchen destroy ubuntu
-----> Starting Kitchen (v1.2.1)
-----> Destroying <default-ubuntu-1204>...
       ==> default: Forcing shutdown of VM...
       ==> default: Destroying VM and associated drives...
       Vagrant instance <default-ubuntu-1204> destroyed.
       Finished destroying <default-ubuntu-1204> (0m4.31s).
-----> Kitchen is finished. (0m4.92s)
 
$ bundle exec kitchen verify ubuntu
-----> Starting Kitchen (v1.2.1)
-----> Creating <default-ubuntu-1204>...
[..]
       Finished creating <default-ubuntu-1204> (0m40.84s).
-----> Converging <default-ubuntu-1204>...
[..]
       Finished converging <default-ubuntu-1204> (0m3.79s).
-----> Setting up <default-ubuntu-1204>...
Fetching: thor-0.19.0.gem (100%)
Fetching: busser-0.6.2.gem (100%)
Successfully installed thor-0.19.0
Successfully installed busser-0.6.2
2 gems installed
-----> Setting up Busser
       Creating BUSSER_ROOT in /tmp/busser
       Creating busser binstub
       Plugin cucumber installed (version 0.1.0)
-----> Running postinstall for cucumber plugin
       Finished setting up <default-ubuntu-1204> (1m32.58s).
-----> Verifying <default-ubuntu-1204>...
       Suite path directory /tmp/busser/suites does not exist, skipping.
Uploading /tmp/busser/suites/cucumber/spec_helper.rb (mode=0644)
Uploading /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb (mode=0644)
Uploading /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb.old (mode=0644)
Uploading /tmp/busser/suites/cucumber/wonderstuff_up.feature (mode=0644)
-----> Running cucumber test suite
Fetching: multipart-post-2.0.0.gem (100%)
Fetching: faraday-0.9.0.gem (100%)
Feature: Potential customer can read about services

  In order to generate more leads for my business
  As a business owner
  I want web users to be able to read about my services

  Scenario: User visits home page                                                       # /tmp/busser/suites/cucumber/wonderstuff_up.feature:7
    Given the url of Wonderstuff's home page                                            # /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:11
    When a web user browses to the url                                                  # /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:16
      Connection refused - connect(2) (Faraday::ConnectionFailed)
      /opt/chef/embedded/lib/ruby/1.9.1/net/http.rb:763:in `initialize'
      /opt/chef/embedded/lib/ruby/1.9.1/net/http.rb:763:in `open'
      /opt/chef/embedded/lib/ruby/1.9.1/net/http.rb:763:in `block in connect'
      /opt/chef/embedded/lib/ruby/1.9.1/timeout.rb:55:in `timeout'
      /opt/chef/embedded/lib/ruby/1.9.1/timeout.rb:100:in `timeout'
      /opt/chef/embedded/lib/ruby/1.9.1/net/http.rb:763:in `connect'
      /opt/chef/embedded/lib/ruby/1.9.1/net/http.rb:756:in `do_start'
      /opt/chef/embedded/lib/ruby/1.9.1/net/http.rb:745:in `start'
      /opt/chef/embedded/lib/ruby/1.9.1/net/http.rb:1285:in `request'
      /opt/chef/embedded/lib/ruby/1.9.1/net/http.rb:1027:in `get'
      /tmp/busser/gems/gems/faraday-0.9.0/lib/faraday/adapter/net_http.rb:78:in `perform_request'
      /tmp/busser/gems/gems/faraday-0.9.0/lib/faraday/adapter/net_http.rb:39:in `call'
      /tmp/busser/gems/gems/faraday-0.9.0/lib/faraday/rack_builder.rb:139:in `build_response'
      /tmp/busser/gems/gems/faraday-0.9.0/lib/faraday/connection.rb:377:in `run_request'
             /tmp/busser/gems/gems/faraday-0.9.0/lib/faraday/connection.rb:140:in `get'
             /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:20:in `/^a web user browses to the url$/'
             /tmp/busser/suites/cucumber/wonderstuff_up.feature:9:in `When a web user browses to the url'
    Then the connection should be successful                                            # /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:23
    Then the page status should be OK                                                   # /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:27
    Then the user should see "Wonderstuff Design is a boutique graphics design agency." # /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:31

Failing Scenarios:
cucumber /tmp/busser/suites/cucumber/wonderstuff_up.feature:7 # Scenario: User visits home page

1 scenario (1 failed)
5 steps (1 failed, 3 skipped, 1 passed)
0m0.081s
Ruby Script [/tmp/busser/gems/gems/busser-cucumber-0.1.0/lib/busser/cucumber/runner.rb /tmp/busser/suites/cucumber] exit code was 1
>>>>>> Verify failed on instance <default-ubuntu-1204>.
>>>>>> Please see .kitchen/logs/default-ubuntu-1204.log for more details
>>>>>> ------Exception-------
>>>>>> Class: Kitchen::ActionFailed
>>>>>> Message: SSH exited (1) for command: [sh -c 'BUSSER_ROOT="/tmp/busser" GEM_HOME="/tmp/busser/gems" GEM_PATH="/tmp/busser/gems" GEM_CACHE="/tmp/busser/gems/cache" ; export BUSSER_ROOT GEM_HOME GEM_PATH GEM_CACHE; sudo -E /tmp/busser/bin/busser test']
>>>>>> ----------------------

Voilà! Notre test d’acceptance a bien échoué en essayant d’accéder à la page web du site que l’on veut créer. Il est maintenant prêt.

Commiter tout le travail fait jusqu’à présent dans Git :

$ git add --all
$ git commit -m 'added cucumber acceptance test'

Ecriture d’un test d’intégration utilisant SpecServer

Introduction à ServerSpec

ServerSpec permet d’écrire des tests RSpec permettant de tester que vos serveurs sont correctement configurés.

ServerSpec teste l’état des serveurs par accès SSH. Pas besoin d’y installer un agent. De plus, Busser se charge entièrement de tout le cycle d’exécution des tests sur les noeuds créés par Test-Kitchen.

Plus d’informations disponibles sur http://serverspec.org/.

Avant de passer aux tests d’intégrations…

Comme nous l’avons fait sur les tests d’acceptance, il faut d’abord s’assurer que les tests que nous écrivons échouent. Une limitation actuelle dans Test-Kitchen/Busser est que le lancement des tests s’arrête dès que le premier d’entre eux échoue. Dans le cas présent, cela veut dire que les tests d’intégration avec ServerSpec ne seront jamais joués car Test-Kitchen s’arrêtera immédiatement après que le test d’acceptance Cucumber échoue.

Pour palier à cette situation, nous allons utiliser le fait que nous avons commité nos changements précédents dans Git. Cela nous permet de détruire le répertoire test/integration/default/cucumber/ en toute tranquilité (même si c’est très moche…), sachant que nous pourront faciliement le récupérer une fois terminé à partir du repository Git.

Supprimer le répertoire test/integration/default/cucumber/ et vérifier le statut Git :

$ rm -R test/integration/default/cucumber/
$ git status
On branch master
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)
 deleted:    test/integration/default/cucumber/spec_helper.rb
 deleted:    test/integration/default/cucumber/step_definitions/wonderstuff_up_steps.rb
 deleted:    test/integration/default/cucumber/wonderstuff_up.feature
no changes added to commit (use "git add" and/or "git commit -a")

Configuration de ServerSpec

ServerSpec a besoin de savoir le type d’OS sur lequel il va effectué les tests avant de lancer ces derniers. Pour cela, nous allons créer un fichier de support spec_helper.rb qui fera ce travail, pour en faire référence ensuite dans tous les fichiers de tests qui seront fait : 

$ mkdir test/integration/default/serverspec
$ vim test/integration/default/serverspec/spec_helper.rb

Contenu de spec_helper.rb :

# encoding: UTF-8
require 'serverspec'
require 'pathname'

include Serverspec::Helper::Exec
include Serverspec::Helper::DetectOS

RSpec.configure do |c|
  c.before :all do
    c.os = backend(Serverspec::Commands::Base).check_os
  end
end

 

Ecriture du test ServerSpec

Créer les répertoires qui vont permettre la prise en charge des tests par Busser, et créer le fichier contenant le test.

$ mkdir test/integration/default/serverspec/localhost
$ vim test/integration/default/serverspec/localhost/readable_services_spec.rb

Contenu de fichier readable_services_spec.rb :

# encoding: UTF-8
require 'spec_helper'

describe 'Wonderstuff Design' do

  it 'should install the lighttpd package' do
    expect(package 'lighttpd').to be_installed
  end

  it 'should enable and start the lighttpd service' do
    expect(service 'lighttpd').to be_enabled
    expect(service 'lighttpd').to be_running
  end

  it 'should render the Wonderstuff Design web page' do
    expect(file('/var/www/index.html')).to be_file
    expect(file('/var/www/index.html')).to contain 'Wonderstuff Design is a boutique graphics design agency.'
  end

end

 

Lancement des tests :

$ bundle exec kitchen verify ubuntu
-----> Starting Kitchen (v1.2.1)
-----> Verifying <default-ubuntu-1204>...
       Removing /tmp/busser/suites/cucumber
Uploading /tmp/busser/suites/serverspec/localhost/readable_services_spec.rb (mode=0644)
Uploading /tmp/busser/suites/serverspec/spec_helper.rb (mode=0644)
-----> Running cucumber test suite
cannot load such file -- spec_helper (LoadError)
/opt/chef/embedded/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
/opt/chef/embedded/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
/tmp/busser/suites/serverspec/localhost/readable_services_spec.rb:2:in `<top (required)>'
/tmp/busser/gems/gems/cucumber-1.3.15/lib/cucumber/rb_support/rb_language.rb:95:in `load'
/tmp/busser/gems/gems/cucumber-1.3.15/lib/cucumber/rb_support/rb_language.rb:95:in `load_code_file'
/tmp/busser/gems/gems/cucumber-1.3.15/lib/cucumber/runtime/support_code.rb:180:in `load_file'
/tmp/busser/gems/gems/cucumber-1.3.15/lib/cucumber/runtime/support_code.rb:83:in `block in load_files!'
/tmp/busser/gems/gems/cucumber-1.3.15/lib/cucumber/runtime/support_code.rb:82:in `each'
/tmp/busser/gems/gems/cucumber-1.3.15/lib/cucumber/runtime/support_code.rb:82:in `load_files!'
/tmp/busser/gems/gems/cucumber-1.3.15/lib/cucumber/runtime.rb:184:in `load_step_definitions'
/tmp/busser/gems/gems/cucumber-1.3.15/lib/cucumber/runtime.rb:42:in `run!'
       /tmp/busser/gems/gems/cucumber-1.3.15/lib/cucumber/cli/main.rb:47:in `execute!'
       /tmp/busser/gems/gems/busser-cucumber-0.1.0/lib/busser/cucumber/runner.rb:22:in `<main>'
Ruby Script [/tmp/busser/gems/gems/busser-cucumber-0.1.0/lib/busser/cucumber/runner.rb /tmp/busser/suites/cucumber] exit code was 1
>>>>>> Verify failed on instance <default-ubuntu-1204>.
>>>>>> Please see .kitchen/logs/default-ubuntu-1204.log for more details
>>>>>> ------Exception-------
>>>>>> Class: Kitchen::ActionFailed
>>>>>> Message: SSH exited (1) for command: [sh -c 'BUSSER_ROOT="/tmp/busser" GEM_HOME="/tmp/busser/gems" GEM_PATH="/tmp/busser/gems" GEM_CACHE="/tmp/busser/gems/cache" ; export BUSSER_ROOT GEM_HOME GEM_PATH GEM_CACHE; sudo -E /tmp/busser/bin/busser test']
>>>>>> ----------------------

On remarque qu’il y a un message d’erreur : les tests Cucumber ont été lancés malgré l’absence des fichiers (que nous avons effacés). Il n’y a pas d’autre moyen de supprimer le plugin busser-cucumber que de détruire et recréer le noeud utilisé par Test-Kitchen :

$ bundle exec kitchen destroy ubuntu
-----> Starting Kitchen (v1.2.1)
-----> Destroying <default-ubuntu-1204>...
       ==> default: Forcing shutdown of VM...
       ==> default: Destroying VM and associated drives...
       Vagrant instance <default-ubuntu-1204> destroyed.
       Finished destroying <default-ubuntu-1204> (0m4.31s).
-----> Kitchen is finished. (0m4.92s)

$ bundle exec kitchen setup ubuntu
-----> Starting Kitchen (v1.2.1)
-----> Creating <default-ubuntu-1204>...
[..]
       Finished creating <default-ubuntu-1204> (0m40.84s).
-----> Converging <default-ubuntu-1204>...
[..]
       Finished converging <default-ubuntu-1204> (0m3.79s).
-----> Setting up <default-ubuntu-1204>...
Fetching: thor-0.19.0.gem (100%)
Fetching: busser-0.6.2.gem (100%)
Successfully installed thor-0.19.0
Successfully installed busser-0.6.2
2 gems installed
-----> Setting up Busser
       Creating BUSSER_ROOT in /tmp/busser
       Creating busser binstub
       Plugin serverspec installed (version 0.2.6)
-----> Running postinstall for serverspec plugin
       Finished setting up <default-ubuntu-1204> (1m11.84s).
-----> Verifying <default-ubuntu-1204>...
       Suite path directory /tmp/busser/suites does not exist, skipping.
Uploading /tmp/busser/suites/serverspec/localhost/readable_services_spec.rb (mode=0644)
Uploading /tmp/busser/suites/serverspec/spec_helper.rb (mode=0644)
-----> Running serverspec test suite
/opt/chef/embedded/bin/ruby -I/tmp/busser/suites/serverspec -S /opt/chef/embedded/bin/rspec /tmp/busser/suites/serverspec/localhost/readable_services_spec.rb --color --format documentation

Wonderstuff Design
No packages found matching lighttpd.
  should install the lighttpd package (FAILED - 1)
  should enable and start the lighttpd service (FAILED - 2)
  should render the Wonderstuff Design web page (FAILED - 3)


Failures:


  1) Wonderstuff Design should install the lighttpd package
     On host ``
     Failure/Error: expect(package 'lighttpd').to be_installed
       dpkg-query -f '${Status}' -W lighttpd | grep -E '^(install|hold) ok installed$'
       expected Package "lighttpd" to be installed
     # /tmp/busser/suites/serverspec/localhost/readable_services_spec.rb:7:in `block (2 levels) in <top (required)>'


  2) Wonderstuff Design should enable and start the lighttpd service
     On host ``
     Failure/Error: expect(service 'lighttpd').to be_enabled
       ls /etc/rc3.d/ | grep -- '^S..lighttpd' || grep 'start on' /etc/init/lighttpd.conf
       grep: /etc/init/lighttpd.conf: No such file or directory
       expected Service "lighttpd" to be enabled
     # /tmp/busser/suites/serverspec/localhost/readable_services_spec.rb:11:in `block (2 levels) in <top (required)>'


  3) Wonderstuff Design should render the Wonderstuff Design web page
     On host ``
     Failure/Error: expect(file('/var/www/index.html')).to be_file
       test -f /var/www/index.html
       expected file? to return true, got false
     # /tmp/busser/suites/serverspec/localhost/readable_services_spec.rb:16:in `block (2 levels) in <top (required)>'


Finished in 0.09551 seconds
3 examples, 3 failures


Failed examples:


rspec /tmp/busser/suites/serverspec/localhost/readable_services_spec.rb:6 # Wonderstuff Design should install the lighttpd package
rspec /tmp/busser/suites/serverspec/localhost/readable_services_spec.rb:10 # Wonderstuff Design should enable and start the lighttpd service
rspec /tmp/busser/suites/serverspec/localhost/readable_services_spec.rb:15 # Wonderstuff Design should render the Wonderstuff Design web page
/opt/chef/embedded/bin/ruby -I/tmp/busser/suites/serverspec -S /opt/chef/embedded/bin/rspec /tmp/busser/suites/serverspec/localhost/readable_services_spec.rb --color --format documentation failed
Ruby Script [/tmp/busser/gems/gems/busser-serverspec-0.2.6/lib/busser/runner_plugin/../serverspec/runner.rb /tmp/busser/suites/serverspec] exit code was 1
>>>>>> Verify failed on instance <default-ubuntu-1204>.
>>>>>> Please see .kitchen/logs/default-ubuntu-1204.log for more details
>>>>>> ------Exception-------
>>>>>> Class: Kitchen::ActionFailed
>>>>>> Message: SSH exited (1) for command: [sh -c 'BUSSER_ROOT="/tmp/busser" GEM_HOME="/tmp/busser/gems" GEM_PATH="/tmp/busser/gems" GEM_CACHE="/tmp/busser/gems/cache" ; export BUSSER_ROOT GEM_HOME GEM_PATH GEM_CACHE; sudo -E /tmp/busser/bin/busser test']
>>>>>> ----------------------

Voilà! Notre test d’intégration a bien échoué en essayant d’accéder à la page web du site que l’on veut créer. Il est maintenant prêt.

Nous pouvons réinstituer les tests Cucumber, et vérifier qu’ils échouent toujours test/integration/default/cucumber/ et relancer les tests :

$ git checkout -- test/integration/default/cucumber/
 
$ bundle exec kitchen setup ubuntu          # Must be run first to install the busser-cucumber plugin!
-----> Starting Kitchen (v1.2.1)
-----> Setting up <default-ubuntu-1204>...
-----> Setting up Busser
       Creating BUSSER_ROOT in /tmp/busser
       Creating busser binstub
       Plugin cucumber installed (version 0.1.0)
-----> Running postinstall for cucumber plugin
       Plugin serverspec already installed
       Finished setting up <default-ubuntu-1204> (1m4.20s).
-----> Kitchen is finished. (1m4.90s)
 
$ bundle exec kitchen verify ubuntu
-----> Starting Kitchen (v1.2.1)
-----> Verifying <default-ubuntu-1204>...
       Removing /tmp/busser/suites/serverspec
Uploading /tmp/busser/suites/cucumber/spec_helper.rb (mode=0644)
Uploading /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb (mode=0644)
Uploading /tmp/busser/suites/cucumber/wonderstuff_up.feature (mode=0644)
Uploading /tmp/busser/suites/serverspec/localhost/readable_services_spec.rb (mode=0644)
Uploading /tmp/busser/suites/serverspec/spec_helper.rb (mode=0644)
-----> Running cucumber test suite
Fetching: multipart-post-2.0.0.gem (100%)
Fetching: faraday-0.9.0.gem (100%)
Feature: Potential customer can read about services

  In order to generate more leads for my business
  As a business owner
  I want web users to be able to read about my services

  Scenario: User visits home page                                                       # /tmp/busser/suites/cucumber/wonderstuff_up.feature:7
    Given the url of Wonderstuff's home page                                            # /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:11
    When a web user browses to the url                                                  # /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:16
      Connection refused - connect(2) (Faraday::ConnectionFailed)
      /opt/chef/embedded/lib/ruby/1.9.1/net/http.rb:763:in `initialize'
      /opt/chef/embedded/lib/ruby/1.9.1/net/http.rb:763:in `open'
      /opt/chef/embedded/lib/ruby/1.9.1/net/http.rb:763:in `block in connect'
      /opt/chef/embedded/lib/ruby/1.9.1/timeout.rb:55:in `timeout'
      /opt/chef/embedded/lib/ruby/1.9.1/timeout.rb:100:in `timeout'
      /opt/chef/embedded/lib/ruby/1.9.1/net/http.rb:763:in `connect'
      /opt/chef/embedded/lib/ruby/1.9.1/net/http.rb:756:in `do_start'
      /opt/chef/embedded/lib/ruby/1.9.1/net/http.rb:745:in `start'
      /opt/chef/embedded/lib/ruby/1.9.1/net/http.rb:1285:in `request'
      /opt/chef/embedded/lib/ruby/1.9.1/net/http.rb:1027:in `get'
             /tmp/busser/gems/gems/faraday-0.9.0/lib/faraday/adapter/net_http.rb:78:in `perform_request'
             /tmp/busser/gems/gems/faraday-0.9.0/lib/faraday/adapter/net_http.rb:39:in `call'
             /tmp/busser/gems/gems/faraday-0.9.0/lib/faraday/rack_builder.rb:139:in `build_response'
             /tmp/busser/gems/gems/faraday-0.9.0/lib/faraday/connection.rb:377:in `run_request'
             /tmp/busser/gems/gems/faraday-0.9.0/lib/faraday/connection.rb:140:in `get'
             /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:20:in `/^a web user browses to the url$/'
             /tmp/busser/suites/cucumber/wonderstuff_up.feature:9:in `When a web user browses to the url'
    Then the connection should be successful                                            # /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:23
    Then the page status should be OK                                                   # /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:27
    Then the user should see "Wonderstuff Design is a boutique graphics design agency." # /tmp/busser/suites/cucumber/step_definitions/wonderstuff_up_steps.rb:31

Failing Scenarios:
cucumber /tmp/busser/suites/cucumber/wonderstuff_up.feature:7 # Scenario: User visits home page

1 scenario (1 failed)
5 steps (1 failed, 3 skipped, 1 passed)
0m0.094s
Ruby Script [/tmp/busser/gems/gems/busser-cucumber-0.1.0/lib/busser/cucumber/runner.rb /tmp/busser/suites/cucumber] exit code was 1
>>>>>> Verify failed on instance <default-ubuntu-1204>.
>>>>>> Please see .kitchen/logs/default-ubuntu-1204.log for more details
>>>>>> ------Exception-------
>>>>>> Class: Kitchen::ActionFailed
>>>>>> Message: SSH exited (1) for command: [sh -c 'BUSSER_ROOT="/tmp/busser" GEM_HOME="/tmp/busser/gems" GEM_PATH="/tmp/busser/gems" GEM_CACHE="/tmp/busser/gems/cache" ; export BUSSER_ROOT GEM_HOME GEM_PATH GEM_CACHE; sudo -E /tmp/busser/bin/busser test']
>>>>>> ----------------------

Tout est bien redevenu normal : Test-Kitchen s’arrête au premier test qui échoue. 

Commiter tout le travail fait jusqu’à présent dans Git :

$ git add --all
$ git commit -m 'added serverspec integration test'

Ecriture d’un test unitaire ChefSpec

Introduction à ChefSpec

ChefSpec est un framework de test unitaire permettant de tester des cookbooks Chef. Il simplifie l’écriture de tests permettant d’obtenir un feedback rapide sur les changements de cookbooks sans avoir besoin de machine virtuelle ni de serveurs dans le cloud.

ChefSpec est une extension de Rspec. Il lance votre cookbook localement en utilisant Chef Solo sans avoir besoin de faire converger un noeud. Cela a deux avantages principaux :

  • C’est très rapide !
  • Vos tests peuvent faire varier les attributs des noeuds, OS, les résultats de recherche pour vérifier le comportement des cookbooks dans divers conditions.

Plus d’information disponible sur https://github.com/sethvargo/chefspec ou encore http://docs.opscode.com/chefspec.html.

Installation de ChefSpec

A l’écriture de l’article, la version de ChefSpec est la 4.0.1 .

Ajouter ChefSpec au Gemfile : 

gem 'chefspec', '4.0.1'

Lancer l’installation du Gem :

$ bundle update
Fetching gem metadata from https://rubygems.org/.......
Fetching additional metadata from https://rubygems.org/..
Resolving dependencies...
Using addressable 2.3.6
Using multipart-post 2.0.0
Using faraday 0.9.0
Using berkshelf-api-client 1.2.0
Using buff-extensions 1.0.0
Using hashie 2.1.2
Using varia_model 0.4.0
Using buff-config 1.0.0
Using buff-ruby_engine 0.1.0
Using buff-shell_out 0.1.1
Using hitimes 1.2.2
Using timers 3.0.1
Using celluloid 0.16.0.pre2
Using nio4r 1.0.0
Using celluloid-io 0.16.0.pre2
Using minitar 0.5.4
Using sawyer 0.5.4
Using octokit 3.2.0
Using retryable 1.3.5
Using buff-ignore 1.1.1
Using erubis 2.7.0
Using json 1.8.1
Using mixlib-log 1.6.0
Using mixlib-authentication 1.3.0
Using net-http-persistent 2.9.4
Using semverse 1.1.0
Using ridley 4.0.0
Using dep-selector-libgecode 1.0.2
Using ffi 1.9.3
Using dep_selector 1.0.3
Using solve 1.2.0
Using thor 0.19.1
Using berkshelf 3.1.3
Using rack 1.5.2
Using chef-zero 2.0.2
Using diff-lcs 1.2.5
Using highline 1.6.21
Using mime-types 1.25.1
Using mixlib-cli 1.5.0
Using mixlib-config 2.1.0
Using mixlib-shellout 1.4.0
Using net-ssh 2.9.1
Using net-ssh-gateway 1.2.0
Using net-ssh-multi 1.2.0
Using ipaddress 0.8.0
Using systemu 2.5.2
Using yajl-ruby 1.2.1
Using ohai 7.0.4
Using coderay 1.1.0
Using method_source 0.8.2
Using slop 3.5.0
Using pry 0.10.0
Using rdoc 4.1.1
Using rest-client 1.6.8
Using chef 11.12.8
Using fauxhai 2.1.2
Using rspec-support 3.0.2
Using rspec-core 3.0.2
Using rspec-expectations 3.0.2
Using rspec-mocks 3.0.2
Using rspec 3.0.0
Installing chefspec 4.0.1
Using net-scp 1.2.1
Using safe_yaml 1.0.3
Using test-kitchen 1.2.1
Using kitchen-vagrant 0.15.0
Using bundler 1.6.2
Your bundle is updated!

Configuration de ChefSpec

Les tests ChefSpec se trouvent dans le répertoire spec. On peut dire à ChefSpec de faire les tests en simulant un OS spécifique. Nous allons faire cela dans cet exemple particulier en nous cantonnant à Ubuntu 12.04. Pour cela, nous allons spécifier l’OS de manière globale en utilisant le fichier de support spec_helper.rb qui fera ce travail, pour en faire référence ensuite dans tous les fichiers de tests qui seront faits. Dans un autre article de cette série, nous lancerons les tests en simulant différents OS grace à Rake. Pour plus d’information sur la spécification de l’OS cible de ChefSpec, se référer à https://github.com/sethvargo/chefspec#configuration .

Créer le répertoire spec et le fichier spec_helper.rb :

$ mkdir spec
$ vim spec/spec_helper.rb

Contenu de spec_helper.rb :

# encoding: UTF-8
require 'chefspec'
require 'chefspec/berkshelf'

RSpec.configure do |config|
  config.platform = 'ubuntu'
  config.version = '12.04'
end
 

Ecriture du test ChefSpec

Créer les répertoires et le fichier contenant le test.

$ mkdir -p spec/unit/recipes/
$ vim spec/unit/recipes/default_spec.rb

Contenu de fichier default_spec.rb :

# encoding: UTF-8
require 'spec_helper'

describe 'wonderstuff::default' do
  let(:chef_run) do
    runner = ChefSpec::Runner.new(
      log_level: :error
    )
    Chef::Config.force_logger true
    runner.converge('recipe[wonderstuff::default]')
  end

  it 'installs the lighttpd package' do
    expect(chef_run).to install_package('lighttpd')
  end

  it 'creates a webpage to be served' do
    expect(chef_run).to render_file('/var/www/index.html').with_content('Wonderstuff Design is a boutique graphics design agency.')
  end

  it 'starts the lighttpd service' do
    expect(chef_run).to start_service('lighttpd')
  end

  it 'enables the lighttpd service' do
    expect(chef_run).to enable_service('lighttpd')
  end
end
 

Lancement des tests :

$ bundle exec rspec -fd

wonderstuff::default
  installs the lighttpd package (FAILED - 1)
  creates a webpage to be served (FAILED - 2)
  starts the lighttpd service (FAILED - 3)
  enables the lighttpd service (FAILED - 4)


Failures:


  1) wonderstuff::default installs the lighttpd package
     Failure/Error: expect(chef_run).to install_package('lighttpd')
       expected "package[lighttpd]" with action :install to be in Chef run. Other package resources:


 
 
     # ./spec/unit/recipes/default_spec.rb:14:in `block (2 levels) in <top (required)>'


  2) wonderstuff::default creates a webpage to be served
     Failure/Error: expect(chef_run).to render_file('/var/www/index.html').with_content('Wonderstuff Design is a boutique graphics design agency.')
       expected Chef run to render "/var/www/index.html" matching:


       Wonderstuff Design is a boutique graphics design agency.


       but got:


 
 
     # ./spec/unit/recipes/default_spec.rb:18:in `block (2 levels) in <top (required)>'


  3) wonderstuff::default starts the lighttpd service
     Failure/Error: expect(chef_run).to start_service('lighttpd')
       expected "service[lighttpd]" with action :start to be in Chef run. Other service resources:


 
 
     # ./spec/unit/recipes/default_spec.rb:22:in `block (2 levels) in <top (required)>'


  4) wonderstuff::default enables the lighttpd service
     Failure/Error: expect(chef_run).to enable_service('lighttpd')
       expected "service[lighttpd]" with action :enable to be in Chef run. Other service resources:


 
 
     # ./spec/unit/recipes/default_spec.rb:26:in `block (2 levels) in <top (required)>'


Finished in 0.09411 seconds (files took 1.79 seconds to load)
4 examples, 4 failures


Failed examples:


rspec ./spec/unit/recipes/default_spec.rb:13 # wonderstuff::default installs the lighttpd package
rspec ./spec/unit/recipes/default_spec.rb:17 # wonderstuff::default creates a webpage to be served
rspec ./spec/unit/recipes/default_spec.rb:21 # wonderstuff::default starts the lighttpd service
rspec ./spec/unit/recipes/default_spec.rb:25 # wonderstuff::default enables the lighttpd service

Voilà! Notre test unitaire a bien échoué et est maintenant prêt.

Commiter tout le travail fait jusqu’à présent dans Git :

$ git add --all
$ git commit -m 'added chefspec unit test'

A suivre…

Voilà, vous avez maintenant :

  • vos tests d’acceptance
  • vos tests d’intégration
  • vos tests unitaires

Dans le prochain article, nous allons écrire le cookbook lui-même, puis rajouter des outils de test permettant de vérifier le bon formatage du code..

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *