android-emulator-webrtc 1.0.18 → 2.0.1
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/README.md +93 -204
- package/dist/components/emulator/emulator.d.ts +64 -0
- package/dist/components/emulator/emulator.js +161 -173
- package/dist/components/emulator/net/emulator_status.d.ts +45 -0
- package/dist/components/emulator/net/emulator_status.js +35 -42
- package/dist/components/emulator/net/logcat.js +37 -54
- package/dist/components/emulator/net/logger.d.ts +7 -0
- package/dist/components/emulator/net/logger.js +20 -0
- package/dist/components/emulator/net/ws_jsep_protocol_driver.d.ts +213 -0
- package/dist/components/emulator/net/ws_jsep_protocol_driver.js +640 -0
- package/dist/components/emulator/views/event_handler.d.ts +37 -0
- package/dist/components/emulator/views/event_handler.js +274 -260
- package/dist/components/emulator/views/webrtc_view.d.ts +27 -0
- package/dist/components/emulator/views/webrtc_view.js +42 -20
- package/dist/index.d.ts +8 -0
- package/dist/index.js +0 -7
- package/dist/proto/emulator_controller_pb.d.ts +1 -0
- package/dist/proto/emulator_controller_pb.js +146 -287
- package/dist/src/components/emulator/emulator.d.ts +64 -0
- package/dist/src/components/emulator/net/emulator_status.d.ts +45 -0
- package/dist/src/components/emulator/net/logger.d.ts +7 -0
- package/dist/src/components/emulator/net/ws_jsep_protocol_driver.d.ts +213 -0
- package/dist/src/components/emulator/views/event_handler.d.ts +37 -0
- package/dist/src/components/emulator/views/webrtc_view.d.ts +27 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/proto/emulator_controller_pb.d.ts +1 -0
- package/package.json +17 -17
- package/proto/emulator_controller.proto +746 -181
- package/.vscode/launch.json +0 -21
- package/.vscode/settings.json +0 -3
- package/CONTRIBUTING.md +0 -28
- package/Makefile +0 -123
- package/android-emulator-webrtc.code-workspace +0 -7
- package/api_descriptor.pb +0 -0
- package/babel.config.js +0 -16
- package/cloudbuild.yaml +0 -41
- package/cloudbuilders/.gcloudignore +0 -1
- package/cloudbuilders/Dockerfile +0 -20
- package/cloudbuilders/README.md +0 -29
- package/cloudbuilders/cloudbuild.yaml +0 -19
- package/dist/components/emulator/net/jsep_protocol_driver.js +0 -365
- package/dist/components/emulator/views/simple_png_view.js +0 -110
- package/dist/proto/emulator_controller_grpc_web_pb.js +0 -1601
- package/dist/proto/emulator_web_client.js +0 -176
- package/dist/proto/rtc_service_grpc_web_pb.js +0 -231
- package/dist/proto/rtc_service_pb.js +0 -338
- package/emulator/index.js +0 -1
- package/eslint_prefix.py +0 -37
- package/gen_md_doc.js +0 -40
- package/npmrc.enc +0 -0
- package/proto/rtc_service.proto +0 -117
- package/protoc-plugin/Makefile +0 -31
- package/protoc-plugin/grpc_generator.cc +0 -1755
- package/src/components/emulator/emulator.js +0 -217
- package/src/components/emulator/net/emulator_status.js +0 -94
- package/src/components/emulator/net/jsep_protocol_driver.js +0 -364
- package/src/components/emulator/net/logcat.js +0 -155
- package/src/components/emulator/views/event_handler.js +0 -268
- package/src/components/emulator/views/simple_png_view.js +0 -105
- package/src/components/emulator/views/webrtc_view.js +0 -142
- package/src/index.js +0 -20
- package/src/proto/emulator_web_client.js +0 -140
- package/test/cloudbuild.yaml +0 -41
- package/test/emulator.test.js +0 -125
- package/test/event_handler.test.js +0 -91
- package/test/fake_events.js +0 -50
- package/test/jsep_protocol_driver.test.js +0 -228
- package/test/simple_png_view.test.js +0 -145
- package/test/touch_event_handler.test.js +0 -118
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2019 The Android Open Source Project
|
|
3
|
-
*
|
|
4
|
-
* Licensed under the Apache License, Version 2.0 (the "License")
|
|
5
|
-
* you may not use this file except in compliance with the License.
|
|
6
|
-
* You may obtain a copy of the License at
|
|
7
|
-
*
|
|
8
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
*
|
|
10
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
* See the License for the specific language governing permissions and
|
|
14
|
-
* limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
import { EmulatorControllerClient } from "../proto/emulator_controller_grpc_web_pb";
|
|
17
|
-
import { RtcClient } from "../proto/rtc_service_grpc_web_pb";
|
|
18
|
-
import { GrpcWebClientBase } from "grpc-web";
|
|
19
|
-
import { EventEmitter } from "events";
|
|
20
|
-
|
|
21
|
-
export class NopAuthenticator {
|
|
22
|
-
authHeader = () => {
|
|
23
|
-
return {};
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
unauthorized = () => { };
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* A GrcpWebClientBase that inject authentication headers and intercepts
|
|
31
|
-
* errors. If the errors are 401, the unauthorized method of the authenticator will be invoked.
|
|
32
|
-
*
|
|
33
|
-
* @export
|
|
34
|
-
* @class EmulatorWebClient
|
|
35
|
-
* @extends {GrpcWebClientBase}
|
|
36
|
-
*/
|
|
37
|
-
class EmulatorWebClient extends GrpcWebClientBase {
|
|
38
|
-
constructor(options, auth) {
|
|
39
|
-
super(options);
|
|
40
|
-
this.auth = auth;
|
|
41
|
-
this.events = new EventEmitter();
|
|
42
|
-
this.events.on("error", e => {console.log("low level gRPC error: " + JSON.stringify(e));})
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
on = (name, fn) => {
|
|
46
|
-
this.events.on(name, fn);
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
rpcCall = (method, request, metadata, methodinfo, callback) => {
|
|
50
|
-
const authHeader = this.auth.authHeader();
|
|
51
|
-
const meta = { ...metadata, ...authHeader };
|
|
52
|
-
const self = this;
|
|
53
|
-
return super.rpcCall(method, request, meta, methodinfo, (err, res) => {
|
|
54
|
-
if (err) {
|
|
55
|
-
if (err.code === 401) self.auth.unauthorized();
|
|
56
|
-
if (self.events)
|
|
57
|
-
self.events.emit("error", err);
|
|
58
|
-
}
|
|
59
|
-
if (callback) callback(err, res);
|
|
60
|
-
});
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
serverStreaming = (method, request, metadata, methodInfo) => {
|
|
64
|
-
const authHeader = this.auth.authHeader();
|
|
65
|
-
const meta = { ...metadata, ...authHeader };
|
|
66
|
-
const stream = super.serverStreaming(method, request, meta, methodInfo);
|
|
67
|
-
const self = this;
|
|
68
|
-
|
|
69
|
-
// Intercept errors.
|
|
70
|
-
stream.on("error", e => {
|
|
71
|
-
if (e.code === 401) {
|
|
72
|
-
self.auth.unauthorized();
|
|
73
|
-
}
|
|
74
|
-
self.events.emit("error", e);
|
|
75
|
-
});
|
|
76
|
-
return stream;
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* An EmulatorControllerService is an EmulatorControllerClient that inject authentication headers.
|
|
82
|
-
* You can provide your own authenticator service that must implement the following mehtods:
|
|
83
|
-
*
|
|
84
|
-
* - `authHeader()` which must return a set of headers that should be send along with a request.
|
|
85
|
-
* - `unauthorized()` a function that gets called when a 401 was received.
|
|
86
|
-
*
|
|
87
|
-
* You can use this to simplify handling authentication failures.
|
|
88
|
-
*
|
|
89
|
-
* TODO(jansene): Maybe expose error handling? That way it does
|
|
90
|
-
* not have to be repeated at every function call.
|
|
91
|
-
*
|
|
92
|
-
* @export
|
|
93
|
-
* @class EmulatorControllerService
|
|
94
|
-
* @extends {EmulatorControllerClient}
|
|
95
|
-
*/
|
|
96
|
-
export class EmulatorControllerService extends EmulatorControllerClient {
|
|
97
|
-
/**
|
|
98
|
-
*Creates an instance of EmulatorControllerService.
|
|
99
|
-
* @param {string} uri of the emulator controller endpoint.
|
|
100
|
-
* @param {Authenticator} authenticator used to authenticate with the emulator endpoint.
|
|
101
|
-
* @param onError callback that will be invoked when a low level gRPC error arises.
|
|
102
|
-
* @memberof EmulatorControllerService
|
|
103
|
-
*/
|
|
104
|
-
constructor(uri, authenticator, onError) {
|
|
105
|
-
super(uri);
|
|
106
|
-
if (!authenticator) authenticator = new NopAuthenticator();
|
|
107
|
-
this.client_ = new EmulatorWebClient({}, authenticator);
|
|
108
|
-
if (onError) this.client_.on('error', e => { onError(e); });
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* An RtcService is an RtcClient that inject authentication headers.
|
|
115
|
-
* You can provide your own authenticator service that must implement the following mehtods:
|
|
116
|
-
*
|
|
117
|
-
* - `authHeader()` which must return a set of headers that should be send along with a request.
|
|
118
|
-
* - `unauthorized()` a function that gets called when a 401 was received.
|
|
119
|
-
*
|
|
120
|
-
* You can use this to simplify handling authentication failures.
|
|
121
|
-
*
|
|
122
|
-
* @export
|
|
123
|
-
* @class EmulatorControllerService
|
|
124
|
-
* @extends {RtcClient}
|
|
125
|
-
*/
|
|
126
|
-
export class RtcService extends RtcClient {
|
|
127
|
-
/**
|
|
128
|
-
*Creates an instance of RtcService.
|
|
129
|
-
* @param {string} uri of the emulator controller endpoint.
|
|
130
|
-
* @param {Authenticator} authenticator used to authenticate with the emulator endpoint.
|
|
131
|
-
* @param onError callback that will be invoked when a low level gRPC error arises.
|
|
132
|
-
* @memberof RtcService
|
|
133
|
-
*/
|
|
134
|
-
constructor(uri, authenticator, onError) {
|
|
135
|
-
super(uri);
|
|
136
|
-
if (!authenticator) authenticator = new NopAuthenticator();
|
|
137
|
-
this.client_ = new EmulatorWebClient({}, authenticator);
|
|
138
|
-
if (onError) this.client_.on('error', e => { onError(e); });
|
|
139
|
-
}
|
|
140
|
-
}
|
package/test/cloudbuild.yaml
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
steps:
|
|
2
|
-
- name: "gcr.io/cloud-builders/gcloud"
|
|
3
|
-
args:
|
|
4
|
-
- kms
|
|
5
|
-
- decrypt
|
|
6
|
-
- --ciphertext-file=npmrc.enc
|
|
7
|
-
- --plaintext-file=/root/.npmrc
|
|
8
|
-
- --location=global
|
|
9
|
-
- --keyring=my-keyring
|
|
10
|
-
- --key=npm-key
|
|
11
|
-
volumes:
|
|
12
|
-
- name: "home"
|
|
13
|
-
path: /root/
|
|
14
|
-
- name: gcr.io/emu-dev-cts/protoc
|
|
15
|
-
args:
|
|
16
|
-
[
|
|
17
|
-
"--include_imports",
|
|
18
|
-
"--include_source_info",
|
|
19
|
-
"--proto_path",
|
|
20
|
-
"./proto",
|
|
21
|
-
"--descriptor_set_out",
|
|
22
|
-
"api_descriptor.pb",
|
|
23
|
-
"--plugin=protoc-gen-grpc-web=/protoc/bin/protoc-gen-grpc-web",
|
|
24
|
-
"--js_out=import_style=commonjs:src/proto",
|
|
25
|
-
"--grpc-web_out=import_style=commonjs,mode=grpcwebtext:src/proto",
|
|
26
|
-
"./proto/emulator_controller.proto",
|
|
27
|
-
"./proto/rtc_service.proto",
|
|
28
|
-
]
|
|
29
|
-
- name: "gcr.io/cloud-builders/npm"
|
|
30
|
-
args: ["install"]
|
|
31
|
-
- name: "gcr.io/cloud-builders/npm"
|
|
32
|
-
args: ["run", "build"]
|
|
33
|
-
- name: "gcr.io/cloud-builders/npm"
|
|
34
|
-
args: ["test"]
|
|
35
|
-
- name: "gcr.io/cloud-builders/npm"
|
|
36
|
-
args: ["publish", "/workspace", "--dry-run"]
|
|
37
|
-
env:
|
|
38
|
-
- HOME=/root/
|
|
39
|
-
volumes:
|
|
40
|
-
- name: "home"
|
|
41
|
-
path: /root/
|
package/test/emulator.test.js
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* @jest-environment jsdom
|
|
4
|
-
*/
|
|
5
|
-
/*
|
|
6
|
-
* Copyright 2020 The Android Open Source Project
|
|
7
|
-
*
|
|
8
|
-
* Licensed under the Apache License, Version 2.0 (the "License")
|
|
9
|
-
* you may not use this file except in compliance with the License.
|
|
10
|
-
* You may obtain a copy of the License at
|
|
11
|
-
*
|
|
12
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
13
|
-
*
|
|
14
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
15
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
16
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
17
|
-
* See the License for the specific language governing permissions and
|
|
18
|
-
* limitations under the License.
|
|
19
|
-
*/
|
|
20
|
-
import "@testing-library/jest-dom";
|
|
21
|
-
import "babel-polyfill";
|
|
22
|
-
import { EventEmitter } from "events";
|
|
23
|
-
import React from "react";
|
|
24
|
-
import { render, fireEvent, screen, waitFor } from "@testing-library/react";
|
|
25
|
-
import Emulator from "../src/components/emulator/emulator";
|
|
26
|
-
import * as Proto from "../src/proto/emulator_controller_pb";
|
|
27
|
-
import * as Rtc from "../src/proto/rtc_service_pb";
|
|
28
|
-
import {
|
|
29
|
-
RtcService,
|
|
30
|
-
EmulatorControllerService,
|
|
31
|
-
} from "../src/proto/emulator_web_client";
|
|
32
|
-
|
|
33
|
-
jest.mock("../src/proto/emulator_web_client");
|
|
34
|
-
|
|
35
|
-
// See https://github.com/testing-library/react-testing-library/issues/470
|
|
36
|
-
// As well as https://github.com/facebook/react/issues/10389
|
|
37
|
-
// All because of the "muted" tag on our video element inside webrtc_view
|
|
38
|
-
const renderIgnoringUnstableFlushDiscreteUpdates = (component) => {
|
|
39
|
-
// tslint:disable: no-console
|
|
40
|
-
const originalError = console.error;
|
|
41
|
-
const error = jest.fn();
|
|
42
|
-
console.error = error;
|
|
43
|
-
const result = render(component);
|
|
44
|
-
expect(error).toHaveBeenCalledTimes(1);
|
|
45
|
-
expect(error).toHaveBeenCalledWith(
|
|
46
|
-
"Warning: unstable_flushDiscreteUpdates: Cannot flush updates when React is already rendering.%s",
|
|
47
|
-
expect.any(String)
|
|
48
|
-
);
|
|
49
|
-
console.error = originalError;
|
|
50
|
-
// tslint:enable: no-console
|
|
51
|
-
return result;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
describe("The emulator", () => {
|
|
55
|
-
beforeEach(() => {
|
|
56
|
-
// Clear all instances and calls to constructor and all methods:
|
|
57
|
-
RtcService.mockClear();
|
|
58
|
-
EmulatorControllerService.mockClear();
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test("Creates gRPC services", async () => {
|
|
62
|
-
render(
|
|
63
|
-
<Emulator uri="/test" width={300} height={300} />
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
expect(EmulatorControllerService).toHaveBeenCalled();
|
|
67
|
-
expect(RtcService).toHaveBeenCalled();
|
|
68
|
-
// Shipped out a gps call
|
|
69
|
-
});
|
|
70
|
-
test("Tries to establish a webrtc connection", async () => {
|
|
71
|
-
let state;
|
|
72
|
-
render(
|
|
73
|
-
<Emulator
|
|
74
|
-
uri="/test"
|
|
75
|
-
width={300}
|
|
76
|
-
height={300}
|
|
77
|
-
onStateChange={(e) => {
|
|
78
|
-
state = e;
|
|
79
|
-
}}
|
|
80
|
-
/>
|
|
81
|
-
);
|
|
82
|
-
|
|
83
|
-
await waitFor(() => state === "connecting");
|
|
84
|
-
expect(RtcService).toHaveBeenCalled();
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
test("Sends a gps location to the emulator", async () => {
|
|
88
|
-
// Let's go to Seattle!
|
|
89
|
-
render(
|
|
90
|
-
<Emulator
|
|
91
|
-
uri="/test"
|
|
92
|
-
width={300}
|
|
93
|
-
height={300}
|
|
94
|
-
gps={{ latitude: 47.6062, longitude: 122.3321 }}
|
|
95
|
-
/>
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
const setGps = EmulatorControllerService.mock.instances[0].setGps;
|
|
99
|
-
expect(setGps).toHaveBeenCalled();
|
|
100
|
-
|
|
101
|
-
const location = new Proto.GpsState();
|
|
102
|
-
location.setLatitude(47.6062);
|
|
103
|
-
location.setLongitude(122.3321);
|
|
104
|
-
location.setAltitude(undefined);
|
|
105
|
-
location.setBearing(undefined);
|
|
106
|
-
location.setSpeed(undefined);
|
|
107
|
-
expect(setGps).toHaveBeenCalledWith(location);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test("The png view requests images", async () => {
|
|
111
|
-
let pngCall = false
|
|
112
|
-
EmulatorControllerService.mockImplementation(() => {
|
|
113
|
-
return {
|
|
114
|
-
streamScreenshot: jest.fn((request) => {
|
|
115
|
-
pngCall = true
|
|
116
|
-
return { on: jest.fn(), cancel: jest.fn() };
|
|
117
|
-
}),
|
|
118
|
-
getStatus: jest.fn(() => {}),
|
|
119
|
-
};
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
render(<Emulator uri="/test" width={300} height={300} view="png" />);
|
|
123
|
-
expect(pngCall).toBeTruthy()
|
|
124
|
-
});
|
|
125
|
-
});
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @jest-environment jsdom
|
|
3
|
-
*/
|
|
4
|
-
/*
|
|
5
|
-
* Copyright 2020 The Android Open Source Project
|
|
6
|
-
*
|
|
7
|
-
* Licensed under the Apache License, Version 2.0 (the "License")
|
|
8
|
-
* you may not use this file except in compliance with the License.
|
|
9
|
-
* You may obtain a copy of the License at
|
|
10
|
-
*
|
|
11
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
-
*
|
|
13
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
-
* See the License for the specific language governing permissions and
|
|
17
|
-
* limitations under the License.
|
|
18
|
-
*/
|
|
19
|
-
import "@testing-library/jest-dom";
|
|
20
|
-
|
|
21
|
-
import React from "react";
|
|
22
|
-
import { render, fireEvent, screen } from "@testing-library/react";
|
|
23
|
-
import { fakeMouseEvent, fakeTouchEvent} from "./fake_events";
|
|
24
|
-
import withMouseKeyHandler from "../src/components/emulator/views/event_handler";
|
|
25
|
-
|
|
26
|
-
import JsepProtocol from "../src/components/emulator/net/jsep_protocol_driver";
|
|
27
|
-
import {
|
|
28
|
-
RtcService,
|
|
29
|
-
EmulatorControllerService,
|
|
30
|
-
} from "../src/proto/emulator_web_client";
|
|
31
|
-
|
|
32
|
-
jest.mock("../src/proto/emulator_web_client");
|
|
33
|
-
jest.mock("../src/proto/rtc_service_pb");
|
|
34
|
-
jest.mock("../src/proto/emulator_controller_pb");
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class FakeEmulator extends React.Component {
|
|
38
|
-
render() {
|
|
39
|
-
return (
|
|
40
|
-
<div
|
|
41
|
-
data-testid="fake"
|
|
42
|
-
style={{ height: "200px", width: "200px", backgroundColor: "#555" }}
|
|
43
|
-
></div>
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const TestView = withMouseKeyHandler(FakeEmulator);
|
|
49
|
-
describe("The event handler using a real jsep serializer", () => {
|
|
50
|
-
|
|
51
|
-
const rtcServiceInstance = new RtcService("http://foo");
|
|
52
|
-
const emulatorServiceInstance = new EmulatorControllerService("http://foo");
|
|
53
|
-
let jsep, fakeScreen;
|
|
54
|
-
|
|
55
|
-
beforeEach(() => {
|
|
56
|
-
jest.clearAllMocks();
|
|
57
|
-
jsep = new JsepProtocol(emulatorServiceInstance, rtcServiceInstance, true);
|
|
58
|
-
|
|
59
|
-
render(<TestView emulator={emulatorServiceInstance} jsep={jsep} />);
|
|
60
|
-
fakeScreen = screen.getByTestId("fake").parentElement;
|
|
61
|
-
Object.defineProperty(fakeScreen, "clientWidth", { get: () => 200 });
|
|
62
|
-
Object.defineProperty(fakeScreen, "clientHeight", { get: () => 200 });
|
|
63
|
-
|
|
64
|
-
expect(fakeScreen).toBeInTheDocument();
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
test("Forwards mouse events", () => {
|
|
68
|
-
fireEvent(fakeScreen, fakeMouseEvent("mousedown", 10, 10));
|
|
69
|
-
fireEvent(fakeScreen, fakeMouseEvent("mouseup", 20, 20));
|
|
70
|
-
|
|
71
|
-
// Shipped out a mouse event
|
|
72
|
-
expect(emulatorServiceInstance.sendMouse).toHaveBeenCalledTimes(2);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
test("Forwards keyboard events", () => {
|
|
76
|
-
fireEvent.keyDown(fakeScreen, { key: "Enter", code: "Enter" });
|
|
77
|
-
fireEvent.keyUp(fakeScreen, { key: "Enter", code: "Enter" });
|
|
78
|
-
|
|
79
|
-
// Shipped out a keyboard event
|
|
80
|
-
expect(emulatorServiceInstance.sendKey).toHaveBeenCalledTimes(2);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
test("Forwards touch events", () => {
|
|
84
|
-
fireEvent(fakeScreen, fakeTouchEvent("touchstart", 10, 10, 1));
|
|
85
|
-
fireEvent(fakeScreen, fakeTouchEvent("touchmove", 20, 20, 2));
|
|
86
|
-
fireEvent(fakeScreen, fakeTouchEvent("touchend", 30, 30, 0));
|
|
87
|
-
|
|
88
|
-
// Shipped out a touch event
|
|
89
|
-
expect(emulatorServiceInstance.sendTouch).toHaveBeenCalledTimes(3);
|
|
90
|
-
});
|
|
91
|
-
});
|
package/test/fake_events.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2021 The Android Open Source Project
|
|
3
|
-
*
|
|
4
|
-
* Licensed under the Apache License, Version 2.0 (the "License")
|
|
5
|
-
* you may not use this file except in compliance with the License.
|
|
6
|
-
* You may obtain a copy of the License at
|
|
7
|
-
*
|
|
8
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
*
|
|
10
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
* See the License for the specific language governing permissions and
|
|
14
|
-
* limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
export function fakeMouseEvent(tp, x, y, props = {}) {
|
|
17
|
-
const event = new MouseEvent(tp, {
|
|
18
|
-
bubbles: true,
|
|
19
|
-
cancelable: true,
|
|
20
|
-
...props,
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
Object.defineProperty(event, "offsetX", { get: () => x });
|
|
24
|
-
Object.defineProperty(event, "offsetY", { get: () => y });
|
|
25
|
-
return event;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function fakeTouchEvent(tp, x, y, force, props = {}) {
|
|
29
|
-
const event = new TouchEvent(tp, {
|
|
30
|
-
bubbles: true,
|
|
31
|
-
cancelable: true,
|
|
32
|
-
...props,
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
Object.defineProperty(event, "changedTouches", {
|
|
36
|
-
get: () => [
|
|
37
|
-
{ clientX: x, clientY: y, radiusX: 4, radiusY: 4, force: force },
|
|
38
|
-
],
|
|
39
|
-
});
|
|
40
|
-
return event;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function resize(width, height) {
|
|
44
|
-
const resizeEvent = document.createEvent("Event");
|
|
45
|
-
resizeEvent.initEvent("resize", true, true);
|
|
46
|
-
|
|
47
|
-
global.window.innerWidth = width || global.window.innerWidth;
|
|
48
|
-
global.window.innerHeight = height || global.window.innerHeight;
|
|
49
|
-
global.window.dispatchEvent(resizeEvent);
|
|
50
|
-
}
|
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @jest-environment jsdom
|
|
3
|
-
*/
|
|
4
|
-
/*
|
|
5
|
-
* Copyright 2020 The Android Open Source Project
|
|
6
|
-
*
|
|
7
|
-
* Licensed under the Apache License, Version 2.0 (the "License")
|
|
8
|
-
* you may not use this file except in compliance with the License.
|
|
9
|
-
* You may obtain a copy of the License at
|
|
10
|
-
*
|
|
11
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
-
*
|
|
13
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
14
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
-
* See the License for the specific language governing permissions and
|
|
17
|
-
* limitations under the License.
|
|
18
|
-
*/
|
|
19
|
-
import { jest } from "@jest/globals";
|
|
20
|
-
import "regenerator-runtime/runtime"; // Somehow needed for jest to be happy with ES6
|
|
21
|
-
|
|
22
|
-
import * as Proto from "../src/proto/emulator_controller_pb";
|
|
23
|
-
import * as Rtc from "../src/proto/rtc_service_pb";
|
|
24
|
-
import JsepProtocol from "../src/components/emulator/net/jsep_protocol_driver.js";
|
|
25
|
-
import {
|
|
26
|
-
RtcService,
|
|
27
|
-
EmulatorControllerService,
|
|
28
|
-
} from "../src/proto/emulator_web_client";
|
|
29
|
-
|
|
30
|
-
jest.mock("../src/proto/emulator_web_client");
|
|
31
|
-
|
|
32
|
-
const jsepMessage = (object, uid) => {
|
|
33
|
-
const guid = new Rtc.RtcId();
|
|
34
|
-
guid.setGuid(uid);
|
|
35
|
-
|
|
36
|
-
const jsepMsg = new Rtc.JsepMsg();
|
|
37
|
-
jsepMsg.setId(guid);
|
|
38
|
-
jsepMsg.setMessage(JSON.stringify(object));
|
|
39
|
-
return jsepMsg;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const requestRtcStream = jest.fn((request, metadata, callback) => {
|
|
43
|
-
const guid = new Rtc.RtcId();
|
|
44
|
-
guid.setGuid("abcde");
|
|
45
|
-
|
|
46
|
-
callback(null, guid);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
const receiveJsepMessage = (message) => {
|
|
50
|
-
const jsepMsg = jsepMessage(message);
|
|
51
|
-
return jest.fn((request, metadata, callback) => {
|
|
52
|
-
callback(null, jsepMsg);
|
|
53
|
-
});
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const RTCPeerConnectionMock = jest.fn().mockImplementation((cfg) => ({
|
|
57
|
-
ondatachannel: jest.fn(),
|
|
58
|
-
createAnswer: jest.fn(),
|
|
59
|
-
addEventListener: jest.fn(),
|
|
60
|
-
addIceCandidate: jest.fn(),
|
|
61
|
-
dispatchEvent: jest.fn(),
|
|
62
|
-
setRemoteDescription: jest.fn(),
|
|
63
|
-
setLocalDescription: jest.fn(),
|
|
64
|
-
close: jest.fn(),
|
|
65
|
-
}));
|
|
66
|
-
|
|
67
|
-
Object.defineProperty(window, "RTCPeerConnection", {
|
|
68
|
-
writable: true,
|
|
69
|
-
value: jest.fn().mockImplementation((cfg) => {
|
|
70
|
-
let sdp = null;
|
|
71
|
-
let signal = null;
|
|
72
|
-
let state = null;
|
|
73
|
-
return {
|
|
74
|
-
ondatachannel: jest.fn(),
|
|
75
|
-
createAnswer: jest.fn(() => {
|
|
76
|
-
return new Promise((resolve) => {
|
|
77
|
-
return { answer: "fake-answer" };
|
|
78
|
-
});
|
|
79
|
-
}),
|
|
80
|
-
addEventListener: jest.fn(),
|
|
81
|
-
addIceCandidate: jest.fn(),
|
|
82
|
-
dispatchEvent: jest.fn(),
|
|
83
|
-
setRemoteDescription: (desc) => {
|
|
84
|
-
sdp = desc;
|
|
85
|
-
state = "have-remote-offer";
|
|
86
|
-
if (signal) signal();
|
|
87
|
-
},
|
|
88
|
-
setLocalDescription: jest.fn(),
|
|
89
|
-
get currentRemoteDescription() {
|
|
90
|
-
return sdp;
|
|
91
|
-
},
|
|
92
|
-
set onsignalingstatechange(fn) {
|
|
93
|
-
signal = fn;
|
|
94
|
-
},
|
|
95
|
-
get signalingState() {
|
|
96
|
-
return state;
|
|
97
|
-
},
|
|
98
|
-
close: jest.fn(),
|
|
99
|
-
};
|
|
100
|
-
}),
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
Object.defineProperty(window, "RTCIceCandidate", {
|
|
104
|
-
writable: true,
|
|
105
|
-
value: jest.fn().mockImplementation((cfg) => ({})),
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
Object.defineProperty(window, "RTCSessionDescription", {
|
|
109
|
-
writable: true,
|
|
110
|
-
value: jest.fn().mockImplementation((desc) => {
|
|
111
|
-
return { sdp: desc };
|
|
112
|
-
}),
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
const sdp = {
|
|
116
|
-
sdp: "fakesdp1",
|
|
117
|
-
type: "offer",
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
const sdp2 = {
|
|
121
|
-
sdp: "fakesdp2",
|
|
122
|
-
type: "offer",
|
|
123
|
-
};
|
|
124
|
-
const candidates_and_sdp = [
|
|
125
|
-
{
|
|
126
|
-
candidate:
|
|
127
|
-
"candidate:4205781435 1 udp 2122260223 10.146.0.6 37608 typ host generation 0 ufrag Er9W network-id 1 network-cost 50",
|
|
128
|
-
sdpMLineIndex: 1,
|
|
129
|
-
sdpMid: "1",
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
candidate:
|
|
133
|
-
"candidate:3022839115 1 tcp 1518280447 10.146.0.6 36959 typ host tcptype passive generation 0 ufrag Er9W network-id 1 network-cost 50",
|
|
134
|
-
sdpMLineIndex: 0,
|
|
135
|
-
sdpMid: "0",
|
|
136
|
-
},
|
|
137
|
-
sdp,
|
|
138
|
-
];
|
|
139
|
-
|
|
140
|
-
const jsepProtocol = (messages) => {
|
|
141
|
-
RtcService.mockClear();
|
|
142
|
-
EmulatorControllerService.mockClear();
|
|
143
|
-
|
|
144
|
-
let receive = jest.fn();
|
|
145
|
-
for (var i = 0; i < messages.length; i++) {
|
|
146
|
-
receive.mockImplementationOnce(receiveJsepMessage(messages[i]));
|
|
147
|
-
}
|
|
148
|
-
RtcService.mockImplementation(() => {
|
|
149
|
-
return {
|
|
150
|
-
requestRtcStream: requestRtcStream,
|
|
151
|
-
receiveJsepMessage: receive,
|
|
152
|
-
sendJsepMessage: jest.fn((msg) => {
|
|
153
|
-
console.log("Sending " + msg);
|
|
154
|
-
}),
|
|
155
|
-
};
|
|
156
|
-
});
|
|
157
|
-
const rtcServiceInstance = new RtcService("http://foo");
|
|
158
|
-
const emulatorServiceInstance = new EmulatorControllerService("http://foo");
|
|
159
|
-
return {
|
|
160
|
-
rtc: rtcServiceInstance,
|
|
161
|
-
jsep: new JsepProtocol(emulatorServiceInstance, rtcServiceInstance, true),
|
|
162
|
-
};
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
describe("Basic jsep protocol with polling.", () => {
|
|
166
|
-
it("calls request rtc stream", () => {
|
|
167
|
-
const { rtc, jsep } = jsepProtocol([{ bye: "we're done" }]);
|
|
168
|
-
jsep.startStream();
|
|
169
|
-
expect(rtc.requestRtcStream.mock.calls.length).toBe(1);
|
|
170
|
-
expect(rtc.receiveJsepMessage.mock.calls.length).toBe(1);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
it("Notifies listeners of a disconnect", () => {
|
|
174
|
-
const { jsep } = jsepProtocol([{ bye: "we're done" }]);
|
|
175
|
-
|
|
176
|
-
const disconnect = jest.fn();
|
|
177
|
-
jsep.on("disconnected", disconnect);
|
|
178
|
-
jsep.startStream();
|
|
179
|
-
expect(disconnect).toHaveBeenCalledTimes(1);
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it("Does not process messages before start", () => {
|
|
183
|
-
const { jsep } = jsepProtocol(candidates_and_sdp);
|
|
184
|
-
|
|
185
|
-
jsep.startStream();
|
|
186
|
-
// All candidates are queued.
|
|
187
|
-
expect(jsep.old_emu_patch.candidates.length).toBe(2);
|
|
188
|
-
expect(jsep.old_emu_patch.sdp).not.toBeNull();
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
it("Flush message queue after bye", () => {
|
|
192
|
-
let msg = Array.from(candidates_and_sdp);
|
|
193
|
-
msg.push({ bye: "we're done" });
|
|
194
|
-
const { jsep } = jsepProtocol(msg);
|
|
195
|
-
|
|
196
|
-
jsep.startStream();
|
|
197
|
-
expect(jsep.old_emu_patch.candidates.length).toBe(0);
|
|
198
|
-
expect(jsep.old_emu_patch.sdp).toBe(null);
|
|
199
|
-
expect(jsep.peerConnection).toBe(null);
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
it("Out of order messages handled after start", () => {
|
|
203
|
-
let msg = Array.from(candidates_and_sdp);
|
|
204
|
-
msg.push({ start: { foo: "bar" } });
|
|
205
|
-
const { jsep } = jsepProtocol(msg);
|
|
206
|
-
|
|
207
|
-
jsep.startStream();
|
|
208
|
-
expect(jsep.old_emu_patch.candidates.length).toBe(0);
|
|
209
|
-
expect(jsep.peerConnection).not.toBeNull();
|
|
210
|
-
expect(jsep.peerConnection.currentRemoteDescription).not.toBeNull();
|
|
211
|
-
// Peer connection was initialized with rtc config
|
|
212
|
-
expect(RTCPeerConnection.mock.calls[0][0]).toStrictEqual({ foo: "bar" });
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
it.skip("Never handles sdp twice / (async problem)", async () => {
|
|
216
|
-
// 2nd jsep gets dropped.
|
|
217
|
-
let { rtc, jsep } = jsepProtocol([sdp, sdp2, { start: { foo: "bar" } }]);
|
|
218
|
-
jsep.startStream();
|
|
219
|
-
expect(jsep.old_emu_patch.candidates.length).toBe(0);
|
|
220
|
-
expect(jsep.old_emu_patch.sdp).toBeNull();
|
|
221
|
-
expect(jsep.old_emu_patch.answer).toBe(true);
|
|
222
|
-
expect(jsep.peerConnection).not.toBeNull();
|
|
223
|
-
expect(jsep.peerConnection.currentRemoteDescription.sdp.sdp).toBe(sdp.sdp);
|
|
224
|
-
// Peer connection was initialized with rtc config
|
|
225
|
-
expect(RTCPeerConnection.mock.calls[0][0]).toStrictEqual({ foo: "bar" });
|
|
226
|
-
expect(rtc.sendJsepMessage.mock.calls[0]).toBe(1);
|
|
227
|
-
});
|
|
228
|
-
});
|