1# Copyright 2015 gRPC authors. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15require 'spec_helper' 16require 'grpc/generic/rpc_desc' 17require 'grpc/generic/service' 18 19# A test message that encodes/decodes using marshal/marshal. 20class GoodMsg 21 def self.marshal(_o) 22 '' 23 end 24 25 def self.unmarshal(_o) 26 GoodMsg.new 27 end 28end 29 30# A test message that encodes/decodes using encode/decode. 31class EncodeDecodeMsg 32 def self.encode(_o) 33 '' 34 end 35 36 def self.decode(_o) 37 GoodMsg.new 38 end 39end 40 41GenericService = GRPC::GenericService 42Dsl = GenericService::Dsl 43 44describe Dsl do 45 it 'can be included in new classes' do 46 blk = proc { Class.new { include Dsl } } 47 expect(&blk).to_not raise_error 48 end 49end 50 51describe GenericService do 52 context '#underscore' do 53 it 'should convert CamelCase to underscore separated' do 54 expect(GenericService.underscore('AnRPC')).to eq('an_rpc') 55 expect(GenericService.underscore('AMethod')).to eq('a_method') 56 expect(GenericService.underscore('PrintHTML')).to eq('print_html') 57 expect(GenericService.underscore('SeeHTMLBooks')).to eq('see_html_books') 58 end 59 end 60 61 describe 'including it' do 62 it 'adds a class method, rpc' do 63 c = Class.new do 64 include GenericService 65 end 66 expect(c.methods).to include(:rpc) 67 end 68 69 it 'adds rpc descs using the added class method, #rpc' do 70 c = Class.new do 71 include GenericService 72 rpc :AnRpc, GoodMsg, GoodMsg 73 end 74 75 expect(c.rpc_descs).to include(:AnRpc) 76 expect(c.rpc_descs[:AnRpc]).to be_a(GRPC::RpcDesc) 77 end 78 79 it 'give subclasses access to #rpc_descs' do 80 base = Class.new do 81 include GenericService 82 rpc :AnRpc, GoodMsg, GoodMsg 83 end 84 c = Class.new(base) do 85 end 86 expect(c.rpc_descs).to include(:AnRpc) 87 expect(c.rpc_descs[:AnRpc]).to be_a(GRPC::RpcDesc) 88 end 89 90 it 'adds a default service name' do 91 c = Class.new do 92 include GenericService 93 end 94 expect(c.service_name).to eq('GenericService') 95 end 96 97 it 'adds a default service name to subclasses' do 98 base = Class.new do 99 include GenericService 100 end 101 c = Class.new(base) do 102 end 103 expect(c.service_name).to eq('GenericService') 104 end 105 106 it 'adds the specified service name' do 107 c = Class.new do 108 include GenericService 109 self.service_name = 'test.service.TestService' 110 end 111 expect(c.service_name).to eq('test.service.TestService') 112 end 113 114 it 'adds the specified service name to subclasses' do 115 base = Class.new do 116 include GenericService 117 self.service_name = 'test.service.TestService' 118 end 119 c = Class.new(base) do 120 end 121 expect(c.service_name).to eq('test.service.TestService') 122 end 123 end 124 125 describe '#include' do 126 it 'raises if #rpc is missing an arg' do 127 blk = proc do 128 Class.new do 129 include GenericService 130 rpc :AnRpc, GoodMsg 131 end 132 end 133 expect(&blk).to raise_error ArgumentError 134 135 blk = proc do 136 Class.new do 137 include GenericService 138 rpc :AnRpc 139 end 140 end 141 expect(&blk).to raise_error ArgumentError 142 end 143 144 describe 'when #rpc args are incorrect' do 145 it 'raises if an arg does not have the marshal or unmarshal methods' do 146 blk = proc do 147 Class.new do 148 include GenericService 149 rpc :AnRpc, GoodMsg, Object 150 end 151 end 152 expect(&blk).to raise_error ArgumentError 153 end 154 155 it 'raises if a type arg only has the marshal method' do 156 # a bad message type with only a marshal method 157 class OnlyMarshal 158 def marshal(o) 159 o 160 end 161 end 162 163 blk = proc do 164 Class.new do 165 include GenericService 166 rpc :AnRpc, OnlyMarshal, GoodMsg 167 end 168 end 169 expect(&blk).to raise_error ArgumentError 170 end 171 172 it 'raises if a type arg only has the unmarshal method' do 173 # a bad message type with only an unmarshal method 174 class OnlyUnmarshal 175 def self.ummarshal(o) 176 o 177 end 178 end 179 blk = proc do 180 Class.new do 181 include GenericService 182 rpc :AnRpc, GoodMsg, OnlyUnmarshal 183 end 184 end 185 expect(&blk).to raise_error ArgumentError 186 end 187 end 188 189 it 'is ok for services that expect the default {un,}marshal methods' do 190 blk = proc do 191 Class.new do 192 include GenericService 193 rpc :AnRpc, GoodMsg, GoodMsg 194 end 195 end 196 expect(&blk).not_to raise_error 197 end 198 199 it 'is ok for services that override the default {un,}marshal methods' do 200 blk = proc do 201 Class.new do 202 include GenericService 203 self.marshal_class_method = :encode 204 self.unmarshal_class_method = :decode 205 rpc :AnRpc, EncodeDecodeMsg, EncodeDecodeMsg 206 end 207 end 208 expect(&blk).not_to raise_error 209 end 210 end 211 212 describe '#rpc_stub_class' do 213 it 'generates a client class that defines any of the rpc methods' do 214 s = Class.new do 215 include GenericService 216 rpc :AnRpc, GoodMsg, GoodMsg 217 rpc :AServerStreamer, GoodMsg, stream(GoodMsg) 218 rpc :AClientStreamer, stream(GoodMsg), GoodMsg 219 rpc :ABidiStreamer, stream(GoodMsg), stream(GoodMsg) 220 end 221 client_class = s.rpc_stub_class 222 expect(client_class.instance_methods).to include(:an_rpc) 223 expect(client_class.instance_methods).to include(:a_server_streamer) 224 expect(client_class.instance_methods).to include(:a_client_streamer) 225 expect(client_class.instance_methods).to include(:a_bidi_streamer) 226 end 227 228 describe 'the generated instances' do 229 it 'can be instanciated with just a hostname and credentials' do 230 s = Class.new do 231 include GenericService 232 rpc :AnRpc, GoodMsg, GoodMsg 233 rpc :AServerStreamer, GoodMsg, stream(GoodMsg) 234 rpc :AClientStreamer, stream(GoodMsg), GoodMsg 235 rpc :ABidiStreamer, stream(GoodMsg), stream(GoodMsg) 236 end 237 client_class = s.rpc_stub_class 238 blk = proc do 239 client_class.new('fakehostname', :this_channel_is_insecure) 240 end 241 expect(&blk).not_to raise_error 242 end 243 244 it 'has the methods defined in the service' do 245 s = Class.new do 246 include GenericService 247 rpc :AnRpc, GoodMsg, GoodMsg 248 rpc :AServerStreamer, GoodMsg, stream(GoodMsg) 249 rpc :AClientStreamer, stream(GoodMsg), GoodMsg 250 rpc :ABidiStreamer, stream(GoodMsg), stream(GoodMsg) 251 end 252 client_class = s.rpc_stub_class 253 o = client_class.new('fakehostname', :this_channel_is_insecure) 254 expect(o.methods).to include(:an_rpc) 255 expect(o.methods).to include(:a_bidi_streamer) 256 expect(o.methods).to include(:a_client_streamer) 257 expect(o.methods).to include(:a_bidi_streamer) 258 end 259 end 260 end 261end 262