skeleton 0.3.3 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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