/* * Sakuli - Testing and Monitoring-Tool for Websites and common UIs. * * Copyright 2013 - 2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sakuli.actions.environment; import net.sf.sahi.util.OSUtils; import org.sakuli.actions.Action; import org.sakuli.actions.ModifySahiTimer; import org.sakuli.actions.environment.CommandLineUtil.CommandLineResult; import org.sakuli.actions.logging.LogToResult; import org.sakuli.actions.screenbased.Region; import org.sakuli.actions.screenbased.*; import org.sakuli.datamodel.properties.ActionProperties; import org.sakuli.exceptions.SakuliException; import org.sakuli.loader.BeanLoader; import org.sakuli.loader.ScreenActionLoader; import org.sikuli.script.*; import org.sikuli.script.Key; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.awt.event.KeyEvent; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; /** * This is a Singeton because the Function should be stateless * * @author Tobias Schneck */ public class Environment implements Action { protected final Logger logger = LoggerFactory.getLogger(this.getClass()); private final boolean resumeOnException; private ScreenActionLoader loader; private TypingUtil<Environment> typingUtil; /** * Creates a new Environment object, to control all non-region actions like typing or pasting. */ public Environment() { this(false); } /** * Creates a new Environment object, to control all non-region actions like typing or pasting. * * @param resumeOnException if true, the test execution won't stop on an occurring error. */ public Environment(boolean resumeOnException) { this.resumeOnException = resumeOnException; this.loader = BeanLoader.loadScreenActionLoader(); this.typingUtil = new TypingUtil<>(this); } /** * Runs the assigned command on the host and returns the result. __Attention:__ this is OS depended feature! So be * aware which os you are running, maybe us to check {@link Environment#isLinux()} or {@link Environment#isWindows()}. * * @param command OS depended command as {@link CommandLineResult} * @return the result as {@link String} * @throws SakuliException if the command won't exit with value 0 */ public static CommandLineResult runCommand(String command) throws SakuliException { return runCommand(command, true); } /** * Equal to {@link #runCommand(String)}, but with option to avoid throwing an exception if the exit code != 0 */ public static CommandLineResult runCommand(String command, boolean throwException) throws SakuliException { return CommandLineUtil.runCommand(command, throwException); } /** * set a new default similarity of the screen capturing methods. To reset the similarty call {@link * #resetSimilarity()}. * * @param similarity double value between 0 and 1, default = {@link ActionProperties#defaultRegionSimilarity} * @return this {@link Environment} or NULL on errors. */ @LogToResult(message = "set similarity level", logClassInstance = false) public Environment setSimilarity(double similarity) { if (similarity >= 0 && similarity <= 1) { this.loader.getSettings().setMinSimilarity(similarity); } else { loader.getExceptionHandler().handleException("The similartiy must be a double value between 0 and 1!", resumeOnException); return null; } return this; } /** * Resets the current similarty of the screen capturing methods to the original default value of * {@link ActionProperties#defaultRegionSimilarity}. * * @return this {@link Environment} or NULL on errors. */ @LogToResult(message = "reset similarity level to default") public Environment resetSimilarity() { this.loader.getSettings().restetMinSimilarity(); return this; } /** * @return a {@link Region} object from the current focused window or NULL on errors. */ @LogToResult(logClassInstance = false) public Region getRegionFromFocusedWindow() { org.sikuli.script.Region origRegion = App.focusedWindow(); if (origRegion != null) { return new Region(origRegion, resumeOnException); } loader.getExceptionHandler().handleException("couldn't extract a Region from the current focused window", resumeOnException); return null; } /** * Takes a screenshot of the current screen and saves it to the overgiven path. If there ist just a file name, the * screenshot will be saved in your testsuite log folder. * * @param pathName "pathname/filname.format" or just "filename.format"<br> for example "test.png". */ @LogToResult(message = "take a screenshot from the current screen and save it to the file system", logClassInstance = false) public String takeScreenshot(final String pathName) { Path folderPath; String message; if (pathName.contains(File.separator)) { folderPath = Paths.get(pathName.substring(0, pathName.lastIndexOf(File.separator))); message = pathName.substring(pathName.lastIndexOf(File.separator) + 1, pathName.lastIndexOf(".")); } else { folderPath = loader.getActionProperties().getScreenShotFolder(); message = pathName.substring(0, pathName.lastIndexOf(".")); } try { loader.getScreen().capture(); return loader.getScreenshotActions().takeScreenshot(message, folderPath, pathName.substring(pathName.lastIndexOf(".") + 1)).toFile().getAbsolutePath(); } catch (IOException e) { loader.getExceptionHandler().handleException("Can't create Screenshot for path '" + pathName + "': " + e.getMessage(), resumeOnException); } return null; } /** * Blocks the current testcase execution for x seconds * * @param seconds to sleep * @return this {@link Environment} or NULL on errors. */ @LogToResult(message = "sleep and do nothing for x seconds", logClassInstance = false) public Environment sleep(Integer seconds) { return typingUtil.sleep(seconds * 1000L); } /** * Blocks the current testcase execution for x seconds * * @param seconds to sleep * @return this {@link Environment} or NULL on errors. */ @LogToResult(message = "sleep and do nothing for x seconds", logClassInstance = false) public Environment sleep(Double seconds) { return typingUtil.sleep((long) (seconds * 1000L)); } /** * Blocks the current testcase execution for x milliseconds * * @param milliseconds to sleep * @return this {@link Environment} or NULL on errors. */ @LogToResult(message = "sleep and do nothing for x milliseconds", logClassInstance = false) public Environment sleepMs(Integer milliseconds) { return typingUtil.sleep(Long.valueOf(milliseconds)); } /** * @return the current content of the clipboard as {@link String} or NULL on errors */ @LogToResult(message = "get string from system clipboard", logClassInstance = false) public String getClipboard() { return App.getClipboard(); } /** * sets the String paramter to the system clipboard * * @param text as {@link String} * @return this {@link Environment}. */ @LogToResult(message = "put to clipboard", logClassInstance = false) public Environment setClipboard(String text) { App.setClipboard(text); return this; } /** * Clean the content of the clipboard. */ @LogToResult(logClassInstance = false) public Environment cleanClipboard() { Application.setClipboard(" "); return this; } /** * pastes the current clipboard content into the focused area. Will do the same as "STRG + C". * * @return this {@link Environment}. */ @ModifySahiTimer @LogToResult(message = "paste the current clipboard into the focus", logClassInstance = false) public Environment pasteClipboard() { int mod = Key.getHotkeyModifier(); IRobot r = loader.getScreen().getRobot(); r.keyDown(mod); r.keyDown(KeyEvent.VK_V); r.keyUp(KeyEvent.VK_V); r.keyUp(mod); return this; } /** * copy the current selected item or text to the clipboard. Will do the same as "STRG + V". * * @return this {@link Environment}. */ @ModifySahiTimer @LogToResult(message = "copy the current selection to the clipboard", logClassInstance = false) public Environment copyIntoClipboard() { int mod = Key.getHotkeyModifier(); IRobot r = loader.getScreen().getRobot(); r.keyDown(mod); r.keyDown(KeyEvent.VK_C); r.keyUp(KeyEvent.VK_C); r.keyUp(mod); return this; } /** * {@link org.sakuli.actions.screenbased.TypingUtil#paste(String)}. */ @ModifySahiTimer @LogToResult(logClassInstance = false) public Environment paste(String text) { return typingUtil.paste(text); } /** * {@link org.sakuli.actions.screenbased.TypingUtil#pasteMasked(String)}. */ @ModifySahiTimer @LogToResult(logClassInstance = false, logArgs = false) public Environment pasteMasked(String text) { return typingUtil.pasteMasked(text); } /** * {@link org.sakuli.actions.screenbased.TypingUtil#pasteAndDecrypt(String)}. */ @ModifySahiTimer @LogToResult(logClassInstance = false, logArgs = false) public Environment pasteAndDecrypt(String text) { return typingUtil.pasteAndDecrypt(text); } /** * See {@link org.sakuli.actions.screenbased.TypingUtil#type(String, String)}. */ @ModifySahiTimer @LogToResult(message = "type over system keyboard", logClassInstance = false) public Environment type(String text) { return typingUtil.type(text, null); } /** * See {@link org.sakuli.actions.screenbased.TypingUtil#type(String, String)}. */ @ModifySahiTimer @LogToResult(message = "type with pressed modifiers", logClassInstance = false) public Environment type(String text, String optModifiers) { return typingUtil.type(text, optModifiers); } /** * See {@link org.sakuli.actions.screenbased.TypingUtil#typeMasked(String, String)}. */ @ModifySahiTimer @LogToResult(message = "type over system keyboard", logClassInstance = false, logArgs = false) public Environment typeMasked(String text) { return typingUtil.typeMasked(text, null); } /** * See {@link org.sakuli.actions.screenbased.TypingUtil#typeMasked(String, String)}. */ @ModifySahiTimer @LogToResult(message = "type with pressed modifiers", logClassInstance = false, logArgs = false) public Environment typeMasked(String text, String optModifiers) { return typingUtil.typeMasked(text, optModifiers); } /** * See {@link org.sakuli.actions.screenbased.TypingUtil#typeAndDecrypt(String, String)} . */ @ModifySahiTimer @LogToResult(message = "decrypt and type over system keyboard", logClassInstance = false, logArgs = false) public Environment typeAndDecrypt(String text) { return typingUtil.typeAndDecrypt(text, null); } /** * See {@link org.sakuli.actions.screenbased.TypingUtil#typeAndDecrypt(String, String)} . */ @ModifySahiTimer @LogToResult(message = "decrypt and type with pressed modifiers", logClassInstance = false, logArgs = false) public Environment typeAndDecrypt(String text, String optModifiers) { return typingUtil.typeAndDecrypt(text, optModifiers); } /** * See {@link TypingUtil#keyDown(String)}. */ @ModifySahiTimer @LogToResult(message = "press key down", logClassInstance = false) public Environment keyDown(String keys) { return typingUtil.keyDown(keys); } /** * See {@link TypingUtil#keyUp(String)}. */ @ModifySahiTimer @LogToResult(message = "press key up", logClassInstance = false) public Environment keyUp(String keys) { return typingUtil.keyUp(keys); } /** * See {@link TypingUtil#write(String)}. */ @ModifySahiTimer @LogToResult(message = "interpret and write the following expresion", logClassInstance = false) public Environment write(String text) { return typingUtil.write(text); } /** * {@link TypingUtil#mouseWheelDown(int)} */ @LogToResult(message = "move mouse wheel down x times") public Environment mouseWheelDown(int steps) { return typingUtil.mouseWheelDown(steps); } /** * {@link TypingUtil#mouseWheelUp(int)} */ @LogToResult(message = "move mouse wheel up x times") public Environment mouseWheelUp(int steps) { return typingUtil.mouseWheelUp(steps); } /** * {@link org.sakuli.actions.screenbased.TypingUtil#decryptSecret(String)} */ @LogToResult(logClassInstance = false, logArgs = false) public String decryptSecret(String secret) { return typingUtil.decryptSecret(secret); } /** * @return true, if the OS is any instance of an Windows based OS */ @LogToResult(logClassInstance = false, logArgs = false) public boolean isWindows() { switch (OSUtils.identifyOS()) { case "xp": return true; case "nt": return true; default: return false; } } /** * @return true, if the OS is any instance of an Linux based OS */ @LogToResult(logClassInstance = false, logArgs = false) public boolean isLinux() { switch (OSUtils.identifyOS()) { case "linux": return true; default: return false; } } /** * @return a identifier of the current OS */ @LogToResult(logClassInstance = false, logArgs = false) public String getOsIdentifier() { return OSUtils.identifyOS(); } @Override public boolean getResumeOnException() { return resumeOnException; } @Override public ScreenActionLoader getLoader() { return loader; } @Override public RegionImpl getActionRegion() { return RegionImpl.toRegion(loader.getScreen(), resumeOnException, loader); } }