-
Notifications
You must be signed in to change notification settings - Fork 420
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added ReflectionService initialiser using file paths #1699
Changes from 7 commits
92a8f2d
1fea48d
b2a0e95
f808eea
2c003ce
76bb1f1
8e0fa46
2431bd1
c738569
38b7a6f
f30f52a
cb7ab5d
65d66fb
c05eba6
2beacc0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -26,6 +26,10 @@ public final class ReflectionService: CallHandlerProvider, Sendable { | |||
self.reflectionService.serviceName | ||||
} | ||||
|
||||
public init(protoFilePaths: [String]) throws { | ||||
self.reflectionService = try ReflectionServiceProvider(protoFilePaths: protoFilePaths) | ||||
} | ||||
|
||||
public init(fileDescriptors: [Google_Protobuf_FileDescriptorProto]) throws { | ||||
self.reflectionService = try ReflectionServiceProvider(fileDescriptorProtos: fileDescriptors) | ||||
} | ||||
|
@@ -207,6 +211,27 @@ internal struct ReflectionServiceData: Sendable { | |||
internal final class ReflectionServiceProvider: Grpc_Reflection_V1_ServerReflectionAsyncProvider { | ||||
private let protoRegistry: ReflectionServiceData | ||||
|
||||
internal init(protoFilePaths: [String]) throws { | ||||
|
||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: unnecessary blank line
Suggested change
|
||||
let binaryFilesURLs = protoFilePaths.map { | ||||
#if os(Linux) | ||||
URL(fileURLWithPath: $0) | ||||
#else | ||||
if #available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) { | ||||
URL(filePath: $0, directoryHint: .notDirectory) | ||||
} else { | ||||
URL(fileURLWithPath: $0) | ||||
} | ||||
#endif | ||||
} | ||||
let binaryData = binaryFilesURLs.map { Data(base64Encoded: try! Data(contentsOf: $0)) } | ||||
let fileDescriptorProtos = binaryData.map { | ||||
try! Google_Protobuf_FileDescriptorProto(serializedData: $0!) | ||||
} | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can't We should just do the basic thing: var fileDescriptorProtos = [Google_Protobuf_FileDescriptorProto]()
for path in paths {
// ...
fileDescriptorProtos.append(...)
} |
||||
|
||||
self.protoRegistry = try ReflectionServiceData(fileDescriptors: fileDescriptorProtos) | ||||
} | ||||
|
||||
internal init(fileDescriptorProtos: [Google_Protobuf_FileDescriptorProto]) throws { | ||||
self.protoRegistry = try ReflectionServiceData( | ||||
fileDescriptors: fileDescriptorProtos | ||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,9 +33,28 @@ final class ReflectionServiceIntegrationTests: GRPCTestCase { | |
) | ||
|
||
private func setUpServerAndChannel() throws { | ||
let reflectionServiceProvider = try ReflectionService( | ||
fileDescriptors: self.protos + [self.independentProto] | ||
) | ||
var filePaths: [String] = [] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We actually don't need to do this in the integration tests: we can do it in the unit tests because the actual work is done by the registry rather than the service. This also means we can do this in a separate test as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At the moment, the ReflectionServiceProvider (not the wrapper, the class that contains the registry) is doing the conversion of Data from the file paths to serialised file descriptor protos and then initialises the registry (using the file descriptor ports). This is why I implemented the testing in the integration tests. So if I'm moving it in the Unit tests I should also move the conversion in a Proto initialiser. Should I do this? And my second question if I do this: Should I only implement unit tests for this conversion from binary data to file descriptor photos and leave all the other tests as they were before (using directly file descriptor protos)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, my mistake. Thinking about this some more, I think we can implement this as a couple of helpers on the extension ReflectionService {
static func readSerializedFileDescriptorProto(atPath path: String) throws -> Google_Protobuf_FileDescriptorProto {
// ...
}
static func readSerializedFileDescriptorProtos(atPaths paths: [String]) throws -> [Google_Protobuf_FileDescriptorProto] {
// ...
}
} This way we can test the loading independently of the registry and operation of the service. I.e. we can test that these functions can load and deserialize the serialized descriptors correctly. |
||
let fileManager = FileManager.default | ||
|
||
let fileDescriptorProtos = self.protos + [self.independentProto] | ||
for fileDescriptorProto in fileDescriptorProtos { | ||
let data = try fileDescriptorProto.serializedData() | ||
.base64EncodedData() | ||
#if os(Linux) | ||
let temporaryDirectory = "/tmp/" | ||
#else | ||
let temporaryDirectory = fileManager.temporaryDirectory.path() | ||
#endif | ||
let filePath = temporaryDirectory + fileDescriptorProto.name | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this is sufficiently unique (especially on linux): if we ran these tests in parallel we could end up removing files which another test is expecting to be there. One workaround which is probably fine is to add some randomness to the name. |
||
fileManager.createFile(atPath: filePath, contents: data) | ||
filePaths.append(filePath) | ||
} | ||
defer { | ||
for filePath in filePaths { | ||
XCTAssertNoThrow(try fileManager.removeItem(atPath: filePath)) | ||
} | ||
} | ||
let reflectionServiceProvider = try ReflectionService(protoFilePaths: filePaths) | ||
|
||
let server = try Server.insecure(group: MultiThreadedEventLoopGroup.singleton) | ||
.withServiceProviders([reflectionServiceProvider]) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We aren't loading proto files (i.e.
.proto
) we're loading serialised file descriptor protos:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This also needs documentation