skeleton 0.3.3 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/README.md +140 -65
  4. data/Rakefile +10 -3
  5. data/lib/skeleton.rb +6 -10
  6. data/lib/skeleton/contact.rb +1 -13
  7. data/lib/skeleton/error.rb +4 -0
  8. data/lib/skeleton/graph.rb +56 -0
  9. data/lib/skeleton/header.rb +2 -63
  10. data/lib/skeleton/items.rb +34 -0
  11. data/lib/skeleton/license.rb +1 -12
  12. data/lib/skeleton/model.rb +13 -17
  13. data/lib/skeleton/operation.rb +50 -121
  14. data/lib/skeleton/parameter.rb +31 -88
  15. data/lib/skeleton/parameters.rb +40 -0
  16. data/lib/skeleton/path.rb +42 -80
  17. data/lib/skeleton/presenter.rb +19 -0
  18. data/lib/skeleton/property.rb +6 -0
  19. data/lib/skeleton/response.rb +24 -45
  20. data/lib/skeleton/schema.rb +80 -63
  21. data/lib/skeleton/scope.rb +18 -0
  22. data/lib/skeleton/security_scheme.rb +19 -37
  23. data/lib/skeleton/serializers/options.rb +215 -0
  24. data/lib/skeleton/serializers/swagger.rb +197 -0
  25. data/lib/skeleton/structure.rb +92 -138
  26. data/lib/skeleton/swagger.rb +9 -0
  27. data/lib/skeleton/tag.rb +11 -16
  28. data/lib/skeleton/version.rb +1 -1
  29. data/skeleton.gemspec +2 -0
  30. data/test/fixtures/json-schema-draft-04.json +150 -0
  31. data/test/fixtures/schema.json +1482 -0
  32. data/test/integrations/validate_complex_schema_spec.rb +42 -0
  33. data/test/skeleton/graph_test.rb +22 -0
  34. data/test/skeleton/mapper_test.rb +84 -0
  35. data/test/skeleton/operation_test.rb +11 -0
  36. data/test/skeleton/parameter_test.rb +34 -0
  37. data/test/skeleton/parameters_test.rb +9 -0
  38. data/test/skeleton/path_test.rb +46 -0
  39. data/test/skeleton/property_test.rb +8 -0
  40. data/test/skeleton/serializers/options_test.rb +68 -0
  41. data/test/skeleton/serializers/swagger_test.rb +30 -0
  42. data/test/support/factories/structure_factory.rb +86 -0
  43. data/test/support/fixtures.rb +6 -0
  44. data/test/support/kissmetrics/core_api.rb +542 -0
  45. data/{spec/spec_helper.rb → test/test_helper.rb} +7 -1
  46. metadata +73 -25
  47. data/lib/skeleton/config.rb +0 -37
  48. data/lib/skeleton/documentation.rb +0 -17
  49. data/lib/skeleton/example.rb +0 -31
  50. data/lib/skeleton/headers.rb +0 -50
  51. data/lib/skeleton/helpers/controller_helpers.rb +0 -25
  52. data/lib/skeleton/info.rb +0 -40
  53. data/lib/skeleton/item.rb +0 -99
  54. data/lib/skeleton/responses.rb +0 -59
  55. data/lib/skeleton/scopes.rb +0 -24
  56. data/lib/skeleton/security_definitions.rb +0 -46
  57. data/lib/skeleton/security_requirement.rb +0 -29
  58. data/spec/integrations/use_case_spec.rb +0 -131
  59. data/spec/skeleton/operation_spec.rb +0 -113
  60. data/spec/skeleton/serializers/contact_spec.rb +0 -30
  61. data/spec/skeleton/serializers/documentation_spec.rb +0 -23
  62. data/spec/skeleton/serializers/header_spec.rb +0 -57
@@ -0,0 +1,42 @@
1
+ require 'test_helper'
2
+ require 'multi_json'
3
+ require 'json-schema'
4
+
5
+ require 'skeleton/serializers/swagger'
6
+
7
+ describe 'Validate complex schemas' do
8
+ context 'KISSmetrics Core API' do
9
+ it 'conforms to the Swagger v2.0 Schema' do
10
+ # JSON Validator will reach out and grab this draft. This is to avoid
11
+ # the intermittent errors that occur
12
+ stub_request(:get, "http://json-schema.org/draft-04/schema")
13
+ .to_return({
14
+ status: 200,
15
+ body: Fixtures.read('json-schema-draft-04.json')
16
+ })
17
+
18
+ structure = KISSmetrics::CoreAPI.structure
19
+ hash = Skeleton::Serializers::Swagger.new(structure).to_h
20
+ schema = MultiJson.load(Fixtures.read('schema.json'))
21
+
22
+ errors = JSON::Validator.fully_validate(schema, hash, :errors_as_objects => true)
23
+
24
+ unless errors.empty?
25
+ messages = [
26
+ "JSON Validation Failed",
27
+ "Errors: #{errors.length}"
28
+ ]
29
+
30
+ errors.each do |e|
31
+ messages << ' '.concat(e[:message])
32
+ messages << ' => '.concat(e[:fragment])
33
+ messages << ' => '.concat(e[:failed_attribute])
34
+ messages << ' => '.concat(e[:schema])
35
+ messages << ''
36
+ end
37
+
38
+ fail(messages.join("\n"))
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,22 @@
1
+ require 'test_helper'
2
+
3
+ require 'skeleton/graph'
4
+
5
+ module Skeleton
6
+ class GraphTest < Minitest::Test
7
+ def test_integration
8
+ graph = Skeleton::Graph.new
9
+ graph.register('Accounts', ['Meta', 'AccountData', 'Link'])
10
+ graph.register('Meta', 'Error')
11
+ graph.register('Error', 'Error')
12
+ graph.register('Accounts', 'AccountData')
13
+ graph.register('AccountData', 'Contact')
14
+ graph.register('Accounts', 'Link')
15
+
16
+ expected = Set.new(%w(Accounts Meta AccountData Link Contact Error))
17
+ actual = Set.new
18
+ graph.each_dependent_for('Accounts') { |n| actual.add(n) }
19
+ assert_equal(expected, actual)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,84 @@
1
+ require 'test_helper'
2
+
3
+ require 'skeleton'
4
+
5
+ module Skeleton
6
+ class MapperTest < Minitest::Test
7
+
8
+ def structure
9
+ @structure ||= Skeleton::Structure.new
10
+ end
11
+
12
+ def setup
13
+ structure.configure do
14
+ define_model('Link') do
15
+ describe('The link object used for api discovery')
16
+ required(:href, type: 'string')
17
+ required(:rel, type: 'string')
18
+ optional(:templated, type: 'boolean')
19
+ optional(:name, type: 'string')
20
+ end
21
+
22
+ define_model('Error') do
23
+ describe('Represents an error')
24
+ required(:message, type: 'string')
25
+ optional(:field, type: 'string')
26
+ optional(:errors, type: 'array', items: { ref: 'Error' })
27
+ end
28
+
29
+ define_model('Meta') do
30
+ describe('The meta information regarding the request')
31
+ required(:status, type: 'integer')
32
+ optional(:message, type: 'string')
33
+ optional(:errors, type: 'array', items: { ref: 'Error' })
34
+ end
35
+
36
+ define_model('ErrorResponse') do
37
+ describe('The information when there is an issue with a request')
38
+ required(:meta, ref: 'Meta')
39
+ required(:links, type: 'array', items: { ref: 'Link' })
40
+ end
41
+
42
+ define_model('Contact') do
43
+ optional(:name, type: 'string')
44
+ optional(:country, type: 'string')
45
+ optional(:phone, type: 'string')
46
+ end
47
+
48
+ define_model('AccountData') do
49
+ required(:id, type: 'string', format: 'uuid')
50
+ required(:name, type: 'string')
51
+ required(:status, type: 'string', enum: %w(active canceled))
52
+ required(:created_at, type: 'string', format: 'date-time')
53
+ required(:updated_at, type: 'string', format: 'date-time')
54
+ required(:contact, ref: 'Contact')
55
+ optional(:links, type: 'array', items: { ref: 'Link' })
56
+ end
57
+
58
+ define_model('Account') do
59
+ required(:meta, ref: 'Meta')
60
+ required(:data, ref: 'AccountData')
61
+ required(:links, type: 'array', items: { ref: 'Link' })
62
+ end
63
+
64
+ define_model('Accounts') do
65
+ required(:meta, ref: 'Meta')
66
+ required(:data, type: 'array', items: { ref: 'AccountData' })
67
+ required(:links, type: 'array', items: { ref: 'Link' })
68
+ end
69
+
70
+ define_path('/accounts') do
71
+ get do
72
+ response(200) do
73
+ describe 'get a list of accounts'
74
+ schema(ref: 'Accounts')
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end # end setup
80
+
81
+ def test_the_mapping
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,11 @@
1
+ require 'test_helper'
2
+
3
+ require 'skeleton/operation'
4
+
5
+ module Skeleton
6
+ class OperationTest < Minitest::Test
7
+ def setup
8
+ @operation = Skeleton::Operation.new
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,34 @@
1
+ require 'test_helper'
2
+
3
+ require 'skeleton/parameter'
4
+
5
+ module Skeleton
6
+ class ParameterTests < Minitest::Test
7
+ def parameter
8
+ @parameter ||= Skeleton::Parameter.new
9
+ end
10
+
11
+ def test_body?
12
+ parameter.location = 'body'
13
+ assert(parameter.body?)
14
+ end
15
+
16
+ def test_query?
17
+ parameter.location = 'query'
18
+ refute(parameter.body?)
19
+ assert(parameter.query?)
20
+ end
21
+
22
+ def test_path?
23
+ parameter.location = 'path'
24
+ refute(parameter.body?)
25
+ assert(parameter.path?)
26
+ end
27
+
28
+ def test_header?
29
+ parameter.location = 'header'
30
+ refute(parameter.body?)
31
+ assert(parameter.header?)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,9 @@
1
+ require 'skeleton/parameters'
2
+
3
+ module Skeleton
4
+ class ParametersTest < Minitest::Test
5
+ def setup
6
+ @parameters = Skeleton::Parameters.new
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,46 @@
1
+ require 'test_helper'
2
+
3
+ require 'skeleton/path'
4
+
5
+ module Skeleton
6
+ class PathTest < Minitest::Test
7
+ def setup
8
+ @path = Skeleton::Path.new
9
+ end
10
+ def test_get
11
+ @path.get do
12
+ end
13
+ assert(@path.operations.key?(:get), 'expected the get operation to be present')
14
+ end
15
+
16
+ def test_put
17
+ @path.put do
18
+ end
19
+ assert(@path.operations.key?(:put), 'expected the put operation to be present')
20
+ end
21
+
22
+ def test_post
23
+ @path.post do
24
+ end
25
+ assert(@path.operations.key?(:post), 'expected the post operation to be present')
26
+ end
27
+
28
+ def test_patch
29
+ @path.patch do
30
+ end
31
+ assert(@path.operations.key?(:patch), 'expected the patch operation to be present')
32
+ end
33
+
34
+ def test_delete
35
+ @path.delete do
36
+ end
37
+ assert(@path.operations.key?(:delete), 'expected the delete operation to be present')
38
+ end
39
+
40
+ def test_options
41
+ @path.options do
42
+ end
43
+ assert(@path.operations.key?(:options), 'expected the options operation to be present')
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,8 @@
1
+ require 'test_helper'
2
+
3
+ require 'skeleton/property'
4
+
5
+ module Skeleton
6
+ class PropertyTest < Minitest::Test
7
+ end
8
+ end
@@ -0,0 +1,68 @@
1
+ require 'test_helper'
2
+
3
+ module Skeleton
4
+ module Serializers
5
+ class OptionsTest < Minitest::Test
6
+ def structure
7
+ @structure ||= Skeleton::Structure.new
8
+ end
9
+
10
+ def serializer
11
+ @serializer ||= Skeleton::Serializers::Options.new(structure, path: '/accounts')
12
+ end
13
+
14
+ def test_deeply_nested_dependencies
15
+ Factories::StructureFactory.configure_basic_structure(structure)
16
+ hash = serializer.to_h
17
+
18
+ refute_nil(hash[:definitions], 'Expected definitions to be present')
19
+ refute_nil(hash[:definitions]['Accounts'])
20
+ refute_nil(hash[:definitions]['AccountData'])
21
+ refute_nil(hash[:definitions]['Meta'])
22
+ refute_nil(hash[:definitions]['Error'])
23
+ refute_nil(hash[:definitions]['Link'])
24
+ refute_nil(hash[:definitions]['Contact'])
25
+ refute_nil(hash[:definitions]['ErrorResponse'])
26
+ end
27
+
28
+ def test_empty_structure
29
+ assert_raises(Skeleton::Error) { serializer.to_h }
30
+ end
31
+
32
+ def test_reference_non_existant_model
33
+ structure.define_path('/accounts') do
34
+ get do
35
+ response(200) do
36
+ schema(ref: 'Foo')
37
+ end
38
+ end
39
+ end
40
+ structure.define_model('Foo') do
41
+ property(:bar, type: 'array', items: { ref: 'Bar' })
42
+ end
43
+
44
+ hash = serializer.to_h
45
+
46
+ refute_nil(hash[:definitions], 'Expected definitions to be present')
47
+ refute_nil(hash[:definitions]['Foo'], 'Expected Foo to be present')
48
+ assert_empty(hash[:definitions]['Bar'], 'Expected Bar to be empty')
49
+ end
50
+
51
+ def test_path_that_does_not_exist
52
+ structure.define_model('Foo') do
53
+ property(:bar, type: 'array', items: { ref: 'Bar' })
54
+ end
55
+
56
+ assert_raises(Skeleton::Error) do
57
+ serializer.to_h
58
+ end
59
+ end
60
+
61
+ def test_path_not_specified
62
+ assert_raises(Skeleton::Error) do
63
+ Skeleton::Serializers::Options.new(structure)
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,30 @@
1
+ require 'test_helper'
2
+
3
+ module Skeleton
4
+ module Serializers
5
+ class SwaggerTest < Minitest::Test
6
+ def structure
7
+ @structure ||= Skeleton::Structure.new
8
+ end
9
+
10
+ def serializer
11
+ @serializer ||= Skeleton::Serializers::Swagger.new(structure)
12
+ end
13
+
14
+ def test_empty_structure
15
+ result = serializer.to_h
16
+ assert_equal('2.0', result[:swagger])
17
+ refute_nil(result[:info], 'expected the info hash to be present')
18
+
19
+ assert(result.key?(:basePath))
20
+ assert(result.key?(:host))
21
+ assert_empty(result[:schemes])
22
+ assert_empty(result[:consumes])
23
+ assert_empty(result[:produces])
24
+ assert_empty(result[:tags])
25
+ assert_empty(result[:paths])
26
+ assert_empty(result[:definitions])
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,86 @@
1
+ require 'skeleton'
2
+
3
+ module Factories
4
+ class StructureFactory
5
+ def self.build_basic_structure
6
+ structure = Skeleton::Structure.new
7
+ configure_basic_structure(structure)
8
+ structure
9
+ end
10
+
11
+ def self.configure_basic_structure(structure)
12
+ structure.configure do
13
+ define_model('Link') do
14
+ describe('The link object used for api discovery')
15
+ required(:href, type: 'string')
16
+ required(:rel, type: 'string')
17
+ optional(:templated, type: 'boolean')
18
+ optional(:name, type: 'string')
19
+ end
20
+
21
+ define_model('Error') do
22
+ describe('Represents an error')
23
+ required(:message, type: 'string')
24
+ optional(:field, type: 'string')
25
+ optional(:errors, type: 'array', items: { ref: 'Error' })
26
+ end
27
+
28
+ define_model('Meta') do
29
+ describe('The meta information regarding the request')
30
+ required(:status, type: 'integer')
31
+ optional(:message, type: 'string')
32
+ optional(:errors, type: 'array', items: { ref: 'Error' })
33
+ end
34
+
35
+ define_model('ErrorResponse') do
36
+ describe('The information when there is an issue with a request')
37
+ required(:meta, ref: 'Meta')
38
+ required(:links, type: 'array', items: { ref: 'Link' })
39
+ end
40
+
41
+ define_model('Contact') do
42
+ optional(:name, type: 'string')
43
+ optional(:country, type: 'string')
44
+ optional(:phone, type: 'string')
45
+ end
46
+
47
+ define_model('AccountData') do
48
+ required(:id, type: 'string', format: 'uuid')
49
+ required(:name, type: 'string')
50
+ required(:status, type: 'string', enum: %w(active canceled))
51
+ required(:created_at, type: 'string', format: 'date-time')
52
+ required(:updated_at, type: 'string', format: 'date-time')
53
+ required(:contact, ref: 'Contact')
54
+ optional(:links, type: 'array', items: { ref: 'Link' })
55
+ end
56
+
57
+ define_model('Account') do
58
+ required(:meta, ref: 'Meta')
59
+ required(:data, ref: 'AccountData')
60
+ required(:links, type: 'array', items: { ref: 'Link' })
61
+ end
62
+
63
+ define_model('Accounts') do
64
+ required(:meta, ref: 'Meta')
65
+ required(:data, type: 'array', items: { ref: 'AccountData' })
66
+ required(:links, type: 'array', items: { ref: 'Link' })
67
+ end
68
+
69
+ define_path('/accounts') do
70
+ get do
71
+ response(200) do
72
+ describe 'get a list of accounts'
73
+ schema(ref: 'Accounts')
74
+ end
75
+ response(403) do
76
+ describe 'access denied'
77
+ schema(ref: 'ErrorResponse')
78
+ end
79
+ end
80
+ end
81
+ end
82
+ structure
83
+ end
84
+
85
+ end
86
+ end