[Distributed] Add more tests for implicit Codable on distributed actors

This commit is contained in:
Konrad `ktoso` Malawski
2024-04-16 21:29:28 +09:00
parent 70757ffe5e
commit efd8cbf978
3 changed files with 270 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/../Inputs/FakeDistributedActorSystems.swift
// RUN: %target-build-swift -module-name main -Xfrontend -disable-availability-checking -j2 -parse-as-library -I %t %s %S/../Inputs/FakeDistributedActorSystems.swift -o %t/a.out
// RUN: %target-codesign %t/a.out
// RUN: %target-run %t/a.out | %FileCheck %s --dump-input=always
// REQUIRES: executable_test
// REQUIRES: concurrency
// REQUIRES: distributed
// rdar://76038845
// UNSUPPORTED: use_os_stdlib
// UNSUPPORTED: back_deployment_runtime
// UNSUPPORTED: OS=windows-msvc
import Distributed
extension UInt8: CustomSerializationProtocol {
public func toBytes() throws -> [UInt8] {
[self]
}
public static func fromBytes(_ bytes: [UInt8]) throws -> Self {
bytes.first!
}
}
distributed actor Tester {
typealias ActorSystem = FakeCustomSerializationRoundtripActorSystem
distributed func echo(param: UInt8) -> UInt8 {
param
}
}
// ==== ------------------------------------------------------------------------
func test() async throws {
let system = FakeCustomSerializationRoundtripActorSystem()
let local = Tester(actorSystem: system)
let ref = try Tester.resolve(id: local.id, using: system)
let reply = try await ref.echo(param: 2)
// CHECK: >> remoteCall: on:main.Tester, target:main.Tester.echo(param:), invocation:FakeCustomSerializationInvocationEncoder(genericSubs: [], arguments: [2], returnType: Optional(Swift.UInt8), errorType: nil), throwing:Swift.Never, returning:Swift.UInt8
// CHECK: << remoteCall return: 2
print("reply: \(reply)")
// CHECK: reply: 2
}
@main struct Main {
static func main() async {
try! await test()
}
}

View File

@@ -0,0 +1,169 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/../Inputs/FakeDistributedActorSystems.swift
// RUN: %target-build-swift -module-name main -Xfrontend -disable-availability-checking -j2 -parse-as-library -I %t %s %S/../Inputs/FakeDistributedActorSystems.swift -o %t/a.out
// RUN: %target-codesign %t/a.out
// RUN: %target-run %t/a.out | %FileCheck %s --color
// REQUIRES: executable_test
// REQUIRES: concurrency
// REQUIRES: distributed
// We're using Foundation for the JSON Encoder, could be done without but good enough
// REQUIRES: objc_interop
// rdar://76038845
// UNSUPPORTED: use_os_stdlib
// UNSUPPORTED: back_deployment_runtime
import Foundation
import Distributed
final class LocalActorSystem : DistributedActorSystem {
typealias ActorID = LocalTestingActorID
typealias ResultHandler = LocalTestingInvocationResultHandler
typealias InvocationEncoder = LocalTestingInvocationEncoder
typealias InvocationDecoder = LocalTestingInvocationDecoder
typealias SerializationRequirement = any Codable
func makeInvocationEncoder() -> InvocationEncoder { LocalTestingDistributedActorSystem().makeInvocationEncoder() }
func resolve<Act>(id: ActorID, as actorType: Act.Type) throws -> Act? where Act: DistributedActor {
nil
}
func actorReady<Act>(_ actor: Act) where Act: DistributedActor, Act.ID == ActorID {
}
func resignID(_ id: ActorID) {}
func assignID<Act>(_ actorType: Act.Type) -> ActorID
where Act: DistributedActor {
.init(id: "42")
}
func remoteCall<Act, Err, Res>(on actor: Act,
target: RemoteCallTarget,
invocation: inout InvocationEncoder,
throwing: Err.Type,
returning: Res.Type) async throws -> Res
where Act: DistributedActor,
Act.ID == ActorID,
Err: Error,
Res: Codable {
let decoder = JSONDecoder()
return try! decoder.decode(Res.self, from: await fetchData())
}
func remoteCallVoid<Act, Err>(on actor: Act,
target: RemoteCallTarget,
invocation: inout InvocationEncoder,
throwing errorType: Err.Type) async throws
where Act: DistributedActor,
Act.ID == ActorID,
Err: Error {
fatalError("not implemented: \(#function)")
}
func fetchData() async -> Data {
"42".data(using: .ascii)!
}
}
distributed actor NotCodableDA<ActorSystem>
where ActorSystem: DistributedActorSystem<any Codable> {
init(actorSystem: ActorSystem) async {
self.actorSystem = actorSystem
print(try! await self.request())
}
func request() async throws -> Int {
let target = RemoteCallTarget("test.request")
var encoder = actorSystem.makeInvocationEncoder()
return try await actorSystem.remoteCall(on: self,
target: target,
invocation: &encoder,
throwing: Error.self,
returning: Int.self)
}
}
distributed actor CodableDA<ActorSystem>: Codable
where ActorSystem: DistributedActorSystem<any Codable>,
ActorSystem.ActorID: Codable {
init(actorSystem: ActorSystem) async {
self.actorSystem = actorSystem
print(try! await self.request())
}
func request() async throws -> Int {
let target = RemoteCallTarget("test.request")
var encoder = actorSystem.makeInvocationEncoder()
return try await actorSystem.remoteCall(on: self,
target: target,
invocation: &encoder,
throwing: Error.self,
returning: Int.self)
}
}
distributed actor CodableIDDA<ActorSystem>
where ActorSystem: DistributedActorSystem<any Codable>,
ActorSystem.ActorID: Codable {
init(actorSystem: ActorSystem) async {
self.actorSystem = actorSystem
print(try! await self.request())
}
func request() async throws -> Int {
let target = RemoteCallTarget("test.request")
var encoder = actorSystem.makeInvocationEncoder()
return try await actorSystem.remoteCall(on: self,
target: target,
invocation: &encoder,
throwing: Error.self,
returning: Int.self)
}
}
@main struct Main {
static func main() async throws {
if #available(SwiftStdlib 5.9, *) {
let system = LocalActorSystem()
let ncda = await NotCodableDA(actorSystem: system)
let cidda = await CodableIDDA(actorSystem: system)
let cda = await CodableDA(actorSystem: system)
try await ncda.whenLocal {
let got = try await $0.request()
// CHECK: got = 42
print("got = \(got)")
}
try await cidda.whenLocal {
let got = try await $0.request()
// CHECK: got = 42
print("got = \(got)")
}
let _: any (DistributedActor & Codable) = cda
try await cda.whenLocal {
let got = try await $0.request()
// CHECK: got = 42
print("got = \(got)")
}
// CHECK: OK
print("OK")
}
}
}

View File

@@ -17,3 +17,48 @@ func take<A: Codable>(actor: A) {}
func test(actorSystem: FakeActorSystem) {
take(actor: DA(actorSystem: actorSystem)) // ok
}
func takeCodable<A: Codable>(actor: A) {}
func test_DA(actorSystem: FakeActorSystem) {
takeCodable(actor: DA(actorSystem: actorSystem)) // ok
}
// ==== Generic actors
distributed actor DAG<ActorSystem>
where ActorSystem: DistributedActorSystem<any Codable> {
}
func test_DAG(actorSystem: FakeActorSystem) {
takeCodable(actor: DAG<FakeActorSystem>(actorSystem: actorSystem)) // ok
}
distributed actor DAG_ID<ActorSystem>
where ActorSystem: DistributedActorSystem<any Codable>,
ID: Codable { // expected-error{{cannot find type 'ID' in scope}}
}
func test_DAG_ID(actorSystem: FakeActorSystem) {
takeCodable(actor: DAG_ID<FakeActorSystem>(actorSystem: actorSystem)) // ok
}
distributed actor DAG_ActorSystem_ActorID<ActorSystem>
where ActorSystem: DistributedActorSystem<any Codable>,
ActorSystem.ActorID: Codable {
}
func test_DAG_ActorSystem_ActorID(actorSystem: FakeActorSystem) {
takeCodable(actor: DAG_ActorSystem_ActorID<FakeActorSystem>(actorSystem: actorSystem)) // ok
}
// ==== Not codable cases
protocol SerializableButNotCodable {}
distributed actor DAG_ActorSystem_ActorID_Custom<ActorSystem>
where ActorSystem: DistributedActorSystem<any SerializableButNotCodable> {
// expected-note@-2{{requirement specified as 'ActorSystem.SerializationRequirement' == 'any SerializableButNotCodable'}}
}
func test_DAG_ActorSystem_ActorID_Custom(actorSystem: FakeActorSystem) {
takeCodable(actor: DAG_ActorSystem_ActorID_Custom<FakeActorSystem>(actorSystem: actorSystem))
// expected-error@-1{{'DAG_ActorSystem_ActorID_Custom' requires the types 'any FakeActorSystem.SerializationRequirement' (aka 'any Decodable & Encodable') and 'any SerializableButNotCodable' be equivalent}}
}