|
| 1 | +// RUN: %empty-directory(%t) |
| 2 | +// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/../Inputs/FakeDistributedActorSystems.swift |
| 3 | +// 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 |
| 4 | +// RUN: %target-run %t/a.out | %FileCheck %s --color --dump-input=always |
| 5 | + |
| 6 | +// REQUIRES: executable_test |
| 7 | +// REQUIRES: concurrency |
| 8 | +// REQUIRES: distributed |
| 9 | + |
| 10 | +// rdar://76038845 |
| 11 | +// UNSUPPORTED: use_os_stdlib |
| 12 | +// UNSUPPORTED: back_deployment_runtime |
| 13 | + |
| 14 | +// FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574 |
| 15 | +// UNSUPPORTED: OS=windows-msvc |
| 16 | + |
| 17 | +import Distributed |
| 18 | +import FakeDistributedActorSystems |
| 19 | + |
| 20 | + |
| 21 | +typealias DefaultDistributedActorSystem = FakeRoundtripActorSystem |
| 22 | + |
| 23 | +protocol DistributedWorker: DistributedActor where ActorSystem == DefaultDistributedActorSystem { |
| 24 | + associatedtype WorkItem: Sendable & Codable |
| 25 | + associatedtype WorkResult: Sendable & Codable |
| 26 | + |
| 27 | + // distributed requirement currently is forced to be `async throws`... |
| 28 | + // FIXME(distributed): requirements don't have to be async throws, |
| 29 | + // distributed makes them implicitly async throws anyway... |
| 30 | + distributed func submit(work: WorkItem) async throws -> WorkResult |
| 31 | + |
| 32 | + // non distributed requirements can be witnessed with _normal_ functions |
| 33 | + func sync(work: WorkItem) -> WorkResult |
| 34 | + func async(work: WorkItem) async -> WorkResult |
| 35 | + func syncThrows(work: WorkItem) throws -> WorkResult |
| 36 | + func asyncThrows(work: WorkItem) async throws -> WorkResult |
| 37 | +} |
| 38 | + |
| 39 | +distributed actor TheWorker: DistributedWorker { |
| 40 | + typealias ActorSystem = DefaultDistributedActorSystem |
| 41 | + typealias WorkItem = String |
| 42 | + typealias WorkResult = String |
| 43 | + |
| 44 | + distributed func submit(work: WorkItem) async throws -> WorkResult { |
| 45 | + "\(#function): \(work)" |
| 46 | + } |
| 47 | + |
| 48 | + func sync(work: WorkItem) -> WorkResult { |
| 49 | + return "\(#function): \(work)" |
| 50 | + } |
| 51 | + func async(work: WorkItem) async -> WorkResult { |
| 52 | + return "\(#function): \(work)" |
| 53 | + } |
| 54 | + func syncThrows(work: WorkItem) throws -> WorkResult { |
| 55 | + return "\(#function): \(work)" |
| 56 | + } |
| 57 | + func asyncThrows(work: WorkItem) async throws -> WorkResult { |
| 58 | + return "\(#function): \(work)" |
| 59 | + } |
| 60 | +} |
| 61 | + |
| 62 | +func test_generic(system: DefaultDistributedActorSystem) async throws { |
| 63 | + let localW = TheWorker(actorSystem: system) |
| 64 | + let remoteW = try! TheWorker.resolve(id: localW.id, using: system) |
| 65 | + precondition(__isRemoteActor(remoteW)) |
| 66 | + |
| 67 | + // direct calls work ok: |
| 68 | + let replyDirect = try await remoteW.submit(work: "Direct") |
| 69 | + print("reply direct: \(replyDirect)") |
| 70 | + // CHECK: >> remoteCall: on:main.TheWorker, target:main.TheWorker.submit(work:), invocation:FakeInvocationEncoder(genericSubs: [], arguments: ["Direct"], returnType: Optional(Swift.String), errorType: Optional(Swift.Error)), throwing:Swift.Error, returning:Swift.String |
| 71 | + // CHECK: reply direct: submit(work:): Direct |
| 72 | + |
| 73 | + func callWorker<W: DistributedWorker>(w: W) async throws -> String where W.WorkItem == String, W.WorkResult == String { |
| 74 | + try await w.submit(work: "Hello") |
| 75 | + } |
| 76 | + let reply = try await callWorker(w: remoteW) |
| 77 | + print("reply (remote): \(reply)") |
| 78 | + // CHECK: >> remoteCall: on:main.TheWorker, target:main.TheWorker.submit(work:), invocation:FakeInvocationEncoder(genericSubs: [], arguments: ["Hello"], returnType: Optional(Swift.String), errorType: Optional(Swift.Error)), throwing:Swift.Error, returning:Swift.String |
| 79 | + // CHECK: << remoteCall return: submit(work:): Hello |
| 80 | + // CHECK: reply (remote): submit(work:): Hello |
| 81 | + |
| 82 | + let replyLocal = try await callWorker(w: localW) |
| 83 | + print("reply (local): \(replyLocal)") |
| 84 | + // CHECK-NOT: >> remoteCall |
| 85 | + // CHECK: reply (local): submit(work:): Hello |
| 86 | +} |
| 87 | + |
| 88 | +func test_whenLocal(system: DefaultDistributedActorSystem) async throws { |
| 89 | + let localW = TheWorker(actorSystem: system) |
| 90 | + let remoteW = try! TheWorker.resolve(id: localW.id, using: system) |
| 91 | + precondition(__isRemoteActor(remoteW)) |
| 92 | + |
| 93 | + do { |
| 94 | + let replySync = await remoteW.whenLocal { __secretlyKnownToBeLocal in |
| 95 | + __secretlyKnownToBeLocal.sync(work: "test") |
| 96 | + } |
| 97 | + print("replySync (remote): \(replySync)") |
| 98 | + // CHECK: replySync (remote): nil |
| 99 | + |
| 100 | + let replySyncThrows = try await remoteW.whenLocal { __secretlyKnownToBeLocal in |
| 101 | + try __secretlyKnownToBeLocal.syncThrows(work: "test") |
| 102 | + } |
| 103 | + print("replySyncThrows (remote): \(replySyncThrows)") |
| 104 | + // CHECK: replySyncThrows (remote): nil |
| 105 | + |
| 106 | + let replyAsync = await remoteW.whenLocal { __secretlyKnownToBeLocal in |
| 107 | + await __secretlyKnownToBeLocal.async(work: "test") |
| 108 | + } |
| 109 | + print("replyAsync (remote): \(replyAsync)") |
| 110 | + // CHECK: replyAsync (remote): nil |
| 111 | + |
| 112 | + let replyAsyncThrows = try await remoteW.whenLocal { __secretlyKnownToBeLocal in |
| 113 | + try await __secretlyKnownToBeLocal.asyncThrows(work: "test") |
| 114 | + } |
| 115 | + print("replyAsyncThrows (remote): \(replyAsyncThrows)") |
| 116 | + // CHECK: replyAsyncThrows (remote): nil |
| 117 | + } |
| 118 | + // ==== ---------------------------------------------------------------------- |
| 119 | + |
| 120 | + do { |
| 121 | + let replyDistSubmit = try await localW.whenLocal { __secretlyKnownToBeLocal in |
| 122 | + try await __secretlyKnownToBeLocal.submit(work: "local-test") |
| 123 | + } |
| 124 | + print("replyDistSubmit (local): \(replyDistSubmit ?? "nil")") |
| 125 | + // CHECK-NOT: >> remoteCall |
| 126 | + // CHECK: replyDistSubmit (local): submit(work:): local-test |
| 127 | + |
| 128 | + let replySyncLocal = await localW.whenLocal { __secretlyKnownToBeLocal in |
| 129 | + __secretlyKnownToBeLocal.sync(work: "local-test") |
| 130 | + } |
| 131 | + print("replySyncLocal (local): \(replySyncLocal ?? "nil")") |
| 132 | + // CHECK-NOT: >> remoteCall |
| 133 | + // CHECK: replySyncLocal (local): sync(work:): local-test |
| 134 | + |
| 135 | + let replySyncThrowsLocal = try await localW.whenLocal { __secretlyKnownToBeLocal in |
| 136 | + try __secretlyKnownToBeLocal.syncThrows(work: "local-test") |
| 137 | + } |
| 138 | + print("replySyncThrowsLocal (local): \(replySyncThrowsLocal ?? "nil")") |
| 139 | + // CHECK-NOT: >> remoteCall |
| 140 | + // CHECK: replySyncThrowsLocal (local): syncThrows(work:): local-test |
| 141 | + |
| 142 | + let replyAsyncLocal = await localW.whenLocal { __secretlyKnownToBeLocal in |
| 143 | + await __secretlyKnownToBeLocal.async(work: "local-test") |
| 144 | + } |
| 145 | + print("replyAsyncLocal (local): \(replyAsyncLocal ?? "nil")") |
| 146 | + // CHECK-NOT: >> remoteCall |
| 147 | + // CHECK: replyAsyncLocal (local): async(work:): local-test |
| 148 | + |
| 149 | + let replyAsyncThrowsLocal = try await localW.whenLocal { __secretlyKnownToBeLocal in |
| 150 | + try await __secretlyKnownToBeLocal.asyncThrows(work: "local-test") |
| 151 | + } |
| 152 | + print("replyAsyncThrowsLocal (local): \(replyAsyncThrowsLocal ?? "nil")") |
| 153 | + // CHECK-NOT: >> remoteCall |
| 154 | + // CHECK: replyAsyncThrowsLocal (local): asyncThrows(work:): local-test |
| 155 | + } |
| 156 | +} |
| 157 | + |
| 158 | +@main struct Main { |
| 159 | + static func main() async { |
| 160 | + let system = DefaultDistributedActorSystem() |
| 161 | + try! await test_generic(system: system) |
| 162 | + print("==== ---------------------------------------------------") |
| 163 | + try! await test_whenLocal(system: system) |
| 164 | + } |
| 165 | +} |
0 commit comments