Skip to content

Commit ac5bc08

Browse files
Support tracking media upload progress in Swift (#717)
* Build multipart-form content * Implement uploading media in the Swift wrapper * Fix a compiling issue on Linux * Fix swiftlint format issues * Fix a swiftlint issue * Change upload_media error type to the correct one * Fix swiftlint issues * Add request_id parameter to the create media API * Support tracking media upload progress * Add a code comment * Post notifications when tasks are created * Use `URLSession.uploadTask` to upload media The progress reporting is much more accurate than using `URLRequest.httpBodyStream`. * Fix swiftlint issues * Fix integration tests * Add integration tests to the Swift wrapper * Remove an unused import * Add integration tests for the Swift wrapper * Add uploading media to the Example app * Remove an unnecessary docker-compose option * Fix swiftlint issues * Fix a compiling issue in the Kotlin tests * Simplify propogating URLSessionTask progress updates * Fix dir permission issue in Swift integration tests * PR Suggestions (#732) 1. Allows uploading videos because small files don’t show progress properly 2. Adds `file.startAccessingSecurityScopedResource` for files outside the app sandbox --------- Co-authored-by: Jeremy Massel <[email protected]>
1 parent dfefcbe commit ac5bc08

File tree

21 files changed

+606
-130
lines changed

21 files changed

+606
-130
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/bash -eu
2+
3+
# Give read/write permissions to `./` for all users
4+
chmod -R a+rw ./
5+
6+
echo "--- :docker: Setting up Test Server"
7+
make test-server
8+
9+
echo "--- 🧪 Running Swift Tests"
10+
make test-swift-linux

.buildkite/pipeline.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,7 @@ steps:
103103
agents:
104104
queue: mac
105105
- label: ":swift: :linux: Build and Test"
106-
command: |
107-
echo "--- :swift: Building + Testing"
108-
make test-swift-linux
106+
command: ".buildkite/commands/run-swift-tests-linux.sh"
109107
- label: ":swift: Lint"
110108
command: |
111109
.buildkite/download-xcframework.sh

Makefile

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,6 @@ xcframework-package: xcframework-all
137137
xcframework-package-checksum:
138138
swift package compute-checksum libwordpressFFI.xcframework.zip | tee libwordpressFFI.xcframework.zip.checksum.txt
139139

140-
141-
docker-image-swift:
142-
docker build -t wordpress-rs-swift -f Dockerfile.swift .
143-
144140
docker-image-web:
145141
docker build -t wordpress-rs-web -f wp_rs_web/Dockerfile . --progress=plain
146142

@@ -162,8 +158,8 @@ swift-example-app-ios:
162158
test-swift:
163159
$(MAKE) test-swift-$(uname)
164160

165-
test-swift-linux: docker-image-swift
166-
docker run $(docker_opts_shared) -it wordpress-rs-swift make test-swift-linux-in-docker
161+
test-swift-linux:
162+
docker compose run --rm swift make test-swift-linux-in-docker
167163

168164
test-swift-linux-in-docker: swift-linux-library
169165
swift test -Xlinker -Ltarget/release/libwordpressFFI-linux -Xlinker -lwp_api

Package.resolved

Lines changed: 1 addition & 82 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ var package = Package(
4040
path: "native/swift/Sources/wordpress-api",
4141
swiftSettings: [
4242
.enableExperimentalFeature("StrictConcurrency"),
43+
.define("PROGRESS_REPORTING_ENABLED", .when(platforms: [.iOS, .macOS, .tvOS, .watchOS]))
4344
]
4445
),
4546
.target(
@@ -63,9 +64,12 @@ var package = Package(
6364
.target(name: libwordpressFFI.name)
6465
],
6566
path: "native/swift/Tests/wordpress-api",
66-
resources: [.copy("../../../../test-data/integration-test-responses/")]
67+
resources: [.copy("../../../../test-data/integration-test-responses/")],
68+
swiftSettings: [
69+
.define("PROGRESS_REPORTING_ENABLED", .when(platforms: [.iOS, .macOS, .tvOS, .watchOS]))
70+
]
6771
)
68-
]
72+
].addingIntegrationTests()
6973
)
7074

7175
// MARK: - Enable local development toolings
@@ -121,3 +125,34 @@ func enableSwiftLint() throws {
121125
package.dependencies.append(.package(url: "https://github.com/realm/SwiftLint", exact: .init(version)!))
122126
#endif
123127
}
128+
129+
extension Array where Element == Target {
130+
131+
// Run `make test-server` before running integration tests.
132+
func addingIntegrationTests() -> Self {
133+
var enabled = false
134+
135+
if Context.environment["BUILDKITE"] != nil {
136+
// When running on CI, only enable integration tests on Linux, since macOS CI agent does not have docker.
137+
#if os(Linux)
138+
enabled = true
139+
#endif
140+
} else {
141+
// Enable integration tests during local development, since we can easily install docker env on our macOS.
142+
enabled = true
143+
}
144+
145+
if enabled {
146+
return self + [.testTarget(
147+
name: "IntegrationTests",
148+
dependencies: [
149+
.target(name: "WordPressAPI"),
150+
],
151+
path: "native/swift/Tests/integration-tests",
152+
resources: [.copy("../../../../test-data/")]
153+
)]
154+
} else {
155+
return self
156+
}
157+
}
158+
}

docker-compose.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ services:
2828
timeout: 1s
2929
retries: 30
3030

31+
swift:
32+
build:
33+
context: .
34+
dockerfile: swift.Dockerfile
35+
volumes:
36+
- ./:/app
37+
working_dir: /app
38+
environment:
39+
- TEST_ALL_PLUGINS
40+
- CARGO_HOME=/app/.cargo
41+
3142
database:
3243
image: 'public.ecr.aws/docker/library/mariadb:11.2'
3344
ports:

native/kotlin/api/kotlin/src/integrationTest/kotlin/MediaEndpointTest.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ class MediaEndpointTest {
6767
requestBuilder.media().create(
6868
params = MediaCreateParams(title = title),
6969
"test_media.jpg",
70-
"image/jpeg"
70+
"image/jpeg",
71+
null
7172
)
7273
}.assertSuccessAndRetrieveData().data
7374
assertEquals(title, response.title.rendered)

native/swift/Example/Example.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
24A3C32F2BA8F96F00162AD1 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A3C32E2BA8F96F00162AD1 /* LoginView.swift */; };
2121
24A3C3362BAA874C00162AD1 /* LoginManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A3C3352BAA874C00162AD1 /* LoginManager.swift */; };
2222
24E77D032CE44DD900F6998C /* WordPressAPI in Frameworks */ = {isa = PBXBuildFile; productRef = 24E77D022CE44DD900F6998C /* WordPressAPI */; };
23+
4A0CD45C2DD15C280046FE28 /* UploadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A0CD45B2DD15C280046FE28 /* UploadView.swift */; };
2324
/* End PBXBuildFile section */
2425

2526
/* Begin PBXFileReference section */
@@ -36,6 +37,7 @@
3637
24A3C32E2BA8F96F00162AD1 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; };
3738
24A3C3342BAA45B800162AD1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
3839
24A3C3352BAA874C00162AD1 /* LoginManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginManager.swift; sourceTree = "<group>"; };
40+
4A0CD45B2DD15C280046FE28 /* UploadView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadView.swift; sourceTree = "<group>"; };
3941
/* End PBXFileReference section */
4042

4143
/* Begin PBXFrameworksBuildPhase section */
@@ -59,6 +61,7 @@
5961
242D64932C3608C6007CA96C /* ListView.swift */,
6062
242D64912C360687007CA96C /* RootListView.swift */,
6163
24A3C32E2BA8F96F00162AD1 /* LoginView.swift */,
64+
4A0CD45B2DD15C280046FE28 /* UploadView.swift */,
6265
);
6366
path = UI;
6467
sourceTree = "<group>";
@@ -189,6 +192,7 @@
189192
isa = PBXSourcesBuildPhase;
190193
buildActionMask = 2147483647;
191194
files = (
195+
4A0CD45C2DD15C280046FE28 /* UploadView.swift in Sources */,
192196
242D64922C360687007CA96C /* RootListView.swift in Sources */,
193197
2479BF812B621CB60014A01D /* ExampleApp.swift in Sources */,
194198
24A3C32F2BA8F96F00162AD1 /* LoginView.swift in Sources */,

native/swift/Example/Example/ExampleApp.swift

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ struct ExampleApp: App {
1212
@StateObject
1313
var loginManager = LoginManager()
1414

15+
@State var showUploadView = false
16+
1517
let rootListItems = [
1618
RootListData(name: "Application Passwords", callback: {
1719
try await WordPressAPI.globalInstance.applicationPasswords.listWithEditContext(userId: 1)
@@ -70,29 +72,36 @@ struct ExampleApp: App {
7072

7173
// Initial content for the third column.
7274
Text("Select a category of settings in the sidebar.")
73-
}.toolbar(content: {
74-
#if os(macOS)
75-
ToolbarItem {
75+
}
76+
.sheet(isPresented: $showUploadView) {
77+
UploadView()
78+
}
79+
.toolbar(content: {
80+
ToolbarItem(placement: toolbarItemPlacement) {
7681
Button("Log Out") {
7782
Task {
7883
await loginManager.logout()
7984
}
8085
}
8186
}
82-
#else
83-
ToolbarItem(placement: .bottomBar) {
84-
Button("Log Out") {
85-
Task {
86-
await loginManager.logout()
87-
}
87+
ToolbarItem(placement: toolbarItemPlacement) {
88+
Button("Add Media File") {
89+
showUploadView = true
8890
}
8991
}
90-
#endif
9192
})
9293
} else {
9394
LoginView()
9495
}
9596
}
9697
.environmentObject(loginManager)
9798
}
99+
100+
var toolbarItemPlacement: ToolbarItemPlacement {
101+
#if os(macOS)
102+
.automatic
103+
#else
104+
.bottomBar
105+
#endif
106+
}
98107
}

0 commit comments

Comments
 (0)