appium-webdriveragent 16.5.1 → 16.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/WebDriverAgent.xcodeproj/project.pbxproj +48 -300
- package/WebDriverAgentLib/Info.plist +2 -2
- package/WebDriverAgentLib/Routing/{WatchOS/FBWatchHTTPServer.h → FBHTTPServer.h} +11 -7
- package/WebDriverAgentLib/Routing/{WatchOS/FBWatchHTTPServer.m → FBHTTPServer.m} +26 -13
- package/WebDriverAgentLib/Routing/FBTCPSocket.h +17 -45
- package/WebDriverAgentLib/Routing/FBTCPSocket.m +16 -95
- package/WebDriverAgentLib/Routing/FBWebServer.h +1 -1
- package/WebDriverAgentLib/Routing/FBWebServer.m +5 -55
- package/WebDriverAgentLib/Routing/{WatchOS/RouteRequest.h → RouteRequest.h} +2 -4
- package/WebDriverAgentLib/Routing/{WatchOS/RouteResponse.h → RouteResponse.h} +2 -2
- package/WebDriverAgentLib/Utilities/FBMjpegServer.h +7 -0
- package/WebDriverAgentLib/Utilities/FBMjpegServer.m +15 -16
- package/WebDriverAgentTests/IntegrationTests_watchOS/IntegrationTests_watchOS-Bridging-Header.h +2 -0
- package/WebDriverAgentTests/IntegrationTests_watchOS/WDAMjpegStreamingIntegrationTests.swift +81 -0
- package/package.json +1 -1
- package/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncSocket.h +0 -1220
- package/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncSocket.m +0 -8786
- package/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncUdpSocket.h +0 -1036
- package/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncUdpSocket.m +0 -5868
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDNumber.h +0 -12
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDNumber.m +0 -88
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDRange.h +0 -56
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDRange.m +0 -100
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPConnection.h +0 -109
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPConnection.m +0 -2281
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPLogging.h +0 -122
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPMessage.h +0 -53
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPMessage.m +0 -357
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPResponse.h +0 -149
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPServer.h +0 -126
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPServer.m +0 -372
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/LICENSE +0 -18
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPDataResponse.h +0 -13
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPDataResponse.m +0 -83
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPErrorResponse.h +0 -9
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPErrorResponse.m +0 -38
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/HTTPResponseProxy.h +0 -13
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/HTTPResponseProxy.m +0 -84
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/LICENSE +0 -19
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/Route.h +0 -18
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/Route.m +0 -11
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteRequest.h +0 -16
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteRequest.m +0 -50
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteResponse.h +0 -20
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteResponse.m +0 -66
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingConnection.h +0 -5
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingConnection.m +0 -142
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingHTTPServer.h +0 -55
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingHTTPServer.m +0 -303
- /package/WebDriverAgentLib/Routing/{WatchOS/RouteRequest.m → RouteRequest.m} +0 -0
- /package/WebDriverAgentLib/Routing/{WatchOS/RouteResponse.m → RouteResponse.m} +0 -0
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
#import <mach/mach_time.h>
|
|
12
12
|
@import UniformTypeIdentifiers;
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
// Textual import, not `@import Network;` - see the comment in FBTCPSocket.h.
|
|
15
|
+
#import <Network/Network.h>
|
|
15
16
|
#import "FBConfiguration.h"
|
|
16
17
|
#import "FBLogger.h"
|
|
17
18
|
#import "FBScreenshot.h"
|
|
@@ -36,7 +37,7 @@ static NSUInteger FBNormalizedMjpegFramerate(NSUInteger framerate)
|
|
|
36
37
|
@interface FBMjpegServer()
|
|
37
38
|
|
|
38
39
|
@property (nonatomic, readonly) dispatch_queue_t backgroundQueue;
|
|
39
|
-
@property (nonatomic, readonly) NSMutableArray<
|
|
40
|
+
@property (nonatomic, readonly) NSMutableArray<nw_connection_t> *listeningClients;
|
|
40
41
|
@property (nonatomic, readonly) FBImageProcessor *imageProcessor;
|
|
41
42
|
@property (nonatomic, readonly) long long mainScreenID;
|
|
42
43
|
@property (nonatomic, assign) NSUInteger consecutiveScreenshotFailures;
|
|
@@ -148,9 +149,8 @@ static NSUInteger FBNormalizedMjpegFramerate(NSUInteger framerate)
|
|
|
148
149
|
return;
|
|
149
150
|
}
|
|
150
151
|
NSUInteger clientCount = self.listeningClients.count;
|
|
151
|
-
for (
|
|
152
|
-
|
|
153
|
-
[client writeData:chunk withTimeout:FRAME_TIMEOUT tag:0];
|
|
152
|
+
for (nw_connection_t client in self.listeningClients) {
|
|
153
|
+
[self.socket writeData:chunk toClient:client];
|
|
154
154
|
}
|
|
155
155
|
self.sentFramesCount++;
|
|
156
156
|
self.sentBytesCount += chunk.length * clientCount;
|
|
@@ -164,14 +164,13 @@ static NSUInteger FBNormalizedMjpegFramerate(NSUInteger framerate)
|
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
- (void)didClientConnect:(
|
|
167
|
+
- (void)didClientConnect:(nw_connection_t)newClient
|
|
168
168
|
{
|
|
169
|
-
[FBLogger
|
|
170
|
-
//
|
|
171
|
-
[newClient readDataWithTimeout:-1 tag:0];
|
|
169
|
+
[FBLogger log:@"Got screenshots broadcast client connection"];
|
|
170
|
+
// FBTCPSocket already schedules the receive that -client:didReceiveData: relies on below.
|
|
172
171
|
}
|
|
173
172
|
|
|
174
|
-
- (void)
|
|
173
|
+
- (void)client:(nw_connection_t)client didReceiveData:(NSData *)data
|
|
175
174
|
{
|
|
176
175
|
@synchronized (self.listeningClients) {
|
|
177
176
|
if ([self.listeningClients containsObject:client]) {
|
|
@@ -179,15 +178,15 @@ static NSUInteger FBNormalizedMjpegFramerate(NSUInteger framerate)
|
|
|
179
178
|
}
|
|
180
179
|
}
|
|
181
180
|
|
|
182
|
-
[FBLogger
|
|
181
|
+
[FBLogger log:@"Starting screenshots broadcast for the client"];
|
|
183
182
|
NSString *streamHeader = [NSString stringWithFormat:@"HTTP/1.0 200 OK\r\nServer: %@\r\nConnection: close\r\nMax-Age: 0\r\nExpires: 0\r\nCache-Control: no-cache, private\r\nPragma: no-cache\r\nContent-Type: multipart/x-mixed-replace; boundary=--BoundaryString\r\n\r\n", SERVER_NAME];
|
|
184
|
-
[
|
|
183
|
+
[self.socket writeData:(id)[streamHeader dataUsingEncoding:NSUTF8StringEncoding] toClient:client];
|
|
185
184
|
@synchronized (self.listeningClients) {
|
|
186
185
|
[self.listeningClients addObject:client];
|
|
187
186
|
}
|
|
188
187
|
}
|
|
189
188
|
|
|
190
|
-
- (void)didClientDisconnect:(
|
|
189
|
+
- (void)didClientDisconnect:(nw_connection_t)client
|
|
191
190
|
{
|
|
192
191
|
@synchronized (self.listeningClients) {
|
|
193
192
|
[self.listeningClients removeObject:client];
|
|
@@ -199,10 +198,10 @@ static NSUInteger FBNormalizedMjpegFramerate(NSUInteger framerate)
|
|
|
199
198
|
{
|
|
200
199
|
self.isStreaming = NO;
|
|
201
200
|
@synchronized (self.listeningClients) {
|
|
202
|
-
NSArray<
|
|
201
|
+
NSArray<nw_connection_t> *clients = self.listeningClients.copy;
|
|
203
202
|
[self.listeningClients removeAllObjects];
|
|
204
|
-
for (
|
|
205
|
-
|
|
203
|
+
for (nw_connection_t client in clients) {
|
|
204
|
+
nw_connection_cancel(client);
|
|
206
205
|
}
|
|
207
206
|
}
|
|
208
207
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2015-present, Facebook, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the BSD-style license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import Network
|
|
10
|
+
import XCTest
|
|
11
|
+
|
|
12
|
+
/// Exercises FBMjpegServer+FBTCPSocket the same way FBWebServer wires them together in
|
|
13
|
+
/// -initScreenshotsBroadcaster, but standalone (no full FBWebServer/HTTP command server needed).
|
|
14
|
+
/// A client NWConnection reads the raw wire bytes back to confirm the multipart/x-mixed-replace
|
|
15
|
+
/// stream and its JPEG frames actually arrive, since watchOS has no BSD sockets/GCDAsyncSocket -
|
|
16
|
+
/// the production implementation is Network.framework-backed and worth covering for real.
|
|
17
|
+
final class WDAMjpegStreamingIntegrationTests: WDAWatchInProcessTestCase {
|
|
18
|
+
override class var relaunchForEachTest: Bool { false }
|
|
19
|
+
|
|
20
|
+
private static let jpegMagicBytes: [UInt8] = [0xFF, 0xD8, 0xFF]
|
|
21
|
+
|
|
22
|
+
func testMjpegStreamingProducesJpegFrames() throws {
|
|
23
|
+
// Port 0 asks the system to assign an ephemeral port; -[FBTCPSocket port] then reflects the
|
|
24
|
+
// actual bound port once -start returns, per nw_listener_get_port's documented behavior.
|
|
25
|
+
let socket = FBTCPSocket(port: 0)
|
|
26
|
+
let server = FBMjpegServer()
|
|
27
|
+
server.socket = socket
|
|
28
|
+
socket.delegate = server
|
|
29
|
+
defer {
|
|
30
|
+
server.stopStreaming()
|
|
31
|
+
socket.stop()
|
|
32
|
+
}
|
|
33
|
+
try socket.start()
|
|
34
|
+
let boundPort = socket.port
|
|
35
|
+
XCTAssertNotEqual(boundPort, 0, "FBTCPSocket did not report its bound ephemeral port")
|
|
36
|
+
|
|
37
|
+
let connection = NWConnection(host: "127.0.0.1", port: NWEndpoint.Port(rawValue: boundPort)!, using: .tcp)
|
|
38
|
+
defer { connection.cancel() }
|
|
39
|
+
|
|
40
|
+
let connected = expectation(description: "client connected to the mjpeg broadcaster")
|
|
41
|
+
connection.stateUpdateHandler = { state in
|
|
42
|
+
if case .ready = state {
|
|
43
|
+
connected.fulfill()
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
connection.start(queue: .main)
|
|
47
|
+
wait(for: [connected], timeout: 15)
|
|
48
|
+
|
|
49
|
+
// FBMjpegServer only starts broadcasting once it has seen any data from the client - mimic the
|
|
50
|
+
// request line a real HTTP client would send.
|
|
51
|
+
let sent = expectation(description: "sent the request line")
|
|
52
|
+
connection.send(content: Data("GET / HTTP/1.0\r\n\r\n".utf8), completion: .contentProcessed { _ in
|
|
53
|
+
sent.fulfill()
|
|
54
|
+
})
|
|
55
|
+
wait(for: [sent], timeout: 15)
|
|
56
|
+
|
|
57
|
+
var received = Data()
|
|
58
|
+
let jpegMagicData = Data(Self.jpegMagicBytes)
|
|
59
|
+
let sawJpegFrame = expectation(description: "received at least one jpeg frame")
|
|
60
|
+
func receiveMore() {
|
|
61
|
+
connection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { data, _, _, error in
|
|
62
|
+
if let data = data {
|
|
63
|
+
received.append(data)
|
|
64
|
+
if received.range(of: jpegMagicData) != nil {
|
|
65
|
+
sawJpegFrame.fulfill()
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if error == nil {
|
|
70
|
+
receiveMore()
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
receiveMore()
|
|
75
|
+
wait(for: [sawJpegFrame], timeout: 15)
|
|
76
|
+
|
|
77
|
+
XCTAssertNotNil(received.range(of: Data("multipart/x-mixed-replace".utf8)), "Response is not a multipart stream")
|
|
78
|
+
XCTAssertNotNil(received.range(of: Data("Content-type: image/jpeg".utf8)), "No JPEG part header found")
|
|
79
|
+
XCTAssertNotNil(received.range(of: jpegMagicData), "No JPEG frame data found")
|
|
80
|
+
}
|
|
81
|
+
}
|