service_contract 0.0.10 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/lib/service_contract/avro/endpoint.rb +2 -0
- data/lib/service_contract/avro/protocol.rb +5 -0
- data/lib/service_contract/avro/type.rb +15 -1
- data/lib/service_contract/version.rb +1 -1
- data/test/assertions_test.rb +18 -1
- data/test/sample/1/compiled/city_state.avpr +68 -0
- data/test/sample/1/source/city_state.avdl +30 -0
- data/test/sample/2/compiled/search_param.avpr +25 -0
- data/test/sample/2/source/search_param.avdl +12 -0
- data/test/service_test.rb +57 -2
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8cb40a77b33371d743328e30c58742c07a57d77c
|
4
|
+
data.tar.gz: b9bc84d00c6147ef1c3ecfec18ad7753cf17ec89
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b18b92ce0dcd4eefa1dac486dc51e98bfa4b6353717fb0175b0781b297c0f94694f85942071b49b40d9ea04069c3a9ae6b08b5e6daf3cf9fe7b6fc46f55b6863
|
7
|
+
data.tar.gz: 8f02a7a4235704d826932c5cb5b3d1c9b7f9f2ae9ce1a43f277af081b3d19a6020984202ffe6e922eb57b5eae24db855452c4a7958138d25cee09324814f462b
|
data/.gitignore
CHANGED
@@ -21,6 +21,11 @@ module ServiceContract
|
|
21
21
|
File.join(service.path, resource_name)
|
22
22
|
end
|
23
23
|
|
24
|
+
def main_type
|
25
|
+
# convert protocol name to a class like name. i.e. "city_state" => "CityState"
|
26
|
+
name.split("_").map{|o| o.capitalize}.join
|
27
|
+
end
|
28
|
+
|
24
29
|
protected
|
25
30
|
|
26
31
|
def resource_name
|
@@ -16,7 +16,9 @@ module ServiceContract
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def to_s
|
19
|
-
name
|
19
|
+
return name unless union?
|
20
|
+
|
21
|
+
union_types.map(&:name).join(", ")
|
20
22
|
end
|
21
23
|
|
22
24
|
def subtype
|
@@ -36,6 +38,10 @@ module ServiceContract
|
|
36
38
|
type_string == "record"
|
37
39
|
end
|
38
40
|
|
41
|
+
def union?
|
42
|
+
type_string == "union"
|
43
|
+
end
|
44
|
+
|
39
45
|
def valid_ruby_types
|
40
46
|
case type_string
|
41
47
|
when "array"
|
@@ -48,6 +54,10 @@ module ServiceContract
|
|
48
54
|
[Float]
|
49
55
|
when "boolean"
|
50
56
|
[TrueClass, FalseClass]
|
57
|
+
when "null"
|
58
|
+
[NilClass]
|
59
|
+
when "union"
|
60
|
+
union_types.map(&:valid_ruby_types).flatten
|
51
61
|
else # a complex type
|
52
62
|
[Hash]
|
53
63
|
end
|
@@ -55,6 +65,10 @@ module ServiceContract
|
|
55
65
|
|
56
66
|
protected
|
57
67
|
|
68
|
+
def union_types
|
69
|
+
definition.schemas.map{|schema| Type.build(schema)}
|
70
|
+
end
|
71
|
+
|
58
72
|
def type_string
|
59
73
|
type = definition.type
|
60
74
|
type = type.type_sym.to_s if type.respond_to?(:type_sym)
|
data/test/assertions_test.rb
CHANGED
@@ -8,7 +8,7 @@ class AssertionsTest < Minitest::Test
|
|
8
8
|
assert service, "expect to find a service by version"
|
9
9
|
assert_equal "1", service.version
|
10
10
|
|
11
|
-
assert_equal
|
11
|
+
assert_equal 3, service.protocols.length
|
12
12
|
protocol = service.protocol("location")
|
13
13
|
endpoint = protocol.endpoint("index")
|
14
14
|
|
@@ -41,4 +41,21 @@ class AssertionsTest < Minitest::Test
|
|
41
41
|
assert_endpoint_response(data, endpoint)
|
42
42
|
end
|
43
43
|
|
44
|
+
def test_union_data_matching
|
45
|
+
service = SampleService.find(2)
|
46
|
+
assert service, "expect to find a service by version"
|
47
|
+
|
48
|
+
protocol = service.protocol("search_param")
|
49
|
+
endpoint = protocol.endpoint("index")
|
50
|
+
|
51
|
+
# test can be nil
|
52
|
+
assert_endpoint_response([{customer_id: nil}], endpoint)
|
53
|
+
|
54
|
+
# should be able to be an integer
|
55
|
+
assert_endpoint_response([{customer_id: 4}], endpoint)
|
56
|
+
|
57
|
+
# should be able to be an array of ints
|
58
|
+
assert_endpoint_response([{customer_id: [1,2,3]}], endpoint)
|
59
|
+
end
|
60
|
+
|
44
61
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
{
|
2
|
+
"protocol" : "CityState",
|
3
|
+
"namespace" : "Gnomon",
|
4
|
+
"types" : [ {
|
5
|
+
"type" : "record",
|
6
|
+
"name" : "Timestamp",
|
7
|
+
"fields" : [ {
|
8
|
+
"name" : "timestamp",
|
9
|
+
"type" : "int"
|
10
|
+
} ]
|
11
|
+
}, {
|
12
|
+
"type" : "record",
|
13
|
+
"name" : "CityState",
|
14
|
+
"doc" : "This main class for this protocol",
|
15
|
+
"fields" : [ {
|
16
|
+
"name" : "id",
|
17
|
+
"type" : "int",
|
18
|
+
"doc" : "foo"
|
19
|
+
}, {
|
20
|
+
"name" : "city_id",
|
21
|
+
"type" : "int"
|
22
|
+
}, {
|
23
|
+
"name" : "state_id",
|
24
|
+
"type" : "int"
|
25
|
+
} ]
|
26
|
+
}, {
|
27
|
+
"type" : "record",
|
28
|
+
"name" : "FetchOption",
|
29
|
+
"fields" : [ {
|
30
|
+
"name" : "page",
|
31
|
+
"type" : "int",
|
32
|
+
"default" : 0
|
33
|
+
}, {
|
34
|
+
"name" : "per_page",
|
35
|
+
"type" : "int",
|
36
|
+
"default" : 30
|
37
|
+
} ]
|
38
|
+
} ],
|
39
|
+
"messages" : {
|
40
|
+
"bogus" : {
|
41
|
+
"doc" : "bogus method for testing no parameters",
|
42
|
+
"request" : [ ],
|
43
|
+
"response" : "null"
|
44
|
+
},
|
45
|
+
"non_member_method" : {
|
46
|
+
"doc" : "method that uses non \"main_type\" as the first parameter is considered non-member",
|
47
|
+
"request" : [ {
|
48
|
+
"name" : "options",
|
49
|
+
"type" : "FetchOption"
|
50
|
+
} ],
|
51
|
+
"response" : {
|
52
|
+
"type" : "array",
|
53
|
+
"items" : "CityState"
|
54
|
+
}
|
55
|
+
},
|
56
|
+
"member_method" : {
|
57
|
+
"doc" : "method that uses \"main_type\" as the first parameter is considered member",
|
58
|
+
"request" : [ {
|
59
|
+
"name" : "params",
|
60
|
+
"type" : "CityState"
|
61
|
+
} ],
|
62
|
+
"response" : {
|
63
|
+
"type" : "array",
|
64
|
+
"items" : "CityState"
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}
|
68
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
@namespace("Gnomon")
|
2
|
+
|
3
|
+
protocol CityState {
|
4
|
+
|
5
|
+
record Timestamp {
|
6
|
+
int timestamp;
|
7
|
+
}
|
8
|
+
|
9
|
+
/** This main class for this protocol */
|
10
|
+
record CityState {
|
11
|
+
/** foo */
|
12
|
+
int id;
|
13
|
+
int city_id;
|
14
|
+
int state_id;
|
15
|
+
}
|
16
|
+
|
17
|
+
record FetchOption {
|
18
|
+
int page = 0;
|
19
|
+
int per_page = 30;
|
20
|
+
}
|
21
|
+
|
22
|
+
/** bogus method for testing no parameters */
|
23
|
+
void bogus();
|
24
|
+
|
25
|
+
/** method that uses non "main_type" as the first parameter is considered non-member */
|
26
|
+
array<CityState> non_member_method(FetchOption options);
|
27
|
+
|
28
|
+
/** method that uses "main_type" as the first parameter is considered member */
|
29
|
+
array<CityState> member_method(CityState params);
|
30
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
{
|
2
|
+
"protocol" : "SearchParam",
|
3
|
+
"namespace" : "Gnomon",
|
4
|
+
"types" : [ {
|
5
|
+
"type" : "record",
|
6
|
+
"name" : "SearchParam",
|
7
|
+
"fields" : [ {
|
8
|
+
"name" : "customer_id",
|
9
|
+
"type" : [ "null", "int", {
|
10
|
+
"type" : "array",
|
11
|
+
"items" : "int"
|
12
|
+
} ],
|
13
|
+
"doc" : "Required search params"
|
14
|
+
} ]
|
15
|
+
} ],
|
16
|
+
"messages" : {
|
17
|
+
"index" : {
|
18
|
+
"request" : [ ],
|
19
|
+
"response" : {
|
20
|
+
"type" : "array",
|
21
|
+
"items" : "SearchParam"
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
data/test/service_test.rb
CHANGED
@@ -3,7 +3,7 @@ require 'test_helper'
|
|
3
3
|
class ServiceTest < Minitest::Test
|
4
4
|
|
5
5
|
def test_all
|
6
|
-
assert_equal(
|
6
|
+
assert_equal(2, SampleService.all.length)
|
7
7
|
end
|
8
8
|
|
9
9
|
def test_find
|
@@ -11,11 +11,66 @@ class ServiceTest < Minitest::Test
|
|
11
11
|
assert service, "expect to find a service by version"
|
12
12
|
assert_equal "1", service.version
|
13
13
|
|
14
|
-
assert_equal
|
14
|
+
assert_equal 3, service.protocols.length
|
15
15
|
protocol = service.protocol("location")
|
16
16
|
|
17
17
|
assert_equal "location", protocol.name
|
18
18
|
assert_equal 3, protocol.endpoints.length
|
19
19
|
end
|
20
20
|
|
21
|
+
def test_null_params
|
22
|
+
# the member? method would error if the endpoint method had no parameters. This test verifies the fix.
|
23
|
+
service = SampleService.find(1)
|
24
|
+
protocol = service.protocol("city_state")
|
25
|
+
|
26
|
+
# find the endpoint with no parameters.
|
27
|
+
empty_param_endpoints = protocol.endpoints.select{|e| e.parameters.empty?}
|
28
|
+
assert !empty_param_endpoints.empty?
|
29
|
+
|
30
|
+
empty_param_endpoints.each do |endpoint|
|
31
|
+
assert_equal(false, endpoint.send("member?"))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# The member? method determines if an endpoint is a "member" by looking at its first parameter. If that parameter
|
36
|
+
# is equal to the 'main_type' then it is a member, otherwise it is not a member. Main_type is nothing more than the
|
37
|
+
# classname of the protocol.
|
38
|
+
def test_member_endpoint
|
39
|
+
service = SampleService.find(1)
|
40
|
+
protocol = service.protocol("city_state")
|
41
|
+
|
42
|
+
# only one endpoint is a member method, "member_method"
|
43
|
+
member_names = protocol.endpoints.select{|e| e.send("member?")}.map(&:name)
|
44
|
+
assert_equal(1, member_names.length)
|
45
|
+
assert_equal('member_method', member_names.first)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_non_member_endpoint
|
49
|
+
service = SampleService.find(1)
|
50
|
+
protocol = service.protocol("city_state")
|
51
|
+
|
52
|
+
# two endpoints are non member method, "bogus" and "non_member_method"
|
53
|
+
non_member_names = protocol.endpoints.select{|e| !e.send("member?")}.map(&:name)
|
54
|
+
assert_equal(2, non_member_names.length)
|
55
|
+
assert non_member_names.include?('non_member_method')
|
56
|
+
assert non_member_names.include?('bogus')
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_union_types
|
60
|
+
service = SampleService.find(2)
|
61
|
+
protocol = service.protocol('search_param')
|
62
|
+
|
63
|
+
type = protocol.type('SearchParam')
|
64
|
+
assert(type, 'expected to find a SearchParam type')
|
65
|
+
|
66
|
+
field = type.fields.detect{|field| field.name == 'customer_id'}
|
67
|
+
assert(field, 'expected to find a customer_id field')
|
68
|
+
|
69
|
+
field_type = field.type
|
70
|
+
|
71
|
+
assert_equal('union', field_type.name)
|
72
|
+
assert_equal('null, int, Array(int)', field_type.to_s)
|
73
|
+
assert_equal([NilClass, Fixnum, Array], field_type.valid_ruby_types)
|
74
|
+
end
|
75
|
+
|
21
76
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: service_contract
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Ching
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: avro
|
@@ -120,10 +120,14 @@ files:
|
|
120
120
|
- src/avro-tools-1.7.7.jar
|
121
121
|
- test/assertions_test.rb
|
122
122
|
- test/mock_test.rb
|
123
|
+
- test/sample/1/compiled/city_state.avpr
|
123
124
|
- test/sample/1/compiled/location.avpr
|
124
125
|
- test/sample/1/compiled/sales_region.avpr
|
126
|
+
- test/sample/1/source/city_state.avdl
|
125
127
|
- test/sample/1/source/location.avdl
|
126
128
|
- test/sample/1/source/sales_region.avdl
|
129
|
+
- test/sample/2/compiled/search_param.avpr
|
130
|
+
- test/sample/2/source/search_param.avdl
|
127
131
|
- test/service_test.rb
|
128
132
|
- test/test_helper.rb
|
129
133
|
homepage: ''
|
@@ -153,10 +157,14 @@ summary: Abstract the definition of a service's interface contract
|
|
153
157
|
test_files:
|
154
158
|
- test/assertions_test.rb
|
155
159
|
- test/mock_test.rb
|
160
|
+
- test/sample/1/compiled/city_state.avpr
|
156
161
|
- test/sample/1/compiled/location.avpr
|
157
162
|
- test/sample/1/compiled/sales_region.avpr
|
163
|
+
- test/sample/1/source/city_state.avdl
|
158
164
|
- test/sample/1/source/location.avdl
|
159
165
|
- test/sample/1/source/sales_region.avdl
|
166
|
+
- test/sample/2/compiled/search_param.avpr
|
167
|
+
- test/sample/2/source/search_param.avdl
|
160
168
|
- test/service_test.rb
|
161
169
|
- test/test_helper.rb
|
162
170
|
has_rdoc:
|