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

com.applitools.eyes.MatchWindowTask Maven / Gradle / Ivy

The newest version!
package com.applitools.eyes;

import com.applitools.connectivity.ServerConnector;
import com.applitools.eyes.capture.AppOutputProvider;
import com.applitools.eyes.config.Configuration;
import com.applitools.eyes.fluent.*;
import com.applitools.eyes.logging.Stage;
import com.applitools.eyes.logging.TraceLevel;
import com.applitools.eyes.positioning.PositionMemento;
import com.applitools.eyes.positioning.PositionProvider;
import com.applitools.eyes.visualgrid.model.IGetFloatingRegionOffsets;
import com.applitools.eyes.visualgrid.model.MutableRegion;
import com.applitools.eyes.visualgrid.model.VisualGridSelector;
import com.applitools.utils.ArgumentGuard;
import com.applitools.utils.GeneralUtils;
import org.apache.commons.lang3.tuple.Pair;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class MatchWindowTask {

    private static final int MATCH_INTERVAL = 500; // Milliseconds
    private EyesScreenshot lastScreenshot = null;
    private String lastScreenshotHash;
    private final int defaultRetryTimeout;

    protected Logger logger;
    protected ServerConnector serverConnector;
    protected RunningSession runningSession;
    protected AppOutputProvider appOutputProvider;
    protected MatchResult matchResult;
    protected EyesBase eyes;

    /**
     * @param logger            A logger instance.
     * @param serverConnector   Our gateway to the agent
     * @param runningSession    The running session in which we should match the window
     * @param retryTimeout      The default total time to retry matching (ms).
     * @param eyes              An EyesBase object.
     * @param appOutputProvider A callback for getting the application output when performing match.
     */
    public MatchWindowTask(Logger logger, ServerConnector serverConnector,
                           RunningSession runningSession, int retryTimeout,
                           EyesBase eyes, AppOutputProvider appOutputProvider) {
        ArgumentGuard.notNull(serverConnector, "serverConnector");
        ArgumentGuard.notNull(runningSession, "runningSession");
        ArgumentGuard.greaterThanOrEqualToZero(retryTimeout, "retryTimeout");
        ArgumentGuard.notNull(appOutputProvider, "appOutputProvider");

        this.logger = logger;
        this.serverConnector = serverConnector;
        this.runningSession = runningSession;
        this.defaultRetryTimeout = retryTimeout;
        this.eyes = eyes;
        this.appOutputProvider = appOutputProvider;
    }

    public static void collectRegions(ImageMatchSettings imageMatchSettings, ICheckSettingsInternal checkSettingsInternal) {
        imageMatchSettings.setIgnoreRegions(convertSimpleRegions(checkSettingsInternal.getIgnoreRegions(), imageMatchSettings.getIgnoreRegions()));
        imageMatchSettings.setContentRegions(convertSimpleRegions(checkSettingsInternal.getContentRegions(), imageMatchSettings.getContentRegions()));
        imageMatchSettings.setLayoutRegions(convertSimpleRegions(checkSettingsInternal.getLayoutRegions(), imageMatchSettings.getLayoutRegions()));
        imageMatchSettings.setStrictRegions(convertSimpleRegions(checkSettingsInternal.getStrictRegions(), imageMatchSettings.getStrictRegions()));
        imageMatchSettings.setFloatingRegions(convertFloatingRegions(checkSettingsInternal.getFloatingRegions(), imageMatchSettings.getFloatingRegions()));
        imageMatchSettings.setAccessibility(convertAccessibilityRegions(checkSettingsInternal.getAccessibilityRegions(), imageMatchSettings.getAccessibility()));
    }

    private static AccessibilityRegionByRectangle[] convertAccessibilityRegions(GetAccessibilityRegion[] accessibilityRegions, AccessibilityRegionByRectangle[] currentRegions) {
        List mutableRegions = new ArrayList<>();
        if (currentRegions != null) {
            mutableRegions.addAll(Arrays.asList(currentRegions));
        }

        for (GetAccessibilityRegion getRegions : accessibilityRegions) {
            if (getRegions instanceof AccessibilityRegionByRectangle) {
                mutableRegions.addAll(getRegions.getRegions(null));
            }
        }

        return mutableRegions.toArray(new AccessibilityRegionByRectangle[0]);
    }

    private static Region[] convertSimpleRegions(GetSimpleRegion[] simpleRegions, Region[] currentRegions) {
        List mutableRegions = new ArrayList<>();
        if (currentRegions != null) {
            Collections.addAll(mutableRegions, currentRegions);
        }

        for (GetSimpleRegion simpleRegion : simpleRegions) {
            if (simpleRegion instanceof SimpleRegionByRectangle) {
                mutableRegions.addAll(simpleRegion.getRegions(null));
            }
        }

        return mutableRegions.toArray(new Region[0]);
    }

    private static FloatingMatchSettings[] convertFloatingRegions(GetFloatingRegion[] floatingRegions, FloatingMatchSettings[] currentRegions) {
        List mutableRegions = new ArrayList<>();
        if (currentRegions != null) {
            Collections.addAll(mutableRegions, currentRegions);
        }

        for (GetFloatingRegion getRegions : floatingRegions) {
            if (getRegions instanceof FloatingRegionByRectangle) {
                mutableRegions.addAll(getRegions.getRegions(null));
            }
        }

        return mutableRegions.toArray(new FloatingMatchSettings[0]);
    }

    public static void collectRegions(ImageMatchSettings imageMatchSettings, Location location, List regions, List regionSelectors) {
        if (regions == null) return;

        int currentCounter = 0;
        int currentTypeIndex = 0;
        int currentTypeRegionCount = regionSelectors.get(0).length;

        List> mutableRegions = new ArrayList<>();
        mutableRegions.add(new ArrayList()); // Ignore Regions
        mutableRegions.add(new ArrayList()); // Layout Regions
        mutableRegions.add(new ArrayList()); // Strict Regions
        mutableRegions.add(new ArrayList()); // Content Regions
        mutableRegions.add(new ArrayList()); // Floating Regions
        mutableRegions.add(new ArrayList()); // Accessibility Regions

        for (IRegion region : regions) {
            boolean canAddRegion = false;
            while (!canAddRegion) {
                currentCounter++;
                if (currentCounter > currentTypeRegionCount) {
                    currentTypeIndex++;
                    currentTypeRegionCount = regionSelectors.get(currentTypeIndex).length;
                    currentCounter = 0;
                } else {
                    canAddRegion = true;
                }
            }
            MutableRegion mr = new MutableRegion(region);
            mutableRegions.get(currentTypeIndex).add(mr);
        }

        imageMatchSettings.setIgnoreRegions(filterEmptyEntries(mutableRegions.get(0), location));
        imageMatchSettings.setLayoutRegions(filterEmptyEntries(mutableRegions.get(1), location));
        imageMatchSettings.setStrictRegions(filterEmptyEntries(mutableRegions.get(2), location));
        imageMatchSettings.setContentRegions(filterEmptyEntries(mutableRegions.get(3), location));

        List floatingMatchSettings = new ArrayList<>();
        for (int i = 0; i < regionSelectors.get(4).length; i++) {
            MutableRegion mr = mutableRegions.get(4).get(i);
            if (mr.getArea() == 0) continue;
            VisualGridSelector vgs = regionSelectors.get(4)[i];

            if (vgs.getCategory() instanceof IGetFloatingRegionOffsets) {
                IGetFloatingRegionOffsets gfr = (IGetFloatingRegionOffsets) vgs.getCategory();
                FloatingMatchSettings fms = new FloatingMatchSettings(
                        mr.getLeft(),
                        mr.getTop(),
                        mr.getWidth(),
                        mr.getHeight(),
                        gfr.getMaxUpOffset(),
                        gfr.getMaxDownOffset(),
                        gfr.getMaxLeftOffset(),
                        gfr.getMaxRightOffset()
                );
                floatingMatchSettings.add(fms);
            }
        }
        imageMatchSettings.setFloatingRegions(floatingMatchSettings.toArray(new FloatingMatchSettings[0]));

        List accessibilityRegions = new ArrayList<>();
        VisualGridSelector[] visualGridSelectors = regionSelectors.get(5);
        for (int i = 0; i < visualGridSelectors.length; i++) {
            MutableRegion mr = mutableRegions.get(5).get(i);
            if (mr.getArea() == 0) continue;
            VisualGridSelector vgs = visualGridSelectors[i];

            if (vgs.getCategory() instanceof IGetAccessibilityRegionType) {
                IGetAccessibilityRegionType gar = (IGetAccessibilityRegionType) vgs.getCategory();
                AccessibilityRegionByRectangle accessibilityRegion = new AccessibilityRegionByRectangle(
                        mr.getLeft() - location.getX(),
                        mr.getTop() - location.getY(),
                        mr.getWidth(),
                        mr.getHeight(),
                        gar.getAccessibilityRegionType());
                accessibilityRegions.add(accessibilityRegion);
            }
        }
        imageMatchSettings.setAccessibility(accessibilityRegions.toArray(new AccessibilityRegionByRectangle[0]));
    }

    private static MutableRegion[] filterEmptyEntries(List list, Location location) {
        for (int i = list.size() - 1; i >= 0; i--) {
            MutableRegion mutableRegion = list.get(i);
            if (mutableRegion.getArea() == 0) {
                list.remove(i);
            } else {
                mutableRegion.offset(-location.getX(), -location.getY());
                // TODO Quick fix, should be moved to a separete method outside.
                if (mutableRegion.getLeft() < 0) {
                   mutableRegion.setLeft(0);
                }
                if (mutableRegion.getTop() < 0) {
                    mutableRegion.setTop(0);
                }
            }
        }
        return list.toArray(new MutableRegion[0]);
    }

    private static void collectFloatingRegions(ICheckSettingsInternal checkSettingsInternal,
                                               ImageMatchSettings imageMatchSettings,
                                               EyesScreenshot screenshot) {
        List floatingRegions = new ArrayList<>();
        for (GetFloatingRegion floatingRegion : checkSettingsInternal.getFloatingRegions()) {
            List regions = floatingRegion.getRegions(screenshot);
            floatingRegions.addAll(regions);
        }
        imageMatchSettings.setFloatingRegions(floatingRegions.toArray(new FloatingMatchSettings[0]));

    }

    /**
     * Repeatedly obtains an application snapshot and matches it with the next
     * expected output, until a match is found or the timeout expires.
     * @param userInputs             User input preceding this match.
     * @param region                 Window region to capture.
     * @param tag                    Optional tag to be associated with the match (can be {@code null}).
     * @param shouldRunOnceOnTimeout Force a single match attempt at the end of the match timeout.
     * @param checkSettingsInternal  The settings to use.
     * @return Returns the results of the match
     */
    public MatchResult matchWindow(Trigger[] userInputs, Region region, String tag, boolean shouldRunOnceOnTimeout,
                                   ICheckSettingsInternal checkSettingsInternal, String source) {
        int retryTimeout = checkSettingsInternal.getTimeout();
        if (retryTimeout < 0) {
            retryTimeout = defaultRetryTimeout;
        }

        EyesScreenshot screenshot = takeScreenshot(userInputs, region, tag, shouldRunOnceOnTimeout,
                checkSettingsInternal, retryTimeout, source);

        updateLastScreenshot(screenshot);
        return matchResult;
    }

    private static void collectSimpleRegions(EyesBase eyes,
                                             ICheckSettingsInternal checkSettingsInternal,
                                             ImageMatchSettings imageMatchSettings,
                                             EyesScreenshot screenshot) {
        imageMatchSettings.setIgnoreRegions(collectSimpleRegions(eyes, checkSettingsInternal.getIgnoreRegions(), screenshot));
        imageMatchSettings.setLayoutRegions(collectSimpleRegions(eyes, checkSettingsInternal.getLayoutRegions(), screenshot));
        imageMatchSettings.setStrictRegions(collectSimpleRegions(eyes, checkSettingsInternal.getStrictRegions(), screenshot));
        imageMatchSettings.setContentRegions(collectSimpleRegions(eyes, checkSettingsInternal.getContentRegions(), screenshot));
    }

    private static Region[] collectSimpleRegions(EyesBase eyes, GetSimpleRegion[] regionProviders, EyesScreenshot screenshot) {

        List regions = new ArrayList<>();
        for (GetSimpleRegion regionProvider : regionProviders) {
            try {
                regions.addAll(regionProvider.getRegions(screenshot));
            } catch (OutOfBoundsException ex) {
                GeneralUtils.logExceptionStackTrace(eyes.getLogger(), Stage.CHECK, ex, eyes.getTestId());
            }
        }
        return regions.toArray(new Region[0]);
    }

    /**
     * Build match settings by merging the check settings and the default match settings.
     * @param checkSettingsInternal the settings to match the image by.
     * @param screenshot            the Screenshot wrapper object.
     * @return Merged match settings.
     */
    public static ImageMatchSettings createImageMatchSettings(ICheckSettingsInternal checkSettingsInternal, EyesScreenshot screenshot, EyesBase eyesBase) {
        eyesBase.getLogger().log(TraceLevel.Info, eyesBase.getTestId(), Stage.CHECK,
                Pair.of("configuration", eyesBase.getConfiguration()),
                Pair.of("checkSettings", checkSettingsInternal));
        ImageMatchSettings imageMatchSettings = createImageMatchSettings(checkSettingsInternal, eyesBase);

        if (imageMatchSettings != null) {
            PositionProvider positionProvider = checkSettingsInternal.getStepPositionProvider();
            PositionMemento originalState = null;
            if (positionProvider != null) {
                originalState = positionProvider.getState();
                positionProvider.setPosition(new Location(0, 0));
            }
            collectSimpleRegions(eyesBase, checkSettingsInternal, imageMatchSettings, screenshot);
            collectFloatingRegions(checkSettingsInternal, imageMatchSettings, screenshot);
            collectAccessibilityRegions(checkSettingsInternal, imageMatchSettings, screenshot);
            if (positionProvider != null && originalState != null) {
                positionProvider.restoreState(originalState);
            }
        }

        return imageMatchSettings;
    }

    /**
     * Build match settings by merging the check settings and the default match settings.
     * @param checkSettingsInternal the settings to match the image by.
     * @return Merged match settings.
     */
    public static ImageMatchSettings createImageMatchSettings(ICheckSettingsInternal checkSettingsInternal, EyesBase eyes) {
        ImageMatchSettings imageMatchSettings = null;
        if (checkSettingsInternal != null) {

            Configuration config = eyes.getConfigurationInstance();
            ImageMatchSettings defaultMatchSettings = config.getDefaultMatchSettings();

            imageMatchSettings = new ImageMatchSettings(defaultMatchSettings); // clone default match settings
            imageMatchSettings.setMatchLevel(checkSettingsInternal.getMatchLevel() != null ? checkSettingsInternal.getMatchLevel() : defaultMatchSettings.getMatchLevel());
            imageMatchSettings.setIgnoreCaret(checkSettingsInternal.getIgnoreCaret() != null ? checkSettingsInternal.getIgnoreCaret() : config.getIgnoreCaret());
            imageMatchSettings.setUseDom(checkSettingsInternal.isUseDom() != null ? checkSettingsInternal.isUseDom() : config.getUseDom());
            imageMatchSettings.setEnablePatterns(checkSettingsInternal.isEnablePatterns() != null ? checkSettingsInternal.isEnablePatterns() : config.getEnablePatterns());
            imageMatchSettings.setIgnoreDisplacements(checkSettingsInternal.isIgnoreDisplacements() != null ? checkSettingsInternal.isIgnoreDisplacements() : config.getIgnoreDisplacements());
            imageMatchSettings.setAccessibilitySettings(config.getAccessibilityValidation());
        }
        return imageMatchSettings;
    }

    private EyesScreenshot takeScreenshot(Trigger[] userInputs, Region region, String tag,
                                          boolean shouldMatchWindowRunOnceOnTimeout,
                                          ICheckSettingsInternal checkSettingsInternal,
                                          int retryTimeout, String source) {
        EyesScreenshot screenshot;
        lastScreenshotHash = null;

        // If the wait to load time is 0, or "run once" is true,
        // we perform a single check window.
        if (0 == retryTimeout || shouldMatchWindowRunOnceOnTimeout) {
            if (shouldMatchWindowRunOnceOnTimeout) {
                GeneralUtils.sleep(retryTimeout);
            }
            screenshot = tryTakeScreenshot(userInputs, region, tag, checkSettingsInternal, source);
        } else {
            screenshot = retryTakingScreenshot(userInputs, region, tag, checkSettingsInternal,
                    retryTimeout, source);
        }
        return screenshot;
    }

    private EyesScreenshot retryTakingScreenshot(Trigger[] userInputs, Region region, String tag,
                                                 ICheckSettingsInternal checkSettingsInternal, int retryTimeout, String source) {
        // Start the retry timer.
        long start = System.currentTimeMillis();

        EyesScreenshot screenshot = null;

        long retry = System.currentTimeMillis() - start;

        // The match retry loop.
        while (retry < retryTimeout) {

            // Wait before trying again.
            GeneralUtils.sleep(MATCH_INTERVAL);

            screenshot = tryTakeScreenshot(userInputs, region, tag, checkSettingsInternal, source);

            if (matchResult.getAsExpected()) {
                break;
            }

            retry = System.currentTimeMillis() - start;
        }

        // if we're here because we haven't found a match yet, try once more
        if (!matchResult.getAsExpected()) {
            screenshot = tryTakeScreenshot(userInputs, region, tag, checkSettingsInternal, source);
        }
        return screenshot;
    }

    private EyesScreenshot tryTakeScreenshot(Trigger[] userInputs, Region region, String tag,
                                             ICheckSettingsInternal checkSettingsInternal, String source) {
        AppOutput appOutput = appOutputProvider.getAppOutput(region, checkSettingsInternal);
        EyesScreenshot screenshot = appOutput.getScreenshot();
        String currentScreenshotHash = GeneralUtils.getSha256hash(appOutput.getScreenshotBytes());
        if (currentScreenshotHash.equals(lastScreenshotHash)) {
            return screenshot;
        }

        ImageMatchSettings matchSettings = createImageMatchSettings(checkSettingsInternal, screenshot, eyes);
        MatchWindowData data = eyes.prepareForMatch(checkSettingsInternal, Arrays.asList(userInputs), appOutput, tag, lastScreenshotHash != null,
                matchSettings, null, source);
        matchResult = eyes.performMatch(data);
        lastScreenshotHash = currentScreenshotHash;
        return screenshot;
    }

    private void updateLastScreenshot(EyesScreenshot screenshot) {
        if (screenshot != null) {
            lastScreenshot = screenshot;
        }
    }

    public EyesScreenshot getLastScreenshot() {
        return lastScreenshot;
    }

    private static void collectAccessibilityRegions(ICheckSettingsInternal checkSettingsInternal,
                                                    ImageMatchSettings imageMatchSettings,
                                                    EyesScreenshot screenshot) {
        List accessibilityRegions = new ArrayList<>();
        for (GetAccessibilityRegion regionProvider : checkSettingsInternal.getAccessibilityRegions()) {
            accessibilityRegions.addAll(regionProvider.getRegions(screenshot));
        }
        imageMatchSettings.setAccessibility(accessibilityRegions.toArray(new AccessibilityRegionByRectangle[0]));

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy