jsonapi-grader 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 36b447ba1230dd7ab8e6c1546ed576c0bf559c29
4
- data.tar.gz: 9b28cc55cb678ce74d91a2e1d44ac02cc0154c14
3
+ metadata.gz: 56b6e8fd7709f1e2781f92cee90c07631c70a498
4
+ data.tar.gz: 27dfc9812dbd48b4d376be6cd9f7a4b4b753b826
5
5
  SHA512:
6
- metadata.gz: ab4280c8cc133cf54a8169c26b247ef290d818a0d745533a451222d8d54b4600c557c6b3e0a0d96f24bce641dc8bc3626bdc8b3c50a7ca0f0771a8ab260ffc5a
7
- data.tar.gz: d20412c5bb6b74c1c1470bf5704c64c2b3b072ede3068aa8154d06360f5107ca24aae1be33a4f003c4ffcb2a210f2a48bbf0c5f2fd2034fb6555e72d35ec923b
6
+ metadata.gz: 050674d6228e3df1cdc4e51ebae9486ad5c3bf6481b81cb70af2c1e71144bbc43f2873b042db0cb7e6049f0ff9e93c4f9e241534f27ca856833698d81220e603
7
+ data.tar.gz: c1325c3d78e66fa8f668ec5fbd9feaa6608a37995d7373468711cf5570461c3921dcdb4f347cc981373c09a22436efd5a43a6abf2db104e18069f530cb8b5405
@@ -1,16 +1,15 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'jsonapi/grader'
3
+ require 'bundler/setup'
4
+ require 'rspec'
4
5
 
5
- grader =
6
- case ARGV[0]
7
- when 'serialization'
8
- JSONAPI::Grader::SerializationGrader.new('scenarii_serialization.json',
9
- implementation_dir: ARGV[1])
10
- when 'server'
11
- JSONAPI::Grader::ServerGrader.new(host: ARGV[1])
12
- else
13
- raise 'Unknown arguments'
14
- end
6
+ if ARGV.size != 1
7
+ $stderr.puts 'Usage: jsonapi-grader http://api.example.com'
8
+ exit(-1)
9
+ end
15
10
 
16
- grader.grade
11
+ ENV['HOST'] = ARGV[0]
12
+
13
+ dir = File.expand_path(File.dirname(__FILE__) + '/../spec')
14
+
15
+ RSpec::Core::Runner.run(['-I', dir, '-r', 'spec_helper', dir], $stderr, $stdout)
@@ -0,0 +1,24 @@
1
+ RSpec.describe 'content negotiation' do
2
+ it 'responds with correct content type' do
3
+ get '/books/1'
4
+
5
+ expect(response_status).to be 200
6
+ expect(response['Content-Type']).to eq('application/vnd.api+json')
7
+ end
8
+
9
+ context 'when requesting with media type parameters in content type' do
10
+ it 'responds with 415' do
11
+ get '/books/1', 'Content-Type' => 'application/vnd.api+json; foo=bar'
12
+
13
+ expect(response_status).to be 415
14
+ end
15
+ end
16
+
17
+ context 'when requesting with media type parameters in accept' do
18
+ it 'responds with 406' do
19
+ get '/books/1', 'Accept' => 'application/vnd.api+json; foo=bar'
20
+
21
+ expect(response_status).to be 406
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,33 @@
1
+ RSpec.describe 'fetching a single resource' do
2
+ it 'fetches a single resource' do
3
+ get '/books/1'
4
+
5
+ expect(response_status).to be 200
6
+ expect(response_body['data']).to have_type('books')
7
+ expect(response_body['data']).to have_id('1')
8
+ expect(response_body['data']).to have_attribute('title')
9
+ .with_value('The Fellowship of the Ring')
10
+ expect(response_body['data']).to have_relationship('author')
11
+ expect(response_body['data']).to have_relationship('series')
12
+ end
13
+
14
+ it 'fetches a single resource with meta' do
15
+ get '/books/1'
16
+
17
+ expect(response_status).to be 200
18
+ expect(response_body['data']).to have_meta('foo' => 'bar')
19
+ end
20
+
21
+ it 'fetches a single resource with links' do
22
+ get '/books/1'
23
+
24
+ expect(response_status).to be 200
25
+ expect(response_body['data']).to have_link('self')
26
+ end
27
+
28
+ it 'fetches a non-existent resource' do
29
+ get '/books/foo'
30
+
31
+ expect(response_status).to be 404
32
+ end
33
+ end
@@ -0,0 +1,42 @@
1
+ RSpec.describe 'fetching a resource collection' do
2
+ it 'fetches a resource collection' do
3
+ get '/books'
4
+
5
+ expect(response_status).to be 200
6
+ expect(response_body['data']).to all(have_type('books'))
7
+ end
8
+
9
+ it 'fetches a single resource with includes' do
10
+ get '/books/1?include=author'
11
+
12
+ expect(response_status).to be 200
13
+ expect(response_body['data']).to have_type('books')
14
+ expect(response_body['data']).to have_id('1')
15
+ expect(response_body['data']).to have_relationship('author')
16
+ .with_data('id' => '1', 'type' => 'authors')
17
+ expect(response_body['data']).to have_relationship('series')
18
+ author = response_body['data']['relationships']['author']['data']
19
+ expect(response_body['included'])
20
+ .to include(have_type('authors').and have_id(author['id']))
21
+ end
22
+
23
+ it 'fetches a single resource with meta' do
24
+ get '/books/1'
25
+
26
+ expect(response_status).to be 200
27
+ expect(response_body['data']).to have_meta('foo' => 'bar')
28
+ end
29
+
30
+ it 'fetches a single resource with links' do
31
+ get '/books/1'
32
+
33
+ expect(response_status).to be 200
34
+ expect(response_body['data']).to have_link('self')
35
+ end
36
+
37
+ it 'fetches a non-existent resource' do
38
+ get '/books/foo'
39
+
40
+ expect(response_status).to be 404
41
+ end
42
+ end
@@ -0,0 +1,37 @@
1
+ RSpec.describe 'include' do
2
+ it 'fetches a single resource with includes' do
3
+ get '/books/1?include=author'
4
+
5
+ expect(response_status).to be 200
6
+ expect(response_body['data']).to have_type('books')
7
+ expect(response_body['data']).to have_id('1')
8
+ expect(response_body['data'])
9
+ .to have_relationship('author').with_data('id' => '1', 'type' => 'authors')
10
+ expect(response_body['data']).to have_relationship('series')
11
+ author = response_body['data']['relationships']['author']['data']
12
+ expect(response_body['included'])
13
+ .to include(have_type('authors').and have_id(author['id']))
14
+ end
15
+
16
+ it 'fetches a single resource with includes and stripped out relationship field' do
17
+ get '/books/1?include=author&fields[books]=title'
18
+
19
+ expect(response_status).to be 200
20
+ expect(response_body['data']).to have_type('books')
21
+ expect(response_body['data']).to have_id('1')
22
+ expect(response_body['data']).not_to have_relationship('author')
23
+ expect(response_body['data']).not_to have_relationship('series')
24
+ expect(response_body['included'])
25
+ .to include(have_type('authors'))
26
+ end
27
+
28
+ it 'includes series relationship by default' do
29
+ get '/books/1'
30
+
31
+ expect(response_status).to be 200
32
+ expect(response_body['data']).to have_type('books')
33
+ expect(response_body['data']).to have_id('1')
34
+ expect(response_body['data']).to have_relationship('series')
35
+ expect(response_body['included']).to include(have_type('series'))
36
+ end
37
+ end
@@ -0,0 +1,7 @@
1
+ RSpec.describe 'jsonapi object' do
2
+ it 'has a top level jsonapi object in the response' do
3
+ get '/books/1'
4
+
5
+ expect(response_body).to have_jsonapi_object('version' => '1.0')
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ RSpec.describe 'links' do
2
+ it 'has top level links in the response' do
3
+ get '/books/1'
4
+
5
+ expect(response_body).to have_link('root')
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ RSpec.describe 'meta' do
2
+ it 'has a top level meta in the response' do
3
+ get '/books/1'
4
+
5
+ expect(response_body).to have_meta('foo' => 'bar')
6
+ end
7
+ end
@@ -0,0 +1,30 @@
1
+ RSpec.describe 'relationships' do
2
+ it 'has a relationship meta' do
3
+ get '/books/1'
4
+
5
+ expect(response_status).to be 200
6
+
7
+ expect(response_body['data']).to have_relationship('author')
8
+ expect(response_body['data']['relationships']['author'])
9
+ .to have_meta('foo' => 'bar')
10
+ end
11
+
12
+ it 'has relationship links' do
13
+ get '/books/1'
14
+
15
+ expect(response_status).to be 200
16
+
17
+ expect(response_body['data']).to have_relationship('author')
18
+ expect(response_body['data']['relationships']['author'])
19
+ .to have_links(:related)
20
+ end
21
+
22
+ it 'does not have linkage data when relationship not included' do
23
+ get '/books/1'
24
+
25
+ expect(response_status).to be 200
26
+
27
+ expect(response_body['data']).to have_relationship('author')
28
+ expect(response_body['data']['relationships']['author']['data']).to be_nil
29
+ end
30
+ end
@@ -0,0 +1,105 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
4
+ # this file to always be loaded, without a need to explicitly require it in any
5
+ # files.
6
+ #
7
+ # Given that it is always loaded, you are encouraged to keep this file as
8
+ # light-weight as possible. Requiring heavyweight dependencies from this file
9
+ # will add to the boot time of your test suite on EVERY test run, even for an
10
+ # individual file that may not need all of that loaded. Instead, consider making
11
+ # a separate helper file that requires the additional dependencies and performs
12
+ # the additional setup, and require it from the spec files that actually need
13
+ # it.
14
+ #
15
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
16
+ RSpec.configure do |config|
17
+ # rspec-expectations config goes here. You can use an alternate
18
+ # assertion/expectation library such as wrong or the stdlib/minitest
19
+ # assertions if you prefer.
20
+ config.expect_with :rspec do |expectations|
21
+ # This option will default to `true` in RSpec 4. It makes the `description`
22
+ # and `failure_message` of custom matchers include text for helper methods
23
+ # defined using `chain`, e.g.:
24
+ # be_bigger_than(2).and_smaller_than(4).description
25
+ # # => "be bigger than 2 and smaller than 4"
26
+ # ...rather than:
27
+ # # => "be bigger than 2"
28
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
29
+ end
30
+
31
+ # rspec-mocks config goes here. You can use an alternate test double
32
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
33
+ config.mock_with :rspec do |mocks|
34
+ # Prevents you from mocking or stubbing a method that does not exist on
35
+ # a real object. This is generally recommended, and will default to
36
+ # `true` in RSpec 4.
37
+ mocks.verify_partial_doubles = true
38
+ end
39
+
40
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
41
+ # have no way to turn it off -- the option exists only for backwards
42
+ # compatibility in RSpec 3). It causes shared context metadata to be
43
+ # inherited by the metadata hash of host groups and examples, rather than
44
+ # triggering implicit auto-inclusion in groups with matching metadata.
45
+ config.shared_context_metadata_behavior = :apply_to_host_groups
46
+
47
+ # The settings below are suggested to provide a good initial experience
48
+ # with RSpec, but feel free to customize to your heart's content.
49
+ =begin
50
+ # This allows you to limit a spec run to individual examples or groups
51
+ # you care about by tagging them with `:focus` metadata. When nothing
52
+ # is tagged with `:focus`, all examples get run. RSpec also provides
53
+ # aliases for `it`, `describe`, and `context` that include `:focus`
54
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
55
+ config.filter_run_when_matching :focus
56
+
57
+ # Allows RSpec to persist some state between runs in order to support
58
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
59
+ # you configure your source control system to ignore this file.
60
+ config.example_status_persistence_file_path = "spec/examples.txt"
61
+
62
+ # Limits the available syntax to the non-monkey patched syntax that is
63
+ # recommended. For more details, see:
64
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
65
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
66
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
67
+ config.disable_monkey_patching!
68
+
69
+ # This setting enables warnings. It's recommended, but in some cases may
70
+ # be too noisy due to issues in dependencies.
71
+ config.warnings = true
72
+
73
+ # Many RSpec users commonly either run the entire suite or an individual
74
+ # file, and it's useful to allow more verbose output when running an
75
+ # individual spec file.
76
+ if config.files_to_run.one?
77
+ # Use the documentation formatter for detailed output,
78
+ # unless a formatter has already been configured
79
+ # (e.g. via a command-line flag).
80
+ config.default_formatter = "doc"
81
+ end
82
+
83
+ # Print the 10 slowest examples and example groups at the
84
+ # end of the spec run, to help surface which specs are running
85
+ # particularly slow.
86
+ config.profile_examples = 10
87
+
88
+ # Run specs in random order to surface order dependencies. If you find an
89
+ # order dependency and want to debug it, you can fix the order by providing
90
+ # the seed, which is printed after each run.
91
+ # --seed 1234
92
+ config.order = :random
93
+
94
+ # Seed global randomization in this process using the `--seed` CLI option.
95
+ # Setting this allows you to use `--seed` to deterministically reproduce
96
+ # test failures related to randomization by passing the same `--seed` value
97
+ # as the one that triggered the failure.
98
+ Kernel.srand config.seed
99
+ =end
100
+
101
+ require 'support/http_helpers'
102
+ config.include HTTPHelpers
103
+ require 'jsonapi/rspec'
104
+ config.include JSONAPI::RSpec
105
+ end
@@ -0,0 +1,52 @@
1
+ require 'net/http'
2
+ require 'json'
3
+
4
+ module HTTPHelpers
5
+ def request(klass, url, headers)
6
+ uri = URI(ENV['HOST'] + url)
7
+ req = klass.new(uri)
8
+ req['Accept'] = 'application/vnd.api+json'
9
+
10
+ yield(req) if block_given?
11
+
12
+ headers.each { |k, v| req[k.to_s] = v }
13
+
14
+ @_response = Net::HTTP.start(uri.hostname, uri.port) do |http|
15
+ http.request(req)
16
+ end
17
+ end
18
+
19
+ def get(url, headers = {})
20
+ request(Net::HTTP::Get, url, headers)
21
+ end
22
+
23
+ def post(url, payload, headers = {})
24
+ request(Net::HTTP::Post, url, headers) do |req|
25
+ req['Content-Type'] = 'application/vnd.api+json'
26
+ req.body = payload.to_json
27
+ end
28
+ end
29
+
30
+ def patch(url, payload, headers = {})
31
+ request(Net::HTTP::Patch, url, headers) do |req|
32
+ req['Content-Type'] = 'application/vnd.api+json'
33
+ req.body = payload.to_json
34
+ end
35
+ end
36
+
37
+ def delete(url, headers = {})
38
+ request(Net::HTTP::Delete, url, headers)
39
+ end
40
+
41
+ def response
42
+ @_response
43
+ end
44
+
45
+ def response_body
46
+ JSON.parse(response.body)
47
+ end
48
+
49
+ def response_status
50
+ response.code.to_i
51
+ end
52
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonapi-grader
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lucas Hosseini
@@ -9,7 +9,49 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
  date: 2017-08-02 00:00:00.000000000 Z
12
- dependencies: []
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: jsonapi-rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
13
55
  description: Ensure compliance of your JSON API library.
14
56
  email: lucas.hosseini@gmail.com
15
57
  executables:
@@ -17,20 +59,17 @@ executables:
17
59
  extensions: []
18
60
  extra_rdoc_files: []
19
61
  files:
20
- - "./lib/jsonapi/grader.rb"
21
- - "./lib/jsonapi/grader/serialization_grader.rb"
22
- - "./lib/jsonapi/grader/server/scenarii.rb"
23
- - "./lib/jsonapi/grader/server/scenarii/empty_collection.rb"
24
- - "./lib/jsonapi/grader/server/scenario.rb"
25
- - "./lib/jsonapi/grader/server_grader.rb"
26
- - "./scenarii/empty_collection.json"
27
- - "./scenarii/null_data.json"
28
- - "./scenarii/simple_resource.json"
29
- - "./scenarii/simple_resource_attributes.json"
30
- - "./scenarii/simple_resource_jsonapi_object.json"
31
- - "./scenarii/simple_resource_meta.json"
62
+ - "./spec/content_negotiation_spec.rb"
63
+ - "./spec/fetch_single_resource_spec.rb"
64
+ - "./spec/fetching_resource_collection_spec.rb"
65
+ - "./spec/include_spec.rb"
66
+ - "./spec/jsonapi_object_spec.rb"
67
+ - "./spec/links_spec.rb"
68
+ - "./spec/meta_spec.rb"
69
+ - "./spec/relationships_spec.rb"
70
+ - "./spec/spec_helper.rb"
71
+ - "./spec/support/http_helpers.rb"
32
72
  - bin/jsonapi-grader
33
- - scenarii_serialization.json
34
73
  homepage: https://github.com/beauby/jsonapi-grader
35
74
  licenses:
36
75
  - MIT
@@ -51,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
51
90
  version: '0'
52
91
  requirements: []
53
92
  rubyforge_project:
54
- rubygems_version: 2.6.12
93
+ rubygems_version: 2.6.13
55
94
  signing_key:
56
95
  specification_version: 4
57
96
  summary: Grade jsonapi.org implementations.
@@ -1,2 +0,0 @@
1
- require 'jsonapi/grader/serialization_grader'
2
- require 'jsonapi/grader/server_grader'
@@ -1,64 +0,0 @@
1
- require 'json'
2
-
3
- module JSONAPI
4
- module Grader
5
- class SerializationGrader
6
- def initialize(scenarii_file = 'scenarii_serialization.json', options = {})
7
- scenarii_file = File.expand_path("../../../#{scenarii_file}", __dir__)
8
- @scenarii = JSON.parse(File.read(scenarii_file))
9
- @implementation_dir = options[:implementation_dir]
10
- end
11
-
12
- def grade
13
- compliance = true
14
- score = 0
15
- max_score = 0
16
- @scenarii.each do |scenario|
17
- current_score = score_scenario(scenario)
18
- compliance = false if scenario['required'] && current_score == 0
19
- max_score += scenario['score']
20
- score += current_score
21
- end
22
-
23
- STDERR.puts "Compliance: #{compliance}"
24
- score_percent = (100.0 * score / max_score).round(2)
25
- STDERR.puts "Score: #{score} / #{max_score} (#{score_percent}%)"
26
-
27
- score
28
- end
29
-
30
- private
31
-
32
- def score_scenario(scenario)
33
- document_file = File.expand_path("../../../#{scenario['file']}", __dir__)
34
- reference_document = normalize(JSON.parse(File.read(document_file)))
35
- implementation = "#{@implementation_dir}/#{scenario['name']}"
36
- STDERR.print "Running scenario #{scenario['name']}... "
37
- $stderr.flush
38
- unless File.exists?(implementation)
39
- STDERR.puts "not implemented"
40
- return 0
41
- end
42
-
43
- actual_document = normalize(JSON.parse(`#{implementation}`))
44
- if reference_document == actual_document
45
- STDERR.puts "passed"
46
- return scenario['score']
47
- else
48
- STDERR.puts "failed"
49
- STDERR.puts "Expected: #{reference_document}"
50
- STDERR.puts "Got: #{actual_document}"
51
- return 0
52
- end
53
- end
54
-
55
- def normalize(document)
56
- return document unless document.key?('included')
57
-
58
- document['included'].sort do |a, b|
59
- [a['type'], a['id']] <=> [b['type'], b['id']]
60
- end
61
- end
62
- end
63
- end
64
- end
@@ -1 +0,0 @@
1
- require 'jsonapi/grader/server/scenarii/empty_collection'
@@ -1,45 +0,0 @@
1
- require 'net/http'
2
- require 'jsonapi/grader/server/scenario'
3
-
4
- module JSONAPI
5
- module Grader
6
- module Server
7
- class EmptyCollectionScenario < Scenario
8
- def name
9
- 'empty_collection'
10
- end
11
-
12
- def description
13
- 'The endpoint /empty_collection should return an empty collection.'
14
- end
15
-
16
- def score
17
- 100
18
- end
19
-
20
- def required
21
- true
22
- end
23
-
24
- def call(host)
25
- uri = URI("#{host}/empty_collection")
26
- res = Net::HTTP.start(uri.hostname, uri.port) do |http|
27
- req = Net::HTTP::Get.new(uri)
28
- req['Accept'] = 'application/vnd.api+json'
29
-
30
- http.request(req)
31
- end
32
-
33
- unless res['Content-Type'] == 'application/vnd.api+json'
34
- fail 'Expected Content-Type header to equal application/vnd.api+json'
35
- end
36
-
37
- body = JSON.parse(res.body)
38
- unless body['data'] == []
39
- fail 'Expected empty collection'
40
- end
41
- end
42
- end
43
- end
44
- end
45
- end
@@ -1,31 +0,0 @@
1
- module JSONAPI
2
- module Grader
3
- module Server
4
- class Scenario
5
- def call(host)
6
- raise 'Not implemented'
7
- end
8
-
9
- def score
10
- raise 'Not implemented'
11
- end
12
-
13
- def name
14
- raise 'Not implemented'
15
- end
16
-
17
- def description
18
- raise 'Not implemented'
19
- end
20
-
21
- def endpoint
22
- raise 'Not implemented'
23
- end
24
-
25
- def required
26
- raise 'Not implemented'
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,41 +0,0 @@
1
- require 'jsonapi/grader/server/scenarii'
2
-
3
- module JSONAPI
4
- module Grader
5
- class ServerGrader
6
- SCENARII = [Server::EmptyCollectionScenario.new]
7
-
8
- def initialize(options = {})
9
- @host = options[:host]
10
- end
11
-
12
- def grade
13
- compliance = true
14
- score = 0
15
- max_score = 0
16
- SCENARII.each do |scenario|
17
- STDERR.print "Running scenario #{scenario.name}... "
18
- $stderr.flush
19
-
20
- begin
21
- scenario.call(@host)
22
- STDERR.puts "passed"
23
- score += scenario.score
24
- rescue Exception => error
25
- STDERR.puts "failed"
26
- STDERR.puts scenario.description
27
- STDERR.puts ">>> #{error}"
28
- compliance = false if scenario.required
29
- end
30
- max_score += scenario.score
31
- end
32
-
33
- STDERR.puts "Compliance: #{compliance}"
34
- score_percent = (100.0 * score / max_score).round(2)
35
- STDERR.puts "Score: #{score} / #{max_score} (#{score_percent}%)"
36
-
37
- score
38
- end
39
- end
40
- end
41
- end
@@ -1,3 +0,0 @@
1
- {
2
- "data": []
3
- }
@@ -1,3 +0,0 @@
1
- {
2
- "data": null
3
- }
@@ -1,6 +0,0 @@
1
- {
2
- "data": {
3
- "id": "1",
4
- "type": "articles"
5
- }
6
- }
@@ -1,10 +0,0 @@
1
- {
2
- "data": {
3
- "id": "1",
4
- "type": "articles",
5
- "attributes": {
6
- "title": "json:api",
7
- "content": "I love it."
8
- }
9
- }
10
- }
@@ -1,12 +0,0 @@
1
- {
2
- "data": {
3
- "id": "1",
4
- "type": "articles"
5
- },
6
- "jsonapi": {
7
- "version": "1.0",
8
- "meta": {
9
- "compliant": "true"
10
- }
11
- }
12
- }
@@ -1,9 +0,0 @@
1
- {
2
- "data": {
3
- "id": "1",
4
- "type": "articles"
5
- },
6
- "meta": {
7
- "compliant": "true"
8
- }
9
- }
@@ -1,38 +0,0 @@
1
- [
2
- {
3
- "name": "null_data",
4
- "file": "scenarii/null_data.json",
5
- "score": 100,
6
- "required": true
7
- },
8
- {
9
- "name": "empty_collection",
10
- "file": "scenarii/empty_collection.json",
11
- "score": 100,
12
- "required": true
13
- },
14
- {
15
- "name": "simple_resource",
16
- "file": "scenarii/simple_resource.json",
17
- "score": 100,
18
- "required": true
19
- },
20
- {
21
- "name": "simple_resource_attributes",
22
- "file": "scenarii/simple_resource_attributes.json",
23
- "score": 100,
24
- "required": true
25
- },
26
- {
27
- "name": "simple_resource_meta",
28
- "file": "scenarii/simple_resource_meta.json",
29
- "score": 10,
30
- "required": false
31
- },
32
- {
33
- "name": "simple_resource_jsonapi_object",
34
- "file": "scenarii/simple_resource_jsonapi_object.json",
35
- "score": 10,
36
- "required": false
37
- }
38
- ]