detox 20.12.0-smoke.0 → 20.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. package/Detox-android/com/wix/detox/{20.12.0-smoke.0/detox-20.12.0-smoke.0-javadoc.jar → 20.12.0/detox-20.12.0-javadoc.jar} +0 -0
  2. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-javadoc.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-javadoc.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-javadoc.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-javadoc.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/{20.12.0-smoke.0/detox-20.12.0-smoke.0-sources.jar → 20.12.0/detox-20.12.0-sources.jar} +0 -0
  7. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-sources.jar.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-sources.jar.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-sources.jar.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0-sources.jar.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.aar +0 -0
  12. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.aar.md5 +1 -0
  13. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.aar.sha1 +1 -0
  14. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.aar.sha256 +1 -0
  15. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.aar.sha512 +1 -0
  16. package/Detox-android/com/wix/detox/{20.12.0-smoke.0/detox-20.12.0-smoke.0.pom → 20.12.0/detox-20.12.0.pom} +1 -1
  17. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.pom.md5 +1 -0
  18. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.pom.sha1 +1 -0
  19. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.pom.sha256 +1 -0
  20. package/Detox-android/com/wix/detox/20.12.0/detox-20.12.0.pom.sha512 +1 -0
  21. package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
  22. package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
  23. package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
  24. package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
  25. package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
  26. package/Detox-ios-src.tbz +0 -0
  27. package/Detox-ios.tbz +0 -0
  28. package/android/detox/build.gradle +1 -1
  29. package/android/detox/src/full/java/com/wix/detox/espresso/DetoxAssertion.java +44 -25
  30. package/android/detox/src/full/java/com/wix/detox/espresso/EspressoDetox.java +6 -7
  31. package/android/detox/src/full/java/com/wix/detox/espresso/action/GetAttributesAction.kt +4 -4
  32. package/android/detox/src/full/java/com/wix/detox/espresso/performer/MultipleViewsActionPerformer.kt +43 -0
  33. package/android/detox/src/full/java/com/wix/detox/espresso/performer/SingleViewActionPerformer.kt +19 -0
  34. package/android/detox/src/full/java/com/wix/detox/espresso/performer/ViewActionPerformer.kt +24 -0
  35. package/android/detox/src/full/java/com/wix/invoke/types/Invocation.java +5 -4
  36. package/android/detox/src/main/java/com/wix/detox/espresso/MultipleViewsAction.kt +4 -0
  37. package/android/detox/src/main/java/com/wix/detox/espresso/UiControllerSpy.kt +0 -1
  38. package/android/detox/src/main/java/com/wix/detox/espresso/ViewActionWithResult.kt +2 -1
  39. package/android/detox/src/testFull/java/com/wix/detox/espresso/action/GetAttributesActionTest.kt +6 -5
  40. package/android/detox/src/testFull/java/com/wix/detox/espresso/performer/ViewActionPerformerSpec.kt +37 -0
  41. package/index.d.ts +4 -3
  42. package/local-cli/reset-lock-file.js +9 -5
  43. package/package.json +6 -6
  44. package/src/DetoxWorker.js +9 -5
  45. package/src/android/core/NativeElement.js +26 -29
  46. package/src/android/espressoapi/DetoxAssertion.js +16 -14
  47. package/src/android/espressoapi/EspressoDetox.js +9 -2
  48. package/src/android/interactions/native.js +2 -3
  49. package/src/artifacts/providers/index.js +3 -3
  50. package/src/artifacts/screenshot/SimulatorScreenshotPlugin.js +17 -0
  51. package/src/devices/DeviceRegistry.js +176 -0
  52. package/src/devices/allocation/DeviceAllocator.js +15 -50
  53. package/src/devices/allocation/drivers/AllocationDriverBase.js +4 -10
  54. package/src/devices/allocation/drivers/android/attached/AttachedAndroidAllocDriver.js +6 -7
  55. package/src/devices/allocation/drivers/android/attached/AttachedAndroidLauncher.js +13 -0
  56. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocDriver.js +26 -108
  57. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocationHelper.js +72 -0
  58. package/src/devices/allocation/drivers/android/emulator/EmulatorLauncher.js +43 -33
  59. package/src/devices/allocation/drivers/android/emulator/FreeEmulatorFinder.js +1 -1
  60. package/src/devices/allocation/drivers/android/emulator/launchEmulatorProcess.js +3 -3
  61. package/src/devices/allocation/drivers/android/genycloud/GenyAllocDriver.js +27 -87
  62. package/src/devices/allocation/drivers/android/genycloud/GenyDeviceRegistryFactory.js +16 -0
  63. package/src/devices/allocation/drivers/android/genycloud/GenyInstanceAllocationHelper.js +65 -0
  64. package/src/devices/allocation/drivers/android/genycloud/GenyInstanceLauncher.js +28 -39
  65. package/src/devices/allocation/drivers/ios/SimulatorAllocDriver.js +40 -70
  66. package/src/devices/allocation/drivers/ios/SimulatorLauncher.js +7 -11
  67. package/src/devices/allocation/factories/android.js +35 -29
  68. package/src/devices/allocation/factories/ios.js +5 -7
  69. package/src/devices/common/drivers/DeviceAllocationHelper.js +20 -0
  70. package/src/devices/common/drivers/DeviceLauncher.js +19 -0
  71. package/src/devices/common/drivers/android/emulator/exec/EmulatorExec.js +5 -17
  72. package/src/devices/common/drivers/android/exec/ADB.js +0 -1
  73. package/src/devices/common/drivers/android/genycloud/services/GenyInstanceLifecycleService.js +25 -0
  74. package/src/devices/common/drivers/android/genycloud/services/GenyInstanceLookupService.js +38 -0
  75. package/src/devices/common/drivers/android/genycloud/services/GenyInstanceNaming.js +14 -0
  76. package/src/devices/{allocation → common}/drivers/android/genycloud/services/GenyRecipesService.js +1 -1
  77. package/src/devices/{allocation → common}/drivers/android/genycloud/services/dto/GenyInstance.js +1 -6
  78. package/src/devices/{allocation/drivers/android → common/drivers/android/tools}/FreeDeviceFinder.js +10 -11
  79. package/src/devices/common/drivers/ios/tools/AppleSimUtils.js +1 -1
  80. package/src/devices/cookies/AndroidDeviceCookie.js +0 -4
  81. package/src/devices/cookies/GenycloudEmulatorCookie.js +5 -3
  82. package/src/devices/cookies/IosSimulatorCookie.js +0 -4
  83. package/src/devices/lifecycle/GenyGlobalLifecycleHandler.js +71 -0
  84. package/src/devices/lifecycle/factories/GenyGlobalLifecycleHandlerFactory.js +18 -0
  85. package/src/devices/runtime/drivers/android/genycloud/GenyCloudDriver.js +2 -2
  86. package/src/devices/runtime/factories/android.js +1 -1
  87. package/src/devices/runtime/factories/ios.js +2 -3
  88. package/src/environmentFactory.js +11 -1
  89. package/src/ipc/IPCClient.js +1 -17
  90. package/src/ipc/IPCServer.js +1 -25
  91. package/src/realms/DetoxContext.js +0 -6
  92. package/src/realms/DetoxPrimaryContext.js +42 -42
  93. package/src/realms/DetoxSecondaryContext.js +0 -19
  94. package/src/realms/symbols.js +0 -4
  95. package/src/{devices/servicelocator → servicelocator}/android/emulatorServiceLocator.js +1 -1
  96. package/src/servicelocator/android/genycloudServiceLocator.js +21 -0
  97. package/src/servicelocator/android/index.js +25 -0
  98. package/src/servicelocator/ios.js +7 -0
  99. package/src/utils/environment.js +15 -8
  100. package/src/utils/errorUtils.js +2 -2
  101. package/src/{devices/validation → validation}/android/GenycloudEnvValidator.js +2 -2
  102. package/src/{devices/validation → validation}/factories/index.js +1 -1
  103. package/src/{devices/validation → validation}/ios/IosSimulatorEnvValidator.js +2 -2
  104. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-javadoc.jar.md5 +0 -1
  105. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-javadoc.jar.sha1 +0 -1
  106. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-javadoc.jar.sha256 +0 -1
  107. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-javadoc.jar.sha512 +0 -1
  108. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-sources.jar.md5 +0 -1
  109. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-sources.jar.sha1 +0 -1
  110. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-sources.jar.sha256 +0 -1
  111. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0-sources.jar.sha512 +0 -1
  112. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.aar +0 -0
  113. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.aar.md5 +0 -1
  114. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.aar.sha1 +0 -1
  115. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.aar.sha256 +0 -1
  116. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.aar.sha512 +0 -1
  117. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.pom.md5 +0 -1
  118. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.pom.sha1 +0 -1
  119. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.pom.sha256 +0 -1
  120. package/Detox-android/com/wix/detox/20.12.0-smoke.0/detox-20.12.0-smoke.0.pom.sha512 +0 -1
  121. package/src/devices/allocation/DeviceList.js +0 -44
  122. package/src/devices/allocation/DeviceRegistry.js +0 -186
  123. package/src/devices/allocation/drivers/android/emulator/FreePortFinder.js +0 -16
  124. package/src/devices/allocation/drivers/android/genycloud/GenyRegistry.js +0 -93
  125. package/src/devices/allocation/drivers/android/genycloud/services/GenyInstanceLifecycleService.js +0 -24
  126. package/src/devices/allocation/drivers/ios/SimulatorQuery.js +0 -24
  127. package/src/devices/servicelocator/android/genycloudServiceLocator.js +0 -17
  128. package/src/devices/servicelocator/android/index.js +0 -23
  129. package/src/utils/PIDService.js +0 -27
  130. /package/src/devices/{allocation → common}/drivers/android/genycloud/exec/GenyCloudExec.js +0 -0
  131. /package/src/devices/{allocation → common}/drivers/android/genycloud/services/GenyAuthService.js +0 -0
  132. /package/src/devices/{allocation → common}/drivers/android/genycloud/services/dto/GenyRecipe.js +0 -0
  133. /package/src/{devices/validation → validation}/EnvironmentValidatorBase.js +0 -0
@@ -1,5 +1,5 @@
1
1
  // @ts-nocheck
2
- const log = require('../../utils/logger').child({ cat: 'device,device-allocation' });
2
+ const log = require('../../utils/logger').child({ cat: 'device' });
3
3
  const traceMethods = require('../../utils/traceMethods');
4
4
 
5
5
  class DeviceAllocator {
@@ -8,71 +8,36 @@ class DeviceAllocator {
8
8
  */
9
9
  constructor(allocationDriver) {
10
10
  this._driver = allocationDriver;
11
- traceMethods(log, this, ['init', 'cleanup', 'emergencyCleanup']);
12
- }
13
-
14
- /**
15
- * @returns {Promise<void>}
16
- */
17
- async init() {
18
- if (typeof this._driver.init === 'function') {
19
- await this._driver.init();
20
- }
11
+ traceMethods(log, this, ['allocate', 'postAllocate', 'free']);
21
12
  }
22
13
 
23
14
  /**
24
15
  * @param deviceConfig { Object }
25
- * @returns {Promise<DeviceCookie>}
16
+ * @return {Promise<DeviceCookie>}
26
17
  */
27
- async allocate(deviceConfig) {
28
- return await log.trace.complete({ data: deviceConfig, id: Math.random() }, 'allocate', async () => {
29
- const cookie = await this._driver.allocate(deviceConfig);
30
- log.debug({ event: undefined }, `settled on ${cookie}`);
31
- return cookie;
32
- });
18
+ allocate(deviceConfig) {
19
+ return this._driver.allocate(deviceConfig);
33
20
  }
34
21
 
35
22
  /**
36
23
  * @param {DeviceCookie} deviceCookie
37
- * @returns {Promise<DeviceCookie>}
24
+ * @return {Promise<unknown>}
38
25
  */
39
- async postAllocate(deviceCookie) {
40
- return await log.trace.complete({ data: deviceCookie, id: Math.random() }, `post-allocate: ${deviceCookie}`, async () => {
41
- const updatedCookie = typeof this._driver.postAllocate === 'function'
42
- ? await this._driver.postAllocate(deviceCookie)
43
- : undefined;
26
+ postAllocate(deviceCookie) {
27
+ if (typeof this._driver.postAllocate !== 'function') {
28
+ return Promise.resolve();
29
+ }
44
30
 
45
- return updatedCookie || deviceCookie;
46
- });
31
+ return this._driver.postAllocate(deviceCookie);
47
32
  }
48
33
 
49
34
  /**
50
35
  * @param cookie { DeviceCookie }
51
- * @param options { Partial<DeallocOptions> }
52
- * @returns {Promise<void>}
53
- */
54
- async free(cookie, options = {}) {
55
- await log.trace.complete({ data: options, id: Math.random() }, `free: ${cookie}`, async () => {
56
- await this._driver.free(cookie, options);
57
- });
58
- }
59
-
60
- /**
61
- * @returns {Promise<void>}
62
- */
63
- async cleanup() {
64
- if (typeof this._driver.cleanup === 'function') {
65
- await this._driver.cleanup();
66
- }
67
- }
68
-
69
- /**
70
- * @returns {void}
36
+ * @param options { DeallocOptions }
37
+ * @return {Promise<void>}
71
38
  */
72
- emergencyCleanup() {
73
- if (typeof this._driver.emergencyCleanup === 'function') {
74
- this._driver.emergencyCleanup();
75
- }
39
+ free(cookie, options) {
40
+ return this._driver.free(cookie, options);
76
41
  }
77
42
  }
78
43
 
@@ -7,30 +7,24 @@
7
7
  */
8
8
 
9
9
  class AllocationDriverBase {
10
- async init() {}
11
-
12
10
  /**
13
11
  * @param deviceConfig { Object }
14
- * @return {Promise<import('../../cookies/DeviceCookie')>}
12
+ * @return {Promise<DeviceCookie>}
15
13
  */
16
14
  async allocate(deviceConfig) {}
17
15
 
18
16
  /**
19
- * @param {import('../../cookies/DeviceCookie')} deviceCookie
20
- * @return {Promise<import('../../cookies/DeviceCookie') | void>}
17
+ * @param {DeviceCookie} deviceCookie
18
+ * @return {Promise<void>}
21
19
  */
22
20
  async postAllocate(deviceCookie) {}
23
21
 
24
22
  /**
25
- * @param cookie { import('../../cookies/DeviceCookie') }
23
+ * @param cookie { DeviceCookie }
26
24
  * @param options { DeallocOptions }
27
25
  * @return {Promise<void>}
28
26
  */
29
27
  async free(cookie, options) {}
30
-
31
- async cleanup() {}
32
-
33
- emergencyCleanup() {}
34
28
  }
35
29
 
36
30
  module.exports = AllocationDriverBase;
@@ -7,16 +7,14 @@ class AttachedAndroidAllocDriver extends AllocationDriverBase {
7
7
  * @param adb { ADB }
8
8
  * @param deviceRegistry { DeviceRegistry }
9
9
  * @param freeDeviceFinder { FreeDeviceFinder }
10
+ * @param attachedAndroidLauncher { AttachedAndroidLauncher }
10
11
  */
11
- constructor({ adb, deviceRegistry, freeDeviceFinder }) {
12
+ constructor({ adb, deviceRegistry, freeDeviceFinder, attachedAndroidLauncher }) {
12
13
  super();
13
14
  this._adb = adb;
14
15
  this._deviceRegistry = deviceRegistry;
15
16
  this._freeDeviceFinder = freeDeviceFinder;
16
- }
17
-
18
- async init() {
19
- await this._deviceRegistry.unregisterZombieDevices();
17
+ this._attachedAndroidLauncher = attachedAndroidLauncher;
20
18
  }
21
19
 
22
20
  /**
@@ -25,7 +23,7 @@ class AttachedAndroidAllocDriver extends AllocationDriverBase {
25
23
  */
26
24
  async allocate(deviceConfig) {
27
25
  const adbNamePattern = deviceConfig.device.adbName;
28
- const adbName = await this._deviceRegistry.registerDevice(() => this._freeDeviceFinder.findFreeDevice(adbNamePattern));
26
+ const adbName = await this._deviceRegistry.allocateDevice(() => this._freeDeviceFinder.findFreeDevice(adbNamePattern));
29
27
 
30
28
  return new AttachedAndroidDeviceCookie(adbName);
31
29
  }
@@ -40,6 +38,7 @@ class AttachedAndroidAllocDriver extends AllocationDriverBase {
40
38
  // TODO Also disable native animations?
41
39
  await this._adb.apiLevel(adbName);
42
40
  await this._adb.unlockScreen(adbName);
41
+ await this._attachedAndroidLauncher.notifyLaunchCompleted(adbName);
43
42
  }
44
43
 
45
44
  /**
@@ -48,7 +47,7 @@ class AttachedAndroidAllocDriver extends AllocationDriverBase {
48
47
  */
49
48
  async free(cookie) {
50
49
  const { adbName } = cookie;
51
- await this._deviceRegistry.unregisterDevice(adbName);
50
+ await this._deviceRegistry.disposeDevice(adbName);
52
51
  }
53
52
  }
54
53
 
@@ -0,0 +1,13 @@
1
+ const DeviceLauncher = require('../../../../common/drivers/DeviceLauncher');
2
+
3
+ class AttachedAndroidLauncher extends DeviceLauncher {
4
+ constructor(eventEmitter) {
5
+ super(eventEmitter);
6
+ }
7
+
8
+ notifyLaunchCompleted(adbName) {
9
+ return super._notifyBootEvent(adbName, 'device', false);
10
+ }
11
+ }
12
+
13
+ module.exports = AttachedAndroidLauncher;
@@ -1,7 +1,6 @@
1
+ // @ts-nocheck
1
2
  const _ = require('lodash');
2
3
 
3
- const Deferred = require('../../../../../utils/Deferred');
4
- const log = require('../../../../../utils/logger').child({ cat: 'device,device-allocation' });
5
4
  const AndroidEmulatorCookie = require('../../../../cookies/AndroidEmulatorCookie');
6
5
  const AllocationDriverBase = require('../../AllocationDriverBase');
7
6
 
@@ -9,45 +8,20 @@ const { patchAvdSkinConfig } = require('./patchAvdSkinConfig');
9
8
 
10
9
  class EmulatorAllocDriver extends AllocationDriverBase {
11
10
  /**
12
- * @param {object} options
13
- * @param {import('../../../../common/drivers/android/exec/ADB')} options.adb
14
- * @param {import('./AVDValidator')} options.avdValidator
15
- * @param {DetoxInternals.RuntimeConfig} options.detoxConfig
16
- * @param {import('../../../DeviceRegistry')} options.deviceRegistry
17
- * @param {import('./FreeEmulatorFinder')} options.freeDeviceFinder
18
- * @param {import('./FreePortFinder')} options.freePortFinder
19
- * @param {import('./EmulatorLauncher')} options.emulatorLauncher
20
- * @param {import('./EmulatorVersionResolver')} options.emulatorVersionResolver
11
+ * @param adb { ADB }
12
+ * @param avdValidator { AVDValidator }
13
+ * @param emulatorVersionResolver { EmulatorVersionResolver }
14
+ * @param emulatorLauncher { EmulatorLauncher }
15
+ * @param allocationHelper { EmulatorAllocationHelper }
21
16
  */
22
- constructor({
23
- adb,
24
- avdValidator,
25
- detoxConfig,
26
- deviceRegistry,
27
- freeDeviceFinder,
28
- freePortFinder,
29
- emulatorVersionResolver,
30
- emulatorLauncher
31
- }) {
17
+ constructor({ adb, avdValidator, emulatorVersionResolver, emulatorLauncher, allocationHelper }) {
32
18
  super();
33
-
34
- /** @type {Deferred} */
35
- this._deferredAllocation = Deferred.resolved(null);
36
- /** @type {Promise<unknown>} */
37
- this._pendingAllocation = Promise.resolve();
38
-
39
19
  this._adb = adb;
40
20
  this._avdValidator = avdValidator;
41
- this._deviceRegistry = deviceRegistry;
42
21
  this._emulatorVersionResolver = emulatorVersionResolver;
43
22
  this._emulatorLauncher = emulatorLauncher;
44
- this._freeDeviceFinder = freeDeviceFinder;
45
- this._freePortFinder = freePortFinder;
46
- this._shouldShutdown = detoxConfig.behavior.cleanup.shutdownDevice;
47
- }
48
-
49
- async init() {
50
- await this._deviceRegistry.unregisterZombieDevices();
23
+ this._allocationHelper = allocationHelper;
24
+ this._launchInfo = {};
51
25
  }
52
26
 
53
27
  /**
@@ -55,111 +29,55 @@ class EmulatorAllocDriver extends AllocationDriverBase {
55
29
  * @returns {Promise<AndroidEmulatorCookie>}
56
30
  */
57
31
  async allocate(deviceConfig) {
58
- await this._pendingAllocation.catch(() => { /* ignore previous errors */ });
59
- this._deferredAllocation = new Deferred();
60
- this._pendingAllocation = this._deviceRegistry.registerDevice(() => this._deferredAllocation.promise);
61
-
62
- try {
63
- return await this._doAllocate(deviceConfig);
64
- } catch (e) {
65
- this._deferredAllocation.reject(e);
66
- throw e;
67
- }
68
- }
69
-
70
- /**
71
- * @param deviceConfig
72
- * @returns {Promise<AndroidEmulatorCookie>}
73
- */
74
- async _doAllocate(deviceConfig) {
75
32
  const avdName = deviceConfig.device.avdName;
76
33
 
77
34
  await this._avdValidator.validate(avdName, deviceConfig.headless);
78
35
  await this._fixAvdConfigIniSkinNameIfNeeded(avdName, deviceConfig.headless);
79
36
 
80
- let adbName = await this._freeDeviceFinder.findFreeDevice(avdName);
81
- if (!adbName) {
82
- const port = await this._freePortFinder.findFreePort();
83
- adbName = `emulator-${port}`;
37
+ const allocResult = await this._allocationHelper.allocateDevice(avdName);
38
+ const { adbName } = allocResult;
84
39
 
85
- await this._emulatorLauncher.launch({
40
+ this._launchInfo[adbName] = {
41
+ avdName,
42
+ isRunning: allocResult.isRunning,
43
+ launchOptions: {
86
44
  bootArgs: deviceConfig.bootArgs,
87
45
  gpuMode: deviceConfig.gpuMode,
88
46
  headless: deviceConfig.headless,
89
47
  readonly: deviceConfig.readonly,
90
- avdName,
91
- adbName,
92
- port,
93
- });
94
- }
48
+ port: allocResult.placeholderPort,
49
+ },
50
+ };
95
51
 
96
52
  return new AndroidEmulatorCookie(adbName);
97
53
  }
98
54
 
99
- /**
100
- * @param {AndroidEmulatorCookie} deviceCookie
101
- */
102
- async postAllocate(deviceCookie) {
103
- try {
104
- await this._doPostAllocate(deviceCookie);
105
- this._deferredAllocation.resolve(deviceCookie.adbName);
106
- } catch (e) {
107
- this._deferredAllocation.reject(e);
108
- throw e;
109
- }
110
- }
111
-
112
55
  /**
113
56
  * @param {AndroidEmulatorCookie} deviceCookie
114
57
  * @returns {Promise<void>}
115
58
  */
116
- async _doPostAllocate(deviceCookie) {
59
+ async postAllocate(deviceCookie) {
117
60
  const { adbName } = deviceCookie;
61
+ const { avdName, isRunning, launchOptions } = this._launchInfo[adbName];
118
62
 
119
- await this._emulatorLauncher.awaitEmulatorBoot(adbName);
63
+ await this._emulatorLauncher.launch(avdName, adbName, isRunning, launchOptions);
120
64
  await this._adb.apiLevel(adbName);
121
65
  await this._adb.disableAndroidAnimations(adbName);
122
66
  await this._adb.unlockScreen(adbName);
123
67
  }
124
68
 
125
69
  /**
126
- * @param cookie {AndroidEmulatorCookie}
127
- * @param options {Partial<import('../../AllocationDriverBase').DeallocOptions>}
128
- * @return {Promise<void>}
70
+ * @param cookie { AndroidEmulatorCookie }
71
+ * @param options { DeallocOptions }
72
+ * @return { Promise<void> }
129
73
  */
130
74
  async free(cookie, options = {}) {
131
75
  const { adbName } = cookie;
132
76
 
133
- if (options.shutdown) {
134
- await this._doShutdown(adbName);
135
- await this._deviceRegistry.unregisterDevice(adbName);
136
- } else {
137
- await this._deviceRegistry.releaseDevice(adbName);
138
- }
139
- }
140
-
141
- async cleanup() {
142
- if (this._shouldShutdown) {
143
- const { devices } = await this._adb.devices();
144
- const actualEmulators = devices.map((device) => device.adbName);
145
- const sessionDevices = await this._deviceRegistry.readSessionDevices();
146
- const emulatorsToShutdown = _.intersection(sessionDevices.getIds(), actualEmulators);
147
- const shutdownPromises = emulatorsToShutdown.map((adbName) => this._doShutdown(adbName));
148
- await Promise.all(shutdownPromises);
149
- }
150
-
151
- await this._deviceRegistry.unregisterSessionDevices();
152
- }
77
+ await this._allocationHelper.deallocateDevice(adbName);
153
78
 
154
- /**
155
- * @param {string} adbName
156
- * @return {Promise<void>}
157
- */
158
- async _doShutdown(adbName) {
159
- try {
79
+ if (options.shutdown) {
160
80
  await this._emulatorLauncher.shutdown(adbName);
161
- } catch (err) {
162
- log.warn({ err }, `Failed to shutdown emulator ${adbName}`);
163
81
  }
164
82
  }
165
83
 
@@ -0,0 +1,72 @@
1
+ const logger = require('../../../../../utils/logger').child({ cat: 'device' });
2
+ const DeviceAllocationHelper = require('../../../../common/drivers/DeviceAllocationHelper');
3
+
4
+ const DetoxEmulatorsPortRange = {
5
+ min: 10000,
6
+ max: 20000
7
+ };
8
+
9
+ class AllocationResult {
10
+ constructor(adbName, placeholderPort) {
11
+ this.adbName = adbName;
12
+ this.placeholderPort = placeholderPort;
13
+ }
14
+
15
+ get isRunning() {
16
+ return !this.placeholderPort;
17
+ }
18
+ }
19
+
20
+ class EmulatorAllocationHelper extends DeviceAllocationHelper {
21
+ constructor(deviceRegistry, freeDeviceFinder, rand = Math.random) {
22
+ super(deviceRegistry, logger);
23
+ this._freeDeviceFinder = freeDeviceFinder;
24
+ this._rand = rand;
25
+ }
26
+
27
+ /**
28
+ * @param avdName
29
+ * @returns {Promise<AllocationResult>}
30
+ */
31
+ async allocateDevice(avdName) {
32
+ this._logAllocationAttempt(avdName);
33
+
34
+ const result = await this._doSynchronizedAllocation(avdName);
35
+ this._logAllocationResult(avdName, result.adbName);
36
+
37
+ return result;
38
+ }
39
+
40
+ async deallocateDevice(adbName) {
41
+ await this._deviceRegistry.disposeDevice(adbName);
42
+ }
43
+
44
+ /**
45
+ * @returns {Promise<AllocationResult>}
46
+ * @private
47
+ */
48
+ async _doSynchronizedAllocation(avdName) {
49
+ let placeholderPort = null;
50
+ let adbName = null;
51
+
52
+ await this._deviceRegistry.allocateDevice(async () => {
53
+ adbName = await this._freeDeviceFinder.findFreeDevice(avdName);
54
+ if (!adbName) {
55
+ placeholderPort = this._allocateEmulatorPlaceholderPort();
56
+ adbName = `emulator-${placeholderPort}`;
57
+ }
58
+ return adbName;
59
+ });
60
+
61
+ return new AllocationResult(adbName, placeholderPort);
62
+ }
63
+
64
+ _allocateEmulatorPlaceholderPort() {
65
+ const { min, max } = DetoxEmulatorsPortRange;
66
+ let port = this._rand() * (max - min) + min;
67
+ port = port & 0xFFFFFFFE; // Should always be even
68
+ return port;
69
+ }
70
+ }
71
+
72
+ module.exports = EmulatorAllocationHelper;
@@ -3,54 +3,47 @@ const { DetoxRuntimeError } = require('../../../../../errors');
3
3
  const log = require('../../../../../utils/logger').child({ cat: 'device' });
4
4
  const retry = require('../../../../../utils/retry');
5
5
  const traceMethods = require('../../../../../utils/traceMethods');
6
+ const DeviceLauncher = require('../../../../common/drivers/DeviceLauncher');
6
7
  const { LaunchCommand } = require('../../../../common/drivers/android/emulator/exec/EmulatorExec');
7
8
 
8
9
  const { launchEmulatorProcess } = require('./launchEmulatorProcess');
9
10
 
10
11
  const isUnknownEmulatorError = (err) => (err.message || '').includes('failed with code null');
11
12
 
12
- class EmulatorLauncher {
13
- constructor({ adb, emulatorExec }) {
13
+ class EmulatorLauncher extends DeviceLauncher {
14
+ constructor({ adb, emulatorExec, eventEmitter }) {
15
+ super(eventEmitter);
14
16
  this._adb = adb;
15
17
  this._emulatorExec = emulatorExec;
16
- traceMethods(log, this, ['awaitEmulatorBoot']);
18
+ traceMethods(log, this, ['_awaitEmulatorBoot']);
17
19
  }
18
20
 
19
21
  /**
20
- * @param {object} options
21
- * @param {string} options.avdName
22
- * @param {string} options.adbName
23
- * @param {number} options.port
24
- * @param {string | undefined} options.bootArgs
25
- * @param {string | undefined} options.gpuMode
26
- * @param {boolean} options.headless
27
- * @param {boolean} options.readonly
22
+ * @param avdName { String }
23
+ * @param adbName { String }
24
+ * @param isRunning { Boolean }
25
+ * @param options { Object }
26
+ * @param options.port { Number | undefined }
27
+ * @param options.bootArgs { String | undefined }
28
+ * @param options.gpuMode { String | undefined }
29
+ * @param options.headless { Boolean }
30
+ * @param options.readonly { Boolean }
28
31
  */
29
- async launch(options) {
30
- const launchCommand = new LaunchCommand(options);
31
- await retry({
32
- retries: 2,
33
- interval: 100,
34
- conditionFn: isUnknownEmulatorError,
35
- }, () => launchEmulatorProcess(this._emulatorExec, this._adb, launchCommand));
36
- }
37
-
38
- /**
39
- * @param {string} adbName
40
- */
41
- async awaitEmulatorBoot(adbName) {
42
- await retry({ retries: 240, interval: 2500, shouldUnref: true }, async () => {
43
- const isBootComplete = await this._adb.isBootComplete(adbName);
44
-
45
- if (!isBootComplete) {
46
- throw new DetoxRuntimeError({
47
- message: `Waited for ${adbName} to complete booting for too long!`,
48
- });
49
- }
50
- });
32
+ async launch(avdName, adbName, isRunning, options = { port: undefined }) {
33
+ if (!isRunning) {
34
+ const launchCommand = new LaunchCommand(avdName, options);
35
+ await retry({
36
+ retries: 2,
37
+ interval: 100,
38
+ conditionFn: isUnknownEmulatorError,
39
+ }, () => this._launchEmulator(avdName, launchCommand, adbName));
40
+ }
41
+ await this._awaitEmulatorBoot(adbName);
42
+ await this._notifyBootEvent(adbName, avdName, !isRunning);
51
43
  }
52
44
 
53
45
  async shutdown(adbName) {
46
+ await this._notifyPreShutdown(adbName);
54
47
  await this._adb.emuKill(adbName);
55
48
  await retry({
56
49
  retries: 5,
@@ -64,6 +57,23 @@ class EmulatorLauncher {
64
57
  });
65
58
  }
66
59
  });
60
+ await this._notifyShutdownCompleted(adbName);
61
+ }
62
+
63
+ _launchEmulator(emulatorName, launchCommand, adbName) {
64
+ return launchEmulatorProcess(emulatorName, this._emulatorExec, launchCommand, this._adb, adbName);
65
+ }
66
+
67
+ async _awaitEmulatorBoot(adbName) {
68
+ await retry({ retries: 240, interval: 2500, shouldUnref: true }, async () => {
69
+ const isBootComplete = await this._adb.isBootComplete(adbName);
70
+
71
+ if (!isBootComplete) {
72
+ throw new DetoxRuntimeError({
73
+ message: `Waited for ${adbName} to complete booting for too long!`,
74
+ });
75
+ }
76
+ });
67
77
  }
68
78
  }
69
79
 
@@ -1,4 +1,4 @@
1
- const FreeDeviceFinder = require('../FreeDeviceFinder');
1
+ const FreeDeviceFinder = require('../../../../common/drivers/android/tools/FreeDeviceFinder');
2
2
 
3
3
  class FreeEmulatorFinder extends FreeDeviceFinder {
4
4
  /**
@@ -4,10 +4,10 @@ const _ = require('lodash');
4
4
 
5
5
  const unitLogger = require('../../../../../utils/logger').child({ cat: 'device' });
6
6
 
7
- function launchEmulatorProcess(emulatorExec, adb, emulatorLaunchCommand) {
7
+ function launchEmulatorProcess(emulatorName, emulatorExec, emulatorLaunchCommand, adb, adbName) {
8
8
  let childProcessOutput;
9
9
  const portName = emulatorLaunchCommand.port ? `-${emulatorLaunchCommand.port}` : '';
10
- const tempLog = `./${emulatorLaunchCommand.avdName}${portName}.log`;
10
+ const tempLog = `./${emulatorName}${portName}.log`;
11
11
  const stdout = fs.openSync(tempLog, 'a');
12
12
  const stderr = fs.openSync(tempLog, 'a');
13
13
 
@@ -31,7 +31,7 @@ function launchEmulatorProcess(emulatorExec, adb, emulatorLaunchCommand) {
31
31
 
32
32
  log = log.child({ child_pid: childProcessPromise.childProcess.pid });
33
33
 
34
- adb.waitForDevice(emulatorLaunchCommand.adbName).then(() => childProcessPromise._cpResolve());
34
+ adb.waitForDevice(adbName).then(() => childProcessPromise._cpResolve());
35
35
 
36
36
  return childProcessPromise.then(() => true).catch((err) => {
37
37
  detach();