@@ -170,6 +170,206 @@ func (x) TestAllExtensionNumbersForTypeName(t *testing.T) {
170
170
}
171
171
}
172
172
173
+ func (x ) TestFileDescWithDependencies (t * testing.T ) {
174
+ depFile , err := protodesc .NewFile (
175
+ & descriptorpb.FileDescriptorProto {
176
+ Name : proto .String ("dep.proto" ),
177
+ }, nil ,
178
+ )
179
+ if err != nil {
180
+ t .Fatalf ("unexpected error: %s" , err )
181
+ }
182
+
183
+ deps := & protoregistry.Files {}
184
+ if err := deps .RegisterFile (depFile ); err != nil {
185
+ t .Fatalf ("unexpected error: %s" , err )
186
+ }
187
+
188
+ rootFileProto := & descriptorpb.FileDescriptorProto {
189
+ Name : proto .String ("root.proto" ),
190
+ Dependency : []string {
191
+ "google/protobuf/descriptor.proto" ,
192
+ "reflection/grpc_testing/proto2_ext2.proto" ,
193
+ "dep.proto" ,
194
+ },
195
+ }
196
+
197
+ // dep.proto is in deps; the other imports come from protoregistry.GlobalFiles
198
+ resolver := & combinedResolver {first : protoregistry .GlobalFiles , second : deps }
199
+ rootFile , err := protodesc .NewFile (rootFileProto , resolver )
200
+ if err != nil {
201
+ t .Fatalf ("unexpected error: %s" , err )
202
+ }
203
+
204
+ // Create a file hierarchy that contains a placeholder for dep.proto
205
+ placeholderDep := placeholderFile {depFile }
206
+ placeholderDeps := & protoregistry.Files {}
207
+ if err := placeholderDeps .RegisterFile (placeholderDep ); err != nil {
208
+ t .Fatalf ("unexpected error: %s" , err )
209
+ }
210
+ resolver = & combinedResolver {first : protoregistry .GlobalFiles , second : placeholderDeps }
211
+
212
+ rootFileHasPlaceholderDep , err := protodesc .NewFile (rootFileProto , resolver )
213
+ if err != nil {
214
+ t .Fatalf ("unexpected error: %s" , err )
215
+ }
216
+
217
+ rootFileIsPlaceholder := placeholderFile {rootFile }
218
+
219
+ // Full transitive dependency graph of root.proto includes five files:
220
+ // - root.proto
221
+ // - google/protobuf/descriptor.proto
222
+ // - reflection/grpc_testing/proto2_ext2.proto
223
+ // - reflection/grpc_testing/proto2.proto
224
+ // - dep.proto
225
+
226
+ for _ , test := range []struct {
227
+ name string
228
+ sent []string
229
+ root protoreflect.FileDescriptor
230
+ expect []string
231
+ }{
232
+ {
233
+ name : "send_all" ,
234
+ root : rootFile ,
235
+ // expect full transitive closure
236
+ expect : []string {
237
+ "root.proto" ,
238
+ "google/protobuf/descriptor.proto" ,
239
+ "reflection/grpc_testing/proto2_ext2.proto" ,
240
+ "reflection/grpc_testing/proto2.proto" ,
241
+ "dep.proto" ,
242
+ },
243
+ },
244
+ {
245
+ name : "already_sent" ,
246
+ sent : []string {
247
+ "root.proto" ,
248
+ "google/protobuf/descriptor.proto" ,
249
+ "reflection/grpc_testing/proto2_ext2.proto" ,
250
+ "reflection/grpc_testing/proto2.proto" ,
251
+ "dep.proto" ,
252
+ },
253
+ root : rootFile ,
254
+ // expect only the root to be re-sent
255
+ expect : []string {"root.proto" },
256
+ },
257
+ {
258
+ name : "some_already_sent" ,
259
+ sent : []string {
260
+ "reflection/grpc_testing/proto2_ext2.proto" ,
261
+ "reflection/grpc_testing/proto2.proto" ,
262
+ },
263
+ root : rootFile ,
264
+ expect : []string {
265
+ "root.proto" ,
266
+ "google/protobuf/descriptor.proto" ,
267
+ "dep.proto" ,
268
+ },
269
+ },
270
+ {
271
+ name : "root_is_placeholder" ,
272
+ root : rootFileIsPlaceholder ,
273
+ // expect error, no files
274
+ },
275
+ {
276
+ name : "placeholder_skipped" ,
277
+ root : rootFileHasPlaceholderDep ,
278
+ // dep.proto is a placeholder so is skipped
279
+ expect : []string {
280
+ "root.proto" ,
281
+ "google/protobuf/descriptor.proto" ,
282
+ "reflection/grpc_testing/proto2_ext2.proto" ,
283
+ "reflection/grpc_testing/proto2.proto" ,
284
+ },
285
+ },
286
+ {
287
+ name : "placeholder_skipped_and_some_sent" ,
288
+ sent : []string {
289
+ "reflection/grpc_testing/proto2_ext2.proto" ,
290
+ "reflection/grpc_testing/proto2.proto" ,
291
+ },
292
+ root : rootFileHasPlaceholderDep ,
293
+ expect : []string {
294
+ "root.proto" ,
295
+ "google/protobuf/descriptor.proto" ,
296
+ },
297
+ },
298
+ } {
299
+ t .Run (test .name , func (t * testing.T ) {
300
+ s := NewServerV1 (ServerOptions {}).(* serverReflectionServer )
301
+
302
+ sent := map [string ]bool {}
303
+ for _ , path := range test .sent {
304
+ sent [path ] = true
305
+ }
306
+
307
+ descriptors , err := s .fileDescWithDependencies (test .root , sent )
308
+ if len (test .expect ) == 0 {
309
+ // if we're not expecting any files then we're expecting an error
310
+ if err == nil {
311
+ t .Fatalf ("expecting an error; instead got %d files" , len (descriptors ))
312
+ }
313
+ return
314
+ }
315
+
316
+ checkDescriptorResults (t , descriptors , test .expect )
317
+ })
318
+ }
319
+ }
320
+
321
+ func checkDescriptorResults (t * testing.T , descriptors [][]byte , expect []string ) {
322
+ t .Helper ()
323
+ if len (descriptors ) != len (expect ) {
324
+ t .Errorf ("expected result to contain %d descriptor(s); instead got %d" , len (expect ), len (descriptors ))
325
+ }
326
+ names := map [string ]struct {}{}
327
+ for i , desc := range descriptors {
328
+ var descProto descriptorpb.FileDescriptorProto
329
+ if err := proto .Unmarshal (desc , & descProto ); err != nil {
330
+ t .Fatalf ("could not unmarshal descriptor result #%d" , i + 1 )
331
+ }
332
+ names [descProto .GetName ()] = struct {}{}
333
+ }
334
+ actual := make ([]string , 0 , len (names ))
335
+ for name := range names {
336
+ actual = append (actual , name )
337
+ }
338
+ sort .Strings (actual )
339
+ sort .Strings (expect )
340
+ if ! reflect .DeepEqual (actual , expect ) {
341
+ t .Fatalf ("expected file descriptors for %v; instead got %v" , expect , actual )
342
+ }
343
+ }
344
+
345
+ type placeholderFile struct {
346
+ protoreflect.FileDescriptor
347
+ }
348
+
349
+ func (placeholderFile ) IsPlaceholder () bool {
350
+ return true
351
+ }
352
+
353
+ type combinedResolver struct {
354
+ first , second protodesc.Resolver
355
+ }
356
+
357
+ func (r * combinedResolver ) FindFileByPath (path string ) (protoreflect.FileDescriptor , error ) {
358
+ file , err := r .first .FindFileByPath (path )
359
+ if err == nil {
360
+ return file , nil
361
+ }
362
+ return r .second .FindFileByPath (path )
363
+ }
364
+
365
+ func (r * combinedResolver ) FindDescriptorByName (name protoreflect.FullName ) (protoreflect.Descriptor , error ) {
366
+ desc , err := r .first .FindDescriptorByName (name )
367
+ if err == nil {
368
+ return desc , nil
369
+ }
370
+ return r .second .FindDescriptorByName (name )
371
+ }
372
+
173
373
// Do end2end tests.
174
374
175
375
type server struct {
0 commit comments