vigia 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YWJmOWE0NTllY2M5OWM1ODVlYzQwOTVhMmZjM2ExMTRmZDQ0NjA0ZA==
4
+ NDYwMThkZDk2ZDI3NDFhYzc5ZWUyNzQ4NzA0NmRjMjgyNmFjZGM4Nw==
5
5
  data.tar.gz: !binary |-
6
- ZTg5ZDljZmVmODNiNDIxN2ZhNjIyN2NjODYwNDdjMmY1MmE3ZjRmOQ==
6
+ MDk2NWU5YTkyMTg0NzE2YzFiNmRlMDY2Yzg3NmNkMDU1NmFiNmJkOQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- NzA4ODNkYTIzODZmYTc0ODZmNDZjYWU3YTdmYmRkMzJiMjZhNzhmZWU0N2Q3
10
- YjRmNGQyMGU1MmJjNTVjMWZhYzQyNDk5N2I1ZjU4N2E0MzBlYjM4ZWQ5Y2E2
11
- Mjc0ZTFmOWMwNTRmYTUyYTUxNDRiNzA0NWEwMWE3Zjc0MTYyNjY=
9
+ ZjA0N2FmOTg2ODRiN2Y1Y2FiMzEwYzcyNDBkNGMwNzQ2ZWNhZmMwZjc4OWZl
10
+ MDNiYzU3MDE0MTQxMzNkNWFjNWY3NzhiYWQyNWVhZDhiMzllZDMzMDY3MWQ1
11
+ MzM0ZjJjNTgxYWU4ZWU5ODZlZTExYzFlZDdjZDFlZWYzYzQxODY=
12
12
  data.tar.gz: !binary |-
13
- YWU1MDFjZjE3NWM0OTQ4MzFkNmZjODk1ZTQyN2E5MGYzODMwMzgxNjk3YmQz
14
- ZGVmNjQwZmI1Mzg5NGQ3ZDYyNGIwZTcxODc4ZTA1ZjRkN2NiNzI5NDY2YzBh
15
- MDcyZTNhN2RjNmFhZjM0NTU1NjQyOTM1ZTE3Y2U4MjIwMjZiMmI=
13
+ OWMyMDQyZTViMWNkZTMzZmM5OGRlM2E1OTk2MmUwYTI5ZGY0MjEwMzM1NTZj
14
+ NTQ1YjgxMTVmMTBiODk2YTM1YWUxNDIzNDRlNDNmMTljM2QwYWNlOWMwOTE2
15
+ NTc1YTVhZDcwMDMzNzM2NTI4MGY3YWI2OWYyYjIyZjgzODcxZjA=
data/Gemfile CHANGED
@@ -4,4 +4,7 @@ source 'https://rubygems.org'
4
4
  gem 'redsnow', github: 'apiaryio/redsnow', submodules: true
5
5
  gem 'codeclimate-test-reporter', group: :test, require: nil
6
6
 
7
+ # Pull raml from github
8
+ gem 'raml_ruby', github: 'coub/raml_ruby'
9
+
7
10
  gemspec
data/README.md CHANGED
@@ -9,7 +9,7 @@ Vigia
9
9
 
10
10
  <img src="http://singularities.org/vigia.png" width="96" height="96" class="right" alt="Vigia logo" />
11
11
 
12
- Vigia is a gem to perform integration tests using RSpec and a compatible adapter (See [Adapters](https://github.com/lonelyplanet/vigia/wiki/Adapters)). The adapter creates the structure of the test (groups and context) and sets up all the variables (See [Context variables](https://github.com/lonelyplanet/vigia/wiki/Context-variables)) used to perform the http request.
12
+ Vigia is a gem to perform integration tests on an API server using RSpec and a compatible adapter (See [Adapters](https://github.com/lonelyplanet/vigia/wiki/Adapters)). The adapter creates the structure of the test (groups and context) and sets up all the variables (See [Context variables](https://github.com/lonelyplanet/vigia/wiki/Context-variables)) used to perform the http request.
13
13
 
14
14
  These results and expectations objects can be used to run examples that will compare the expected value with the server response value. Vigia allows to use a variety of different ways to execute these comparisons (See [Vigia Examples](https://github.com/lonelyplanet/vigia/wiki/Expectations---Examples) and [Custom Shared Examples](https://github.com/lonelyplanet/vigia/wiki/Shared-examples))
15
15
 
@@ -1,12 +1,14 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require 'redsnow'
4
+ require 'raml'
4
5
  require 'rspec'
5
6
  require 'rest_client'
6
7
  require 'addressable/template'
7
8
 
8
9
  require_relative 'vigia/adapter'
9
10
  require_relative 'vigia/adapters/blueprint'
11
+ require_relative 'vigia/adapters/raml'
10
12
  require_relative 'vigia/config'
11
13
  require_relative 'vigia/hooks'
12
14
  require_relative 'vigia/formatter'
@@ -17,6 +19,7 @@ require_relative 'vigia/parameters'
17
19
  require_relative 'vigia/rspec'
18
20
  require_relative 'vigia/sail/rspec_object'
19
21
  require_relative 'vigia/sail/example'
22
+ require_relative 'vigia/sail/examples/default'
20
23
  require_relative 'vigia/sail/context'
21
24
  require_relative 'vigia/sail/group'
22
25
  require_relative 'vigia/sail/group_instance'
@@ -25,21 +28,39 @@ require_relative 'vigia/version'
25
28
 
26
29
  module Vigia
27
30
  class << self
28
- def config
29
- @config
30
- end
31
+
32
+ attr_reader :config
33
+
31
34
  def configure
32
- @config = Vigia::Config.new
33
- yield @config
34
- @config.apply
35
+ reset!
36
+ @config = Vigia::Config.new.tap do |_config|
37
+ yield _config
38
+ load_default_examples if _config.load_default_examples
39
+ end
35
40
  end
41
+
36
42
  def spec_folder
37
43
  File.join(__dir__, 'vigia', 'spec')
38
44
  end
45
+
39
46
  def rspec!
47
+ ensure_config
40
48
  Vigia::Rspec.new.run!
41
49
  end
50
+
51
+ def reset!
52
+ [ Vigia::Sail::Context, Vigia::Sail::Example, Vigia::Sail::Group ].map(&:clean!)
53
+ @config = nil
54
+ end
55
+
56
+ private
57
+
58
+ def load_default_examples
59
+ Vigia::Sail::Examples::Default.load!
60
+ end
61
+
62
+ def ensure_config
63
+ (config && config.validate!) || raise('Invalid config')
64
+ end
42
65
  end
43
66
  end
44
-
45
- require_relative 'vigia/sail/examples/default'
@@ -0,0 +1,111 @@
1
+ module Vigia
2
+ module Adapters
3
+ class Raml < Vigia::Adapter
4
+
5
+ attr_reader :raml
6
+
7
+ setup_adapter do
8
+
9
+ after_initialize do
10
+ @raml = ::Raml::parse_file(source_file)
11
+ end
12
+
13
+ group :resource,
14
+ primary: true,
15
+ children: [ :method ],
16
+ describes: -> { adapter.raml.resources.values },
17
+ description: -> { "Resource: #{ resource.name }" },
18
+ recursion: -> { resources.values }
19
+
20
+ group :method,
21
+ children: [ :response ],
22
+ describes: -> { resource.methods.values },
23
+ description: -> { "Method: #{ method.name }" }
24
+
25
+ group :response,
26
+ children: [ :body ],
27
+ describes: -> { method.responses.values },
28
+ description: -> { "Response: #{ response.name }" }
29
+
30
+ group :body,
31
+ contexts: [ :default ],
32
+ describes: -> { response.bodies.values },
33
+ description: -> { "Content type: #{ body.name }" }
34
+
35
+ context :default,
36
+ http_client_options: {
37
+ method: -> { method.name },
38
+ uri_template: -> { adapter.resource_uri_template(method) },
39
+ parameters: -> { adapter.parameters_for(method) },
40
+ headers: -> { adapter.request_headers(body) },
41
+ payload: -> { adapter.payload_for(method, body) if adapter.with_payload?(method.name) }
42
+ },
43
+ expectations: {
44
+ code: -> { response.name.to_i },
45
+ headers: -> { adapter.expected_headers(body) },
46
+ body: -> { body.schema.value }
47
+ }
48
+ end
49
+
50
+ def resource_uri_template(method)
51
+ uri_template = method.parent.resource_path
52
+ uri_template += query_parameters(method)
53
+ end
54
+
55
+ def parameters_for(method)
56
+ format_parameters(method.query_parameters) + format_parameters(method.parent.uri_parameters)
57
+ end
58
+
59
+ def request_headers(body)
60
+ method = body.parent.parent
61
+ compile_headers(method.headers).tap do |headers|
62
+ return unless with_payload?(method.name)
63
+ return if request_body_for(method, body).name == '*/*'
64
+ headers.merge!(content_type: request_body_for(method, body).name)
65
+ end
66
+ end
67
+
68
+ def expected_headers(body)
69
+ compile_headers(body.parent.headers).tap do |headers|
70
+ # Dont add content_type header if response is 204 (nil response)
71
+ headers.merge!(content_type: body.media_type) unless body.parent.name == 204 or headers.key?(:content_type)
72
+ end
73
+ end
74
+
75
+ def payload_for(method, body)
76
+ return unless with_payload?(method.name)
77
+ request_body_for(method, body).schema.value
78
+ end
79
+
80
+ def with_payload?(method_name)
81
+ [ :post, :put, :patch ].include?(method_name.to_s.downcase.to_sym)
82
+ end
83
+
84
+ private
85
+
86
+ def format_parameters(raml_hash)
87
+ raml_hash.values.each_with_object([]) do |parameter, array|
88
+ array << { name: parameter.name, value: parameter.example, required: !parameter.optional }
89
+ end
90
+ end
91
+
92
+ def compile_headers(headers)
93
+ headers.each_with_object({}) do |(key, header), hash|
94
+ raise "Required header #{ key } does not have an example value" if header.example.nil? && !header.optional
95
+ hash.merge!(key.to_s.gsub('-', '_').downcase.to_sym => header.example)
96
+ end
97
+ end
98
+
99
+ def request_body_for(method, response_body)
100
+ body = response_body.name == '*/*' ? method.bodies.values.first : method.bodies[response_body.name]
101
+ body ||raise("An example body cannot be found for method #{ method.name } #{ method.parent.resource_path }")
102
+ end
103
+
104
+ def query_parameters(method)
105
+ method.apply_traits if method.traits.any? # Does this belong here RAML?
106
+ return '' if method.query_parameters.empty?
107
+ "{?#{ method.query_parameters.keys.join(',') }}"
108
+ end
109
+ end
110
+ end
111
+ end
@@ -1,12 +1,13 @@
1
1
  module Vigia
2
2
  class Config
3
3
  attr_accessor :source_file, :host, :custom_examples_paths, :custom_examples, :headers, :http_client_class
4
- attr_accessor :adapter, :hooks, :rspec_config_block, :stderr, :stdout, :internal_hosts
4
+ attr_accessor :adapter, :hooks, :rspec_config_block, :stderr, :stdout, :internal_hosts, :load_default_examples
5
5
 
6
6
  def initialize
7
7
  @host = nil
8
8
  @source_file = nil
9
9
  @rspec_config_block = nil
10
+ @load_default_examples = true
10
11
  @internal_hosts = []
11
12
  @headers = {}
12
13
  @custom_examples_paths = []
@@ -18,13 +19,10 @@ module Vigia
18
19
  @http_client_class = Vigia::HttpClient::RestClient
19
20
  end
20
21
 
21
- def apply
22
- validate!
23
- end
24
-
25
22
  def validate!
26
- raise("You need to provide an source") unless source_file
27
23
  raise("You have to provide a host value in config or in the Apib") unless host
24
+
25
+ true
28
26
  end
29
27
 
30
28
  def add_custom_examples_on(filter, name)
@@ -27,7 +27,7 @@ module Vigia
27
27
  end
28
28
 
29
29
  def missing_parameters
30
- required_parameters.select{ |k| k[:value].nil? || k[:value].empty? }.map{ |k| k[:name] }
30
+ required_parameters.select{ |k| k[:value].nil? || k[:value].to_s.empty? }.map{ |k| k[:name] }
31
31
  end
32
32
  end
33
33
  end
@@ -1,10 +1,6 @@
1
1
  module Vigia
2
2
  class Rspec
3
3
  class << self
4
- def adapter
5
- @@adapter
6
- end
7
-
8
4
  def include_shared_folders
9
5
  require_custom_examples
10
6
  require "#{ __dir__ }/spec/support/utils"
@@ -35,6 +31,7 @@ module Vigia
35
31
 
36
32
  def set_global_memoizers(rspec)
37
33
  instance = adapter
34
+ self.class.define_singleton_method(:adapter) { instance }
38
35
  rspec.let(:client) { Vigia.config.http_client_class.new(http_client_options) }
39
36
  rspec.let(:result) { client.run }
40
37
  rspec.let(:result!) { client.run! }
@@ -42,7 +39,7 @@ module Vigia
42
39
  end
43
40
 
44
41
  def adapter
45
- @@adapter ||= Vigia.config.adapter.instance
42
+ @adapter ||= Vigia.config.adapter.instance
46
43
  end
47
44
 
48
45
  private
@@ -1,17 +1,29 @@
1
- Vigia::Sail::Example.register(
2
- :code_match,
3
- description: 'has the expected HTTP code',
4
- expectation: -> {
5
- if expectations.code.is_a?(Range)
6
- expect(expectations.code.member?(result.code)).to be true
7
- else
8
- expect(result.code).to be(expectations.code)
9
- end
10
- }
11
- )
1
+ module Vigia
2
+ module Sail
3
+ module Examples
4
+ module Default
5
+ module_function
12
6
 
13
- Vigia::Sail::Example.register(
14
- :include_headers,
15
- description: 'includes the expected headers',
16
- expectation: -> { expect(result.headers).to include(expectations.headers) }
17
- )
7
+ def load!
8
+ Vigia::Sail::Example.register(
9
+ :code_match,
10
+ description: 'has the expected HTTP code',
11
+ expectation: -> {
12
+ if expectations.code.is_a?(Range)
13
+ expect(expectations.code.member?(result.code)).to be true
14
+ else
15
+ expect(result.code).to be(expectations.code)
16
+ end
17
+ }
18
+ )
19
+
20
+ Vigia::Sail::Example.register(
21
+ :include_headers,
22
+ description: 'includes the expected headers',
23
+ expectation: -> { expect(result.headers).to include(expectations.headers) }
24
+ )
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -15,6 +15,8 @@ module Vigia
15
15
  rspec.describe group_instance do
16
16
  let(group_instance.group.name) { group_instance.described_object }
17
17
 
18
+ group_instance.group.include_recursion(group_instance.described_object, self)
19
+
18
20
  group_instance.run(self)
19
21
  end
20
22
  end
@@ -32,6 +34,16 @@ module Vigia
32
34
  contextual_object(option_name: :describes) || []
33
35
  end
34
36
 
37
+ def include_recursion(object, rspec_context)
38
+ describes = contextual_object(option_name: :recursion, context: object) || []
39
+ return if describes.empty?
40
+
41
+ self.clone.tap do |recursive_group|
42
+ recursive_group.options[:describes] = describes
43
+ recursive_group.instance_variable_set('@rspec', rspec_context)
44
+ end.run
45
+ end
46
+
35
47
  def create_group_instance(object, index)
36
48
  instance_name = "#{ name }#{ index }"
37
49
  Vigia::Sail::GroupInstance.new(instance_name, options, rspec).tap do |instance|
@@ -15,7 +15,7 @@ module Vigia
15
15
  end
16
16
  end
17
17
  end
18
-
18
+
19
19
  def to_s
20
20
  description.respond_to?(:call) ? instance_exec(&description) : description
21
21
  end
@@ -16,6 +16,14 @@ module Vigia
16
16
  instance = new(name, options, rspec)
17
17
  instance.run
18
18
  end
19
+
20
+ def clean!
21
+ @collection = {}
22
+ end
23
+
24
+ def inherited(subclass)
25
+ subclass.instance_variable_set('@collection', {})
26
+ end
19
27
  end
20
28
 
21
29
  include Vigia::Hooks
@@ -17,10 +17,8 @@ module Vigia
17
17
 
18
18
  attr_reader :uri_template
19
19
 
20
- # ApiBluprint uses RFC6570 in all its resource's uri_templates
21
- # https://github.com/apiaryio/api-blueprint/blob/master/API%20Blueprint%20Specification.md#1-uri-templates
22
- def initialize(apib_uri_template)
23
- @uri_template = Addressable::Template.new(apib_uri_template)
20
+ def initialize(template)
21
+ @uri_template = Addressable::Template.new(template)
24
22
  end
25
23
 
26
24
  def expand(parameters)
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Vigia
4
- VERSION = "0.1.4"
4
+ VERSION = "0.2.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vigia
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Tapiador
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-03-25 00:00:00.000000000 Z
12
+ date: 2015-05-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -81,6 +81,20 @@ dependencies:
81
81
  - - ! '>='
82
82
  - !ruby/object:Gem::Version
83
83
  version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: raml_ruby
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :runtime
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ! '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
84
98
  - !ruby/object:Gem::Dependency
85
99
  name: bundler
86
100
  requirement: !ruby/object:Gem::Requirement
@@ -191,22 +205,23 @@ files:
191
205
  - Gemfile
192
206
  - lib/vigia/adapter.rb
193
207
  - lib/vigia/adapters/blueprint.rb
194
- - lib/vigia/config.rb
208
+ - lib/vigia/adapters/raml.rb
195
209
  - lib/vigia/formatter.rb
196
210
  - lib/vigia/hooks.rb
197
211
  - lib/vigia/http_client/options.rb
198
212
  - lib/vigia/http_client/requests.rb
199
213
  - lib/vigia/http_client/rest_client.rb
200
- - lib/vigia/parameters.rb
201
- - lib/vigia/rspec.rb
202
- - lib/vigia/sail/context.rb
203
214
  - lib/vigia/sail/example.rb
204
215
  - lib/vigia/sail/examples/default.rb
216
+ - lib/vigia/sail/context.rb
205
217
  - lib/vigia/sail/group.rb
206
218
  - lib/vigia/sail/group_instance.rb
207
219
  - lib/vigia/sail/rspec_object.rb
208
- - lib/vigia/spec/api_spec.rb
209
220
  - lib/vigia/spec/support/utils.rb
221
+ - lib/vigia/spec/api_spec.rb
222
+ - lib/vigia/rspec.rb
223
+ - lib/vigia/config.rb
224
+ - lib/vigia/parameters.rb
210
225
  - lib/vigia/url.rb
211
226
  - lib/vigia/version.rb
212
227
  - lib/vigia.rb