All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sdl.selenium.web.utils.Retry Maven / Gradle / Ivy

Go to download

Automated Acceptance Testing. Selenium and Selenium WebDriver test framework for web applications. (optimized for dynamic html, ExtJS, Bootstrap, complex UI, simple web applications/sites)

The newest version!
package com.sdl.selenium.web.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Strings;
import org.slf4j.Logger;

import java.time.Duration;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Callable;

public class Retry {

    private static final Logger log = org.slf4j.LoggerFactory.getLogger(Retry.class);

    public static  V retry(int maxRetries, Callable call) {
        return retry(maxRetries, null, call, false);
    }

    /**
     * @param duration example 20 seconds
     * @param call     button.click()
     * @param       type of method
     * @return true or false, throw RuntimeException()
     * 
{@code
     * RetryUtils.retry(Duration.ofSeconds(10), ()-> button.click());
     * }
*/ public static V retry(Duration duration, Callable call) { return retry(duration, null, call, false); } public static V retry(int maxRetries, String prefixLog, Callable call) { return retry(maxRetries, prefixLog, call, false); } /** * @param duration example 20 seconds * @param prefixLog class name * @param call button.click() * @param type of method * @return true or false, throw RuntimeException() *
{@code
     * RetryUtils.retry(Duration.ofSeconds(10), "LoginButton", ()-> button.click());
     * }
*/ public static V retry(Duration duration, String prefixLog, Callable call) { return retry(duration, prefixLog, call, false); } public static boolean retryRunnable(int maxRetries, Runnable r) { return retryRunnable(maxRetries, null, r, false); } public static boolean retryRunnable(int maxRetries, String prefixLog, Runnable r) { return retryRunnable(maxRetries, prefixLog, r, false); } public static boolean retryRunnableSafe(int maxRetries, Runnable r) { return retryRunnable(maxRetries, null, r, true); } public static boolean retryRunnableSafe(int maxRetries, String prefixLog, Runnable r) { return retryRunnable(maxRetries, prefixLog, r, true); } private static boolean retryRunnable(int maxRetries, String prefixLog, Runnable r, boolean safe) { int count = 0; int wait = 0; Fib fib = new Fib(); long startMs = System.currentTimeMillis(); do { count++; // wait = wait == 0 ? 5 : count < 9 ? wait * 2 : wait; wait = count < 9 ? fibonacci(wait, fib).getResult() : wait; Utils.sleep(wait); try { r.run(); return true; } catch (Exception | AssertionError e) { if (safe) { return false; } else { if (count >= maxRetries) { long duringMs = getDuringMillis(startMs); log.error((Strings.isNullOrEmpty(prefixLog) ? "" : prefixLog + ":") + "Retry {} and wait {} milliseconds ->{}", count, duringMs, e); throw new RuntimeException(e.getMessage(), e); } } } } while (count < maxRetries); if (count > 1) { long duringMs = getDuringMillis(startMs); log.info((Strings.isNullOrEmpty(prefixLog) ? "" : prefixLog + ":") + "Retry {} and wait {} milliseconds", count, duringMs); } return true; } private static V retry(int maxRetries, String prefixLog, Callable call, boolean safe) { int count = 0; int wait = 0; Fib fib = new Fib(); long startMs = System.currentTimeMillis(); V execute = null; do { count++; // wait = wait == 0 ? 5 : count < 9 ? wait * 2 : wait; wait = count < 9 ? fibonacci(wait, fib).getResult() : wait; Utils.sleep(wait); // log.info("Retry {} and wait {} ->!!!", count, wait); try { execute = call.call(); } catch (Exception | AssertionError e) { if (!safe) { if (count >= maxRetries) { long duringMs = getDuringMillis(startMs); log.error((Strings.isNullOrEmpty(prefixLog) ? "" : prefixLog + ":") + "Retry {} and wait {} milliseconds ->{}", count, duringMs, e); throw new RuntimeException(e.getMessage(), e); } } } } while ((execute == null || isNotExpected(execute)) && count < maxRetries); if (count > 1) { long duringMs = getDuringMillis(startMs); log.info((Strings.isNullOrEmpty(prefixLog) ? "" : prefixLog + ":") + "Retry {} and wait {} milliseconds", count, duringMs); } return execute; } @SafeVarargs public static Result retryUntilOneIs(int maxRetries, Callable... calls) { return retryUntilOneIs(maxRetries, null, calls); } @SafeVarargs public static Result retryUntilOneIsDetails(int maxRetries, Call... calls) { return retryUntilOneIsDetails(maxRetries, null, calls); } @SafeVarargs public static Result retryUntilOneIs(int maxRetries, String prefixLog, Callable... calls) { int count = 0; int wait = 0; Fib fib = new Fib(); long startMs = System.currentTimeMillis(); V execute = null; boolean notExpected = true; int position = 0; StringBuilder field = new StringBuilder(); do { count++; field.append("\n|").append(count).append(">"); wait = count < 9 ? fibonacci(wait, fib).getResult() : wait; Utils.sleep(wait); int iteration = 0; try { for (Callable call : calls) { iteration++; long startMsCall = System.currentTimeMillis(); execute = call.call(); notExpected = isNotExpected(execute); if (!notExpected) { position = iteration; long millis = getDuringMillis(startMsCall); field.append(position).append(":").append(millis); break; } long millis = getDuringMillis(startMsCall); field.append(iteration).append(":").append(millis).append(","); } } catch (Exception | AssertionError e) { if (count >= maxRetries) { long duringMs = getDuringMillis(startMs); log.error((Strings.isNullOrEmpty(prefixLog) ? "" : prefixLog + ":") + "Retry {} and wait {} milliseconds ->{}", count, duringMs, e); throw new RuntimeException(e.getMessage(), e); } } } while ((execute == null || notExpected) && count < maxRetries); if (count > 1) { long duringMs = getDuringMillis(startMs); log.info((Strings.isNullOrEmpty(prefixLog) ? "" : prefixLog + ":") + "Retry {} and wait {} milliseconds", count, duringMs); } return new Result<>(execute, position, count == maxRetries, field.toString()); } @SafeVarargs public static Result retryUntilOneIsDetails(int maxRetries, String prefixLog, Call... calls) { int count = 0; int wait = 0; Fib fib = new Fib(); long startMs = System.currentTimeMillis(); V execute = null; boolean notExpected = true; int position = 0; StringBuilder field = new StringBuilder(); do { count++; field.append("\n|").append(count).append(">"); wait = count < 9 ? fibonacci(wait, fib).getResult() : wait; Utils.sleep(wait); int iteration = 0; try { for (Call call : calls) { iteration++; long startMsCall = System.currentTimeMillis(); execute = call.callable().call(); notExpected = isNotExpected(execute); if (!notExpected) { position = iteration; long millis = getDuringMillis(startMsCall); field.append(call.name()).append(":").append(millis); break; } long millis = getDuringMillis(startMsCall); field.append(call.name()).append(":").append(millis).append(","); } } catch (Exception | AssertionError e) { if (count >= maxRetries) { long duringMs = getDuringMillis(startMs); log.error((Strings.isNullOrEmpty(prefixLog) ? "" : prefixLog + ":") + "Retry {} and wait {} milliseconds ->{}", count, duringMs, e); throw new RuntimeException(e.getMessage(), e); } } } while ((execute == null || notExpected) && count < maxRetries); if (count > 1) { long duringMs = getDuringMillis(startMs); log.info((Strings.isNullOrEmpty(prefixLog) ? "" : prefixLog + ":") + "Retry {} and wait {} milliseconds", count, duringMs); } return new Result<>(execute, position, count == maxRetries, field.toString()); } @SafeVarargs public static Result retryUntilOneIs(Duration duration, Callable... calls) { return retryUntilOneIs(duration, null, calls); } @SafeVarargs public static Result retryUntilOneIs(Duration duration, String prefixLog, Callable... calls) { int count = 0; int wait = 0; int limit = getLimit(duration); Fib fib = new Fib(limit); long startMillis = System.currentTimeMillis(); long startMs = System.currentTimeMillis(); V execute = null; boolean notExpected = true; int position = 0; StringBuilder field = new StringBuilder(); do { count++; field.append("\n|").append(count).append(">"); wait = fibonacciSinusoidal(wait, fib).getResult(); Utils.sleep(wait); int iteration = 0; try { for (Callable call : calls) { iteration++; long startMsCall = System.currentTimeMillis(); execute = call.call(); notExpected = isNotExpected(execute); if (!notExpected) { position = iteration; long millis = getDuringMillis(startMsCall); field.append(position).append(":").append(millis); break; } long millis = getDuringMillis(startMsCall); field.append(iteration).append(":").append(millis).append(","); } } catch (Exception | AssertionError e) { if (timeIsOver(startMillis, duration)) { long duringMs = getDuringMillis(startMs); log.error((Strings.isNullOrEmpty(prefixLog) ? "" : prefixLog + ":") + "Retry {} and wait {} milliseconds ->{}", count, duringMs, e); throw new RuntimeException(e.getMessage(), e); } } } while ((execute == null || notExpected) && !timeIsOver(startMillis, duration)); if (count > 1) { long duringMs = getDuringMillis(startMs); log.info((Strings.isNullOrEmpty(prefixLog) ? "" : prefixLog + ":") + "Retry {} and wait {} milliseconds", count, duringMs); } return new Result<>(execute, position, timeIsOver(startMillis, duration), field.toString()); } @SafeVarargs public static Result retryUntilOneIsDetails(Duration duration, Call... calls) { return retryUntilOneIsDetails(duration, null, calls); } @SafeVarargs public static Result retryUntilOneIsDetails(Duration duration, String prefixLog, Call... calls) { int count = 0; int wait = 0; int limit = getLimit(duration); Fib fib = new Fib(limit); long startMillis = System.currentTimeMillis(); long startMs = System.currentTimeMillis(); V execute = null; boolean notExpected = true; int position = 0; StringBuilder field = new StringBuilder(); do { count++; field.append("\n|").append(count).append(">"); wait = fibonacciSinusoidal(wait, fib).getResult(); Utils.sleep(wait); int iteration = 0; try { for (Call call : calls) { iteration++; long startMsCall = System.currentTimeMillis(); execute = call.callable().call(); notExpected = isNotExpected(execute); if (!notExpected) { position = iteration; long millis = getDuringMillis(startMsCall); field.append(call.name()).append(":").append(millis); break; } long millis = getDuringMillis(startMsCall); field.append(call.name()).append(":").append(millis).append(","); } } catch (Exception | AssertionError e) { if (timeIsOver(startMillis, duration)) { long duringMs = getDuringMillis(startMs); log.error((Strings.isNullOrEmpty(prefixLog) ? "" : prefixLog + ":") + "Retry {} and wait {} milliseconds ->{}", count, duringMs, e); throw new RuntimeException(e.getMessage(), e); } } } while ((execute == null || notExpected) && !timeIsOver(startMillis, duration)); if (count > 1) { long duringMs = getDuringMillis(startMs); log.info((Strings.isNullOrEmpty(prefixLog) ? "" : prefixLog + ":") + "Retry {} and wait {} milliseconds", count, duringMs); } return new Result<>(execute, position, timeIsOver(startMillis, duration), field.toString()); } private static V retry(Duration duration, String prefixLog, Callable call, boolean safe) { int count = 0; int wait = 0; int limit = getLimit(duration); Fib fib = new Fib(limit); long startMillis = System.currentTimeMillis(); V execute = null; do { count++; wait = fibonacciSinusoidal(wait, fib).getResult(); Utils.sleep(wait * 1000L); try { execute = call.call(); } catch (Exception | AssertionError e) { if (!safe) { if (timeIsOver(startMillis, duration)) { long duringMillis = getDuringMillis(startMillis); log.error((Strings.isNullOrEmpty(prefixLog) ? "" : prefixLog + ":") + "Retry {} and wait {} milliseconds ->{}", count, duringMillis, e); throw new RuntimeException(e.getMessage(), e); } } } } while ((execute == null || isNotExpected(execute)) && !timeIsOver(startMillis, duration)); if (count > 1) { long duringMillis = getDuringMillis(startMillis); log.info((Strings.isNullOrEmpty(prefixLog) ? "" : prefixLog + ":") + "Retry {} and wait {} milliseconds", count, duringMillis); } return execute; } private static int getLimit(Duration duration) { List fibonacciNumbers = List.of(1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610); int limit = (int) (duration.getSeconds() / 8); int lastFibonacci = 0; for (int fibonacci : fibonacciNumbers) { if (fibonacci > limit) { return lastFibonacci; } else if (fibonacci == limit) { return fibonacci; } else { lastFibonacci = fibonacci; } } return limit; } private static boolean timeIsOver(long startMillis, Duration duration) { long duringMillis = getDuringMillis(startMillis); long toMillis = duration.toMillis(); return toMillis <= duringMillis; } private static long getDuringMillis(long startMillis) { long endMillis = System.currentTimeMillis(); return endMillis - startMillis; } @Deprecated public static V retryWithSuccess(int maxRetries, Callable call) { return retry(maxRetries, call); } public static V retrySafe(int maxRetries, Callable call) { return retry(maxRetries, null, call, true); } public static V retrySafe(Duration duration, Callable call) { return retry(duration, null, call, true); } public static V retrySafe(int maxRetries, String prefixLog, Callable call) { return retry(maxRetries, prefixLog, call, true); } public static V retrySafe(Duration duration, String prefixLog, Callable call) { return retry(duration, prefixLog, call, true); } private static boolean isNotExpected(V execute) { if (execute instanceof Boolean) { return !(Boolean) execute; } else if (execute instanceof String) { return Strings.isNullOrEmpty((String) execute); } else if (execute instanceof List list) { return list.isEmpty() || list.stream().allMatch(Objects::isNull); } return execute == null; } /** * @param duration Duration.ofSeconds(2) * @param expected accept only:
{@code Integer, String, Boolean, List and List> }
* @param call getCount(); * @param expected Type * @return expected value */ public static V retryIfNotSame(Duration duration, V expected, Callable call) { V result = retry(duration, () -> doRetryIfNotSame(expected, call)); return result == null ? retry(0, call) : result; } private static V doRetryIfNotSame(V expected, Callable call) throws Exception { V currentResult = call.call(); if (currentResult instanceof Integer && expected instanceof Integer) { return expected == currentResult ? currentResult : null; } else if (currentResult instanceof List currentList && expected instanceof List expectedList) { if (currentList.isEmpty()) { return currentResult; } else if (currentList.get(0) instanceof List && expectedList.get(0) instanceof List) { return compareListOfList((List>) expected, currentResult); } else if (currentList.get(0) instanceof String && expectedList.get(0) instanceof String) { boolean allMatch = currentList.size() == expectedList.size() && currentList.containsAll(expectedList); return allMatch ? currentResult : null; } else { return compareListOfObject(currentResult, currentList, expectedList); } } else if (currentResult instanceof String && expected instanceof String) { return expected.equals(currentResult) ? currentResult : null; } else if (currentResult instanceof Boolean && expected instanceof Boolean) { Boolean bolActual = (Boolean) currentResult; Boolean bolExpected = (Boolean) expected; return bolExpected.equals(bolActual) ? currentResult : null; } else { log.error("Expected and actual objects aren't the some type!"); return null; } } private static V compareListOfList(List> expectedListOfList, V currentResult) { List> currentListOfList = (List>) currentResult; Boolean compare = null; int expectedSize = expectedListOfList.size(); for (List expectedTmp : expectedListOfList) { int currentFind = 0; Boolean match = null; for (List currentTmp : currentListOfList) { boolean matchTmp = expectedTmp.containsAll(currentTmp); if (matchTmp) { currentFind++; match = true; } if (expectedSize == currentFind) { break; } } compare = compare == null ? Boolean.TRUE.equals(match) : compare && Boolean.TRUE.equals(match); } return Boolean.TRUE.equals(compare) ? currentResult : null; } private static V compareListOfObject(V currentResult, List currentList, List expectedList) throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); mapper.configure(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES, true); boolean allMatch = true; for (Object o : expectedList) { String expectedJson = mapper.writeValueAsString(o); boolean found = false; for (Object currentObject : currentList) { String currentJson = mapper.writeValueAsString(currentObject); if (expectedJson.equals(currentJson)) { found = true; break; } } allMatch = allMatch && found; } if (!allMatch) { Utils.sleep(1); } return allMatch ? currentResult : null; } /** * @param maxRetries e.g 3 * @param expected accept only:
{@code Integer, String, Boolean, List and List> }
* @param call getCount(); * @param expected Type * @return expected value */ public static V retryIfNotSame(int maxRetries, V expected, Callable call) { V result = retry(maxRetries, () -> doRetryIfNotSame(expected, call)); return result == null ? retry(0, call) : result; } public static V retryIfNotContains(Duration duration, String expected, Callable call) { V result = retry(duration, () -> { V text = call.call(); return text instanceof String && ((String) text).contains(expected) ? text : null; }); return result == null ? retry(0, call) : result; } public static V retryIfNotContains(int maxRetries, String expected, Callable call) { V result = retry(maxRetries, () -> { V text = call.call(); return text instanceof String && ((String) text).contains(expected) ? text : null; }); return result == null ? retry(0, call) : result; } private static Fib fibonacci(int time, Fib fib) { int sum = time + fib.getLast(); fib.setLast(fib.getStart()); fib.setStart(sum); fib.setResult(sum); // log.info((Strings.isNullOrEmpty(prefixLog) ? "" : prefixLog + ":") + "time is {}", sum); return fib; } private static Fib fibonacciSinusoidal(int time, Fib fib) { int startTMP = fib.getStart(); int sum = 0; if (fib.isPositive() && time >= fib.getLimit()) { // log.info("if1"); sum = fib.getLast(); fib.setStart(fib.getStart() - fib.getLast()); fib.setLast(sum); fib.setPositive(false); if (fib.getLimit() > 2) { fib.setLimit(fib.getLimit() - fib.getStart()); } } else if (!fib.isPositive() && time <= fib.getLimit()) { // log.info("if2"); sum = fib.getStart(); fib.setStart(fib.getLast() == fib.getStart() ? 1 : fib.getLast() - fib.getStart()); fib.setLast(sum); if (startTMP == fib.getStart()) { fib.setPositive(true); fib.setStart(fib.getStart() + 1); fib.setLast(fib.getStart()); fib.setExtra(true); } } else if (fib.isPositive() && time >= 0) { // log.info("if3"); sum = time + fib.getLast(); if (fib.isExtra()) { sum = sum - 1; fib.setLast(fib.getStart() - 1); fib.setExtra(false); } else { fib.setLast(fib.getStart() == 0 ? 1 : fib.getStart()); } fib.setStart(sum); } else { log.info("This value is not covered!"); Utils.sleep(1); } fib.setResult(sum); // log.info("Fib is: {}", fib); return fib; } public static void main(String[] args) { int limit = Retry.getLimit(Duration.ofSeconds(200)); Utils.sleep(1); // int t = 0; // for (int i = 0; i < 10; i++) { //// t = RetryUtils.fibonacciSinusoidal(t, new Fib()).getResult(); //// log.info("time is {}", t); // Utils.sleep(t); // } } private static class Fib { private int start = 0; private int last = 1; private int result; private int limit = 60; private boolean positive = true; private boolean extra = false; public Fib() { } public Fib(int limit) { this.limit = limit; } public void setStart(int start) { this.start = start; } public int getStart() { return start; } public void setLast(int last) { this.last = last; } public int getLast() { return last; } public void setResult(int result) { this.result = result; } public int getResult() { return result; } public int getLimit() { return limit; } public void setLimit(int limit) { this.limit = limit; } public boolean isPositive() { return positive; } public void setPositive(boolean positive) { this.positive = positive; } public boolean isExtra() { return extra; } public void setExtra(boolean extra) { this.extra = extra; } @Override public String toString() { return "Fib{" + "start=" + start + ", last=" + last + ", result=" + result + ", limit=" + limit + ", positive=" + positive + ", extra=" + extra + '}'; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy