From 90bf1eec1cea7a159f6384462793f1d478b104de Mon Sep 17 00:00:00 2001 From: Andrei Kamarouski Date: Thu, 11 Jan 2024 12:04:38 +0100 Subject: [PATCH 1/9] feature(STFClient): do not use 'unheathy' and 'unauthorized' devices for automation --- .../grid/integration/client/STFClient.java | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java b/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java index 435a7d2..6ab5f32 100644 --- a/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java +++ b/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java @@ -15,6 +15,7 @@ *******************************************************************************/ package com.zebrunner.mcloud.grid.integration.client; +import java.time.Duration; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -36,11 +37,15 @@ public final class STFClient { private static final Logger LOGGER = Logger.getLogger(STFClient.class.getName()); private static final Map STF_CLIENTS = new ConcurrentHashMap<>(); + private static final Map STF_DEVICE_IGNORE_AUTOMATION_TIMERS = new ConcurrentHashMap<>(); private static final String STF_URL = System.getenv("STF_URL"); private static final String DEFAULT_STF_TOKEN = System.getenv("STF_TOKEN"); // Max time is seconds for reserving devices in STF private static final String DEFAULT_STF_TIMEOUT = System.getenv("STF_TIMEOUT"); + private static final Duration UNAUTHORIZED_TIMEOUT = Duration.ofMinutes(10); + private static final Duration UNHEALTHY_TIMEOUT = Duration.ofMinutes(5); + private Platform platform; private String token; private boolean isReservedManually = false; @@ -72,6 +77,17 @@ public static boolean reserveSTFDevice(String deviceUDID, Map re if (!isSTFEnabled()) { return true; } + + if (STF_DEVICE_IGNORE_AUTOMATION_TIMERS.get(deviceUDID) != null) { + Duration timeout = STF_DEVICE_IGNORE_AUTOMATION_TIMERS.get(deviceUDID); + if (Duration.ofMillis(System.currentTimeMillis()).compareTo(timeout) < 0) { + return false; + } else { + STF_DEVICE_IGNORE_AUTOMATION_TIMERS.remove(deviceUDID); + } + } + + if (STF_CLIENTS.get(deviceUDID) != null) { LOGGER.warning(() -> String.format("Device '%s' already busy (in the local pool). Info: %s", deviceUDID, STF_CLIENTS.get(deviceUDID))); } @@ -116,10 +132,28 @@ public static boolean reserveSTFDevice(String deviceUDID, Map re } STFDevice stfDevice = optionalSTFDevice.get(); - LOGGER.info(() -> String.format("[STF-%s] STF Device info: %s", sessionUUID, stfDevice)); + LOGGER.info(() -> String.format("[STF-%s] STF device info: %s", sessionUUID, stfDevice)); stfClient.setDevice(stfDevice); + if(stfDevice.getStatus() == null) { + LOGGER.warning(() -> String.format("[STF-%s] STF device status is null. It will be ignored.", sessionUUID)); + return false; + } + + if(stfDevice.getStatus().intValue() == 2) { + LOGGER.warning(() -> String.format("[STF-%s] STF device status 'UNAUTHORIZED'. It will be ignored: %s.", sessionUUID, + UNAUTHORIZED_TIMEOUT)); + STF_DEVICE_IGNORE_AUTOMATION_TIMERS.put(deviceUDID, Duration.ofMillis(System.currentTimeMillis()).plus(UNAUTHORIZED_TIMEOUT)); + return false; + } + + if(stfDevice.getStatus() == 7) { + LOGGER.warning(() -> String.format("[STF-%s] STF device status 'UNHEALTHY'. It will be ignored: %s.", sessionUUID, UNHEALTHY_TIMEOUT)); + STF_DEVICE_IGNORE_AUTOMATION_TIMERS.put(deviceUDID, Duration.ofMillis(System.currentTimeMillis()).plus(UNHEALTHY_TIMEOUT)); + return false; + } + if (stfDevice.getOwner() != null && StringUtils.equals(stfDevice.getOwner().getName(), user.getObject().getUser().getName()) && stfDevice.getPresent() && stfDevice.getReady()) { From 5a2001eff13f982d7ea2d902ed69733faabcf659 Mon Sep 17 00:00:00 2001 From: Andrei Kamarouski Date: Fri, 12 Jan 2024 12:25:25 +0100 Subject: [PATCH 2/9] feature(STFClient): mark device as unheathy if response status 0 (when try to reserve device) --- .../mcloud/grid/integration/client/STFClient.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java b/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java index 6ab5f32..7580d14 100644 --- a/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java +++ b/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java @@ -171,6 +171,16 @@ public static boolean reserveSTFDevice(String deviceUDID, Map re if (response.getStatus() != 200) { LOGGER.warning(() -> String.format("[STF-%s] Could not reserve STF device with udid: %s. Status: %s. Response: %s", sessionUUID, deviceUDID, response.getStatus(), response.getObject())); + if(response.getStatus() == 0) { + LOGGER.warning(() -> String.format("[STF-%s] Device will be marked as unhealthy due to response status '0'.", sessionUUID)); + entity.put("body", Map.of("status", "Unhealthy")); + HttpClient.Response r = HttpClient.uri(Path.STF_DEVICES_ITEM_PATH, STF_URL, deviceUDID) + .withAuthorization(buildAuthToken(stfToken)) + .put(Void.class, entity); + if(r.getStatus() != 200) { + LOGGER.warning(() -> String.format("[STF-%s] Could not mark device as unhealthy. Status: %s. Response: %s", sessionUUID, r.getStatus(), r.getObject())); + } + } return false; } } else { From 50fa552c2b859271dcb6831542131e1d43d3bf8c Mon Sep 17 00:00:00 2001 From: Andrei Kamarouski Date: Fri, 12 Jan 2024 12:52:48 +0100 Subject: [PATCH 3/9] feature(MobileRemoteProxy): add more info about 'Node is down' error --- .../mcloud/grid/MobileRemoteProxy.java | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/zebrunner/mcloud/grid/MobileRemoteProxy.java b/src/main/java/com/zebrunner/mcloud/grid/MobileRemoteProxy.java index 8ceaa80..051f3df 100644 --- a/src/main/java/com/zebrunner/mcloud/grid/MobileRemoteProxy.java +++ b/src/main/java/com/zebrunner/mcloud/grid/MobileRemoteProxy.java @@ -15,6 +15,7 @@ *******************************************************************************/ package com.zebrunner.mcloud.grid; +import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -29,6 +30,7 @@ import org.apache.http.entity.StringEntity; import org.openqa.grid.common.RegistrationRequest; import org.openqa.grid.internal.GridRegistry; +import org.openqa.grid.internal.RemoteProxy; import org.openqa.grid.internal.TestSession; import org.openqa.grid.internal.TestSlot; import org.openqa.grid.selenium.proxy.DefaultRemoteProxy; @@ -68,7 +70,26 @@ public TestSession getNewSession(Map requestedCapability) { return null; } if (isDown()) { - LOGGER.info(() -> "Node is down."); + TestSlot slot = getTestSlots().get(0); + if (slot != null) { + LOGGER.info(() -> String.format("Node is down: '%s:%s' - '%s (%s)'", + Optional.of(slot) + .map(TestSlot::getProxy) + .map(RemoteProxy::getRemoteHost) + .map(URL::getHost) + .orElse(StringUtils.EMPTY), + Optional.of(slot) + .map(TestSlot::getProxy) + .map(RemoteProxy::getRemoteHost) + .map(URL::getPort) + .map(String::valueOf) + .orElse(StringUtils.EMPTY), + CapabilityUtils.getAppiumCapability(slot.getCapabilities(), "udid"), + CapabilityUtils.getAppiumCapability(slot.getCapabilities(), "deviceName")) + ); + } else { + LOGGER.info(() -> "Node is down."); + } return null; } if (!hasCapability(requestedCapability)) { From 74d4ddd242a0d5fc2b5617e6feef666ab682add7 Mon Sep 17 00:00:00 2001 From: Andrei Kamarouski Date: Wed, 24 Jan 2024 15:36:40 +0100 Subject: [PATCH 4/9] refactor(MobileRemoteProxy): code cleanup --- .../mcloud/grid/MobileRemoteProxy.java | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/zebrunner/mcloud/grid/MobileRemoteProxy.java b/src/main/java/com/zebrunner/mcloud/grid/MobileRemoteProxy.java index 051f3df..d6d7007 100644 --- a/src/main/java/com/zebrunner/mcloud/grid/MobileRemoteProxy.java +++ b/src/main/java/com/zebrunner/mcloud/grid/MobileRemoteProxy.java @@ -70,26 +70,25 @@ public TestSession getNewSession(Map requestedCapability) { return null; } if (isDown()) { - TestSlot slot = getTestSlots().get(0); - if (slot != null) { - LOGGER.info(() -> String.format("Node is down: '%s:%s' - '%s (%s)'", - Optional.of(slot) - .map(TestSlot::getProxy) - .map(RemoteProxy::getRemoteHost) - .map(URL::getHost) - .orElse(StringUtils.EMPTY), - Optional.of(slot) - .map(TestSlot::getProxy) - .map(RemoteProxy::getRemoteHost) - .map(URL::getPort) - .map(String::valueOf) - .orElse(StringUtils.EMPTY), - CapabilityUtils.getAppiumCapability(slot.getCapabilities(), "udid"), - CapabilityUtils.getAppiumCapability(slot.getCapabilities(), "deviceName")) - ); - } else { - LOGGER.info(() -> "Node is down."); - } + getTestSlots().stream() + .findAny() + .ifPresent((slot -> { + LOGGER.info(() -> String.format("Node is down: '%s:%s' - '%s (%s)'", + Optional.of(slot) + .map(TestSlot::getProxy) + .map(RemoteProxy::getRemoteHost) + .map(URL::getHost) + .orElse(StringUtils.EMPTY), + Optional.of(slot) + .map(TestSlot::getProxy) + .map(RemoteProxy::getRemoteHost) + .map(URL::getPort) + .map(String::valueOf) + .orElse(StringUtils.EMPTY), + CapabilityUtils.getAppiumCapability(slot.getCapabilities(), "udid"), + CapabilityUtils.getAppiumCapability(slot.getCapabilities(), "deviceName")) + ); + })); return null; } if (!hasCapability(requestedCapability)) { From c0daacc9d7c282f9dcfaf171a1be2d5502ce9bf5 Mon Sep 17 00:00:00 2001 From: Andrei Kamarouski Date: Wed, 24 Jan 2024 15:51:48 +0100 Subject: [PATCH 5/9] refactor(STFClient): change log --- .../grid/integration/client/STFClient.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java b/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java index 7580d14..002b2e8 100644 --- a/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java +++ b/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java @@ -43,6 +43,7 @@ public final class STFClient { // Max time is seconds for reserving devices in STF private static final String DEFAULT_STF_TIMEOUT = System.getenv("STF_TIMEOUT"); + private static final Duration INVALID_STF_RESPONSE_TIMEOUT = Duration.ofMinutes(10); private static final Duration UNAUTHORIZED_TIMEOUT = Duration.ofMinutes(10); private static final Duration UNHEALTHY_TIMEOUT = Duration.ofMinutes(5); @@ -81,6 +82,10 @@ public static boolean reserveSTFDevice(String deviceUDID, Map re if (STF_DEVICE_IGNORE_AUTOMATION_TIMERS.get(deviceUDID) != null) { Duration timeout = STF_DEVICE_IGNORE_AUTOMATION_TIMERS.get(deviceUDID); if (Duration.ofMillis(System.currentTimeMillis()).compareTo(timeout) < 0) { + LOGGER.warning(() -> String.format("[STF-%s] The next attempt to reserve '%s' STF device will be given only after '%s' minutes.", + sessionUUID, + deviceUDID, + timeout.minus(Duration.ofMillis(System.currentTimeMillis())).toMinutes())); return false; } else { STF_DEVICE_IGNORE_AUTOMATION_TIMERS.remove(deviceUDID); @@ -137,19 +142,22 @@ public static boolean reserveSTFDevice(String deviceUDID, Map re stfClient.setDevice(stfDevice); if(stfDevice.getStatus() == null) { - LOGGER.warning(() -> String.format("[STF-%s] STF device status is null. It will be ignored.", sessionUUID)); + LOGGER.warning(() -> String.format("[STF-%s] STF device status is null. It will be ignored: %s minutes.", sessionUUID, + INVALID_STF_RESPONSE_TIMEOUT.toMinutes())); + STF_DEVICE_IGNORE_AUTOMATION_TIMERS.put(deviceUDID, Duration.ofMillis(System.currentTimeMillis()).plus(INVALID_STF_RESPONSE_TIMEOUT)); return false; } if(stfDevice.getStatus().intValue() == 2) { - LOGGER.warning(() -> String.format("[STF-%s] STF device status 'UNAUTHORIZED'. It will be ignored: %s.", sessionUUID, - UNAUTHORIZED_TIMEOUT)); + LOGGER.warning(() -> String.format("[STF-%s] STF device status 'UNAUTHORIZED'. It will be ignored: %s minutes.", sessionUUID, + UNAUTHORIZED_TIMEOUT.toMinutes())); STF_DEVICE_IGNORE_AUTOMATION_TIMERS.put(deviceUDID, Duration.ofMillis(System.currentTimeMillis()).plus(UNAUTHORIZED_TIMEOUT)); return false; } if(stfDevice.getStatus() == 7) { - LOGGER.warning(() -> String.format("[STF-%s] STF device status 'UNHEALTHY'. It will be ignored: %s.", sessionUUID, UNHEALTHY_TIMEOUT)); + LOGGER.warning(() -> String.format("[STF-%s] STF device status 'UNHEALTHY'. It will be ignored: %s minutes.", sessionUUID, + UNHEALTHY_TIMEOUT.toMinutes())); STF_DEVICE_IGNORE_AUTOMATION_TIMERS.put(deviceUDID, Duration.ofMillis(System.currentTimeMillis()).plus(UNHEALTHY_TIMEOUT)); return false; } From e91375c5c61e8e43036b8d2c79d57e13e3b83de0 Mon Sep 17 00:00:00 2001 From: Andrei Kamarouski Date: Thu, 25 Jan 2024 12:36:35 +0100 Subject: [PATCH 6/9] feature(STFClient): add ignore timeouts to the ENV variables --- .../grid/integration/client/STFClient.java | 41 ++++++++++++------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java b/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java index 002b2e8..9d84c1d 100644 --- a/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java +++ b/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java @@ -43,9 +43,22 @@ public final class STFClient { // Max time is seconds for reserving devices in STF private static final String DEFAULT_STF_TIMEOUT = System.getenv("STF_TIMEOUT"); - private static final Duration INVALID_STF_RESPONSE_TIMEOUT = Duration.ofMinutes(10); - private static final Duration UNAUTHORIZED_TIMEOUT = Duration.ofMinutes(10); - private static final Duration UNHEALTHY_TIMEOUT = Duration.ofMinutes(5); + private static final Duration INVALID_STF_RESPONSE_TIMEOUT = Optional.ofNullable(System.getenv("STF_DEVICE_INVALID_RESPONSE_IGNORE_TIMEOUT")) + .filter(StringUtils::isNotBlank) + .map(Integer::parseInt) + .map(Duration::ofSeconds) + .orElse(Duration.ofMinutes(10)); + private static final Duration UNAUTHORIZED_TIMEOUT = Optional.ofNullable(System.getenv("STF_DEVICE_UNAUTHORIZED_IGNORE_TIMEOUT")) + .filter(StringUtils::isNotBlank) + .map(Integer::parseInt) + .map(Duration::ofSeconds) + .orElse(Duration.ofMinutes(10)); + + private static final Duration UNHEALTHY_TIMEOUT = Optional.ofNullable(System.getenv("STF_DEVICE_UNHEALTHY_IGNORE_TIMEOUT")) + .filter(StringUtils::isNotBlank) + .map(Integer::parseInt) + .map(Duration::ofSeconds) + .orElse(Duration.ofMinutes(5)); private Platform platform; private String token; @@ -92,7 +105,6 @@ public static boolean reserveSTFDevice(String deviceUDID, Map re } } - if (STF_CLIENTS.get(deviceUDID) != null) { LOGGER.warning(() -> String.format("Device '%s' already busy (in the local pool). Info: %s", deviceUDID, STF_CLIENTS.get(deviceUDID))); } @@ -141,21 +153,21 @@ public static boolean reserveSTFDevice(String deviceUDID, Map re stfClient.setDevice(stfDevice); - if(stfDevice.getStatus() == null) { + if (stfDevice.getStatus() == null) { LOGGER.warning(() -> String.format("[STF-%s] STF device status is null. It will be ignored: %s minutes.", sessionUUID, INVALID_STF_RESPONSE_TIMEOUT.toMinutes())); STF_DEVICE_IGNORE_AUTOMATION_TIMERS.put(deviceUDID, Duration.ofMillis(System.currentTimeMillis()).plus(INVALID_STF_RESPONSE_TIMEOUT)); return false; } - if(stfDevice.getStatus().intValue() == 2) { + if (stfDevice.getStatus().intValue() == 2) { LOGGER.warning(() -> String.format("[STF-%s] STF device status 'UNAUTHORIZED'. It will be ignored: %s minutes.", sessionUUID, UNAUTHORIZED_TIMEOUT.toMinutes())); - STF_DEVICE_IGNORE_AUTOMATION_TIMERS.put(deviceUDID, Duration.ofMillis(System.currentTimeMillis()).plus(UNAUTHORIZED_TIMEOUT)); - return false; + STF_DEVICE_IGNORE_AUTOMATION_TIMERS.put(deviceUDID, Duration.ofMillis(System.currentTimeMillis()).plus(UNAUTHORIZED_TIMEOUT)); + return false; } - if(stfDevice.getStatus() == 7) { + if (stfDevice.getStatus() == 7) { LOGGER.warning(() -> String.format("[STF-%s] STF device status 'UNHEALTHY'. It will be ignored: %s minutes.", sessionUUID, UNHEALTHY_TIMEOUT.toMinutes())); STF_DEVICE_IGNORE_AUTOMATION_TIMERS.put(deviceUDID, Duration.ofMillis(System.currentTimeMillis()).plus(UNHEALTHY_TIMEOUT)); @@ -179,14 +191,15 @@ public static boolean reserveSTFDevice(String deviceUDID, Map re if (response.getStatus() != 200) { LOGGER.warning(() -> String.format("[STF-%s] Could not reserve STF device with udid: %s. Status: %s. Response: %s", sessionUUID, deviceUDID, response.getStatus(), response.getObject())); - if(response.getStatus() == 0) { - LOGGER.warning(() -> String.format("[STF-%s] Device will be marked as unhealthy due to response status '0'.", sessionUUID)); + if (response.getStatus() == 0) { + LOGGER.warning(() -> String.format("[STF-%s] Device will be marked as unhealthy due to response status '0'.", sessionUUID)); entity.put("body", Map.of("status", "Unhealthy")); - HttpClient.Response r = HttpClient.uri(Path.STF_DEVICES_ITEM_PATH, STF_URL, deviceUDID) + HttpClient.Response r = HttpClient.uri(Path.STF_DEVICES_ITEM_PATH, STF_URL, deviceUDID) .withAuthorization(buildAuthToken(stfToken)) .put(Void.class, entity); - if(r.getStatus() != 200) { - LOGGER.warning(() -> String.format("[STF-%s] Could not mark device as unhealthy. Status: %s. Response: %s", sessionUUID, r.getStatus(), r.getObject())); + if (r.getStatus() != 200) { + LOGGER.warning(() -> String.format("[STF-%s] Could not mark device as unhealthy. Status: %s. Response: %s", sessionUUID, + r.getStatus(), r.getObject())); } } return false; From 7f995ebcfd87301826a6fd5e8d1f10965635e585 Mon Sep 17 00:00:00 2001 From: Andrei Kamarouski Date: Thu, 25 Jan 2024 13:08:22 +0100 Subject: [PATCH 7/9] refactor(STFClient): change minutes to seconds in logs --- .../grid/integration/client/STFClient.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java b/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java index 9d84c1d..99bc3f5 100644 --- a/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java +++ b/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java @@ -95,10 +95,10 @@ public static boolean reserveSTFDevice(String deviceUDID, Map re if (STF_DEVICE_IGNORE_AUTOMATION_TIMERS.get(deviceUDID) != null) { Duration timeout = STF_DEVICE_IGNORE_AUTOMATION_TIMERS.get(deviceUDID); if (Duration.ofMillis(System.currentTimeMillis()).compareTo(timeout) < 0) { - LOGGER.warning(() -> String.format("[STF-%s] The next attempt to reserve '%s' STF device will be given only after '%s' minutes.", + LOGGER.warning(() -> String.format("[STF-%s] The next attempt to reserve '%s' STF device will be given only after '%s' seconds.", sessionUUID, deviceUDID, - timeout.minus(Duration.ofMillis(System.currentTimeMillis())).toMinutes())); + timeout.minus(Duration.ofMillis(System.currentTimeMillis())).toSeconds())); return false; } else { STF_DEVICE_IGNORE_AUTOMATION_TIMERS.remove(deviceUDID); @@ -154,22 +154,22 @@ public static boolean reserveSTFDevice(String deviceUDID, Map re stfClient.setDevice(stfDevice); if (stfDevice.getStatus() == null) { - LOGGER.warning(() -> String.format("[STF-%s] STF device status is null. It will be ignored: %s minutes.", sessionUUID, - INVALID_STF_RESPONSE_TIMEOUT.toMinutes())); + LOGGER.warning(() -> String.format("[STF-%s] STF device status is null. It will be ignored: %s seconds.", sessionUUID, + INVALID_STF_RESPONSE_TIMEOUT.toSeconds())); STF_DEVICE_IGNORE_AUTOMATION_TIMERS.put(deviceUDID, Duration.ofMillis(System.currentTimeMillis()).plus(INVALID_STF_RESPONSE_TIMEOUT)); return false; } if (stfDevice.getStatus().intValue() == 2) { - LOGGER.warning(() -> String.format("[STF-%s] STF device status 'UNAUTHORIZED'. It will be ignored: %s minutes.", sessionUUID, - UNAUTHORIZED_TIMEOUT.toMinutes())); + LOGGER.warning(() -> String.format("[STF-%s] STF device status 'UNAUTHORIZED'. It will be ignored: %s seconds.", sessionUUID, + UNAUTHORIZED_TIMEOUT.toSeconds())); STF_DEVICE_IGNORE_AUTOMATION_TIMERS.put(deviceUDID, Duration.ofMillis(System.currentTimeMillis()).plus(UNAUTHORIZED_TIMEOUT)); return false; } if (stfDevice.getStatus() == 7) { - LOGGER.warning(() -> String.format("[STF-%s] STF device status 'UNHEALTHY'. It will be ignored: %s minutes.", sessionUUID, - UNHEALTHY_TIMEOUT.toMinutes())); + LOGGER.warning(() -> String.format("[STF-%s] STF device status 'UNHEALTHY'. It will be ignored: %s seconds.", sessionUUID, + UNHEALTHY_TIMEOUT.toSeconds())); STF_DEVICE_IGNORE_AUTOMATION_TIMERS.put(deviceUDID, Duration.ofMillis(System.currentTimeMillis()).plus(UNHEALTHY_TIMEOUT)); return false; } From a72047270c2e9acfed35ccaf13015ae44e8f1548 Mon Sep 17 00:00:00 2001 From: Andrei Kamarouski Date: Thu, 25 Jan 2024 13:38:35 +0100 Subject: [PATCH 8/9] refactor(MobileRemoteProxy): modify 'Node is down' logs --- .../com/zebrunner/mcloud/grid/MobileRemoteProxy.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/zebrunner/mcloud/grid/MobileRemoteProxy.java b/src/main/java/com/zebrunner/mcloud/grid/MobileRemoteProxy.java index d6d7007..d6f8408 100644 --- a/src/main/java/com/zebrunner/mcloud/grid/MobileRemoteProxy.java +++ b/src/main/java/com/zebrunner/mcloud/grid/MobileRemoteProxy.java @@ -73,7 +73,9 @@ public TestSession getNewSession(Map requestedCapability) { getTestSlots().stream() .findAny() .ifPresent((slot -> { - LOGGER.info(() -> String.format("Node is down: '%s:%s' - '%s (%s)'", + LOGGER.info(() -> String.format("Node is down: '[%s]-'%s:%s' (%s)'", + CapabilityUtils.getAppiumCapability(slot.getCapabilities(), "deviceName") + .orElse(StringUtils.EMPTY), Optional.of(slot) .map(TestSlot::getProxy) .map(RemoteProxy::getRemoteHost) @@ -85,8 +87,9 @@ public TestSession getNewSession(Map requestedCapability) { .map(URL::getPort) .map(String::valueOf) .orElse(StringUtils.EMPTY), - CapabilityUtils.getAppiumCapability(slot.getCapabilities(), "udid"), - CapabilityUtils.getAppiumCapability(slot.getCapabilities(), "deviceName")) + CapabilityUtils.getAppiumCapability(slot.getCapabilities(), "udid") + .orElse(StringUtils.EMPTY) + ) ); })); return null; From aa5695f851aab9e811b01313ef80f4f82ac6ccae Mon Sep 17 00:00:00 2001 From: Andrei Kamarouski Date: Thu, 25 Jan 2024 15:35:27 +0100 Subject: [PATCH 9/9] feature: check is there device with udid in STF --- .../mcloud/grid/MobileRemoteProxy.java | 15 +++++++++++++++ .../grid/integration/client/STFClient.java | 19 ++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/zebrunner/mcloud/grid/MobileRemoteProxy.java b/src/main/java/com/zebrunner/mcloud/grid/MobileRemoteProxy.java index d6f8408..4864c62 100644 --- a/src/main/java/com/zebrunner/mcloud/grid/MobileRemoteProxy.java +++ b/src/main/java/com/zebrunner/mcloud/grid/MobileRemoteProxy.java @@ -29,6 +29,7 @@ import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.openqa.grid.common.RegistrationRequest; +import org.openqa.grid.common.exception.GridException; import org.openqa.grid.internal.GridRegistry; import org.openqa.grid.internal.RemoteProxy; import org.openqa.grid.internal.TestSession; @@ -57,6 +58,20 @@ public class MobileRemoteProxy extends DefaultRemoteProxy { public MobileRemoteProxy(RegistrationRequest request, GridRegistry registry) { super(request, registry); + getTestSlots().stream() + .findAny() + .ifPresent(slot -> { + String udid = String.valueOf(CapabilityUtils.getAppiumCapability(slot.getCapabilities(), "udid") + .orElse("")); + if (StringUtils.isBlank(udid)) { + throw new GridException(String.format("Appium node must have 'UDID' capability. Slot capabilities: %s", + slot.getCapabilities())); + } + if (!STFClient.isDevicePresentInSTF(udid)) { + throw new GridException(String.format("Could not find device with udid '%s' in STF. Slot capabilities: %s", + udid, slot.getCapabilities())); + } + }); } @Override diff --git a/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java b/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java index 99bc3f5..23212ba 100644 --- a/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java +++ b/src/main/java/com/zebrunner/mcloud/grid/integration/client/STFClient.java @@ -87,10 +87,10 @@ public static STFDevice getSTFDevice(String udid) { * Reserve STF device */ public static boolean reserveSTFDevice(String deviceUDID, Map requestedCapabilities, String sessionUUID) { - LOGGER.info(() -> String.format("[STF-%s] Reserve STF Device.", sessionUUID)); if (!isSTFEnabled()) { return true; } + LOGGER.info(() -> String.format("[STF-%s] Reserve STF Device.", sessionUUID)); if (STF_DEVICE_IGNORE_AUTOMATION_TIMERS.get(deviceUDID) != null) { Duration timeout = STF_DEVICE_IGNORE_AUTOMATION_TIMERS.get(deviceUDID); @@ -376,6 +376,23 @@ private static boolean isSTFEnabled() { return (!StringUtils.isEmpty(STF_URL) && !StringUtils.isEmpty(DEFAULT_STF_TOKEN)); } + public static boolean isDevicePresentInSTF(String udid) { + if (!isSTFEnabled()) { + return true; + } + HttpClient.Response devices = HttpClient.uri(Path.STF_DEVICES_PATH, STF_URL) + .withAuthorization(buildAuthToken(DEFAULT_STF_TOKEN)) + .get(Devices.class); + if (devices.getStatus() != 200) { + LOGGER.warning(() -> String.format("[NODE REGISTRATION] Unable to get devices status. HTTP status: %s", devices.getStatus())); + return false; + } + return devices.getObject() + .getDevices() + .stream() + .anyMatch(device -> StringUtils.equals(device.getSerial(), udid)); + } + @Override public String toString() { return "STFClient{" + "platform=" + platform +