/* MonkeyTalk - a cross-platform functional testing tool
Copyright (C) 2012 Gorilla Logic, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package com.gorillalogic.monkeytalk.processor.command.tests;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.matchers.JUnitMatchers.containsString;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
import com.gorillalogic.monkeytalk.Command;
import com.gorillalogic.monkeytalk.processor.PlaybackResult;
import com.gorillalogic.monkeytalk.processor.PlaybackStatus;
import com.gorillalogic.monkeytalk.processor.Scope;
import com.gorillalogic.monkeytalk.processor.ScriptProcessor;
import com.gorillalogic.monkeytalk.processor.command.VerifyImage;
import com.gorillalogic.monkeytalk.server.JsonServer;
import com.gorillalogic.monkeytalk.utils.Base64;
import com.gorillalogic.monkeytalk.utils.ImageUtils;
public class VerifyImageCommandTest extends BaseCommandHelper {
File scriptDir;
@Before
public void before2() throws IOException {
this.scriptDir = new File(tempDir(), this.getClass().getSimpleName() + "_scripts");
if (scriptDir.exists()) {
scriptDir.delete();
}
scriptDir.mkdirs();
}
@Test
public void testWithMissingExpected() throws IOException {
tempScript("foo.mt", "Device * VerifyImage", scriptDir);
ScriptProcessor processor = new ScriptProcessor(HOST, PORT, scriptDir);
processor.setPlaybackListener(LISTENER_WITH_OUTPUT);
PlaybackResult result = processor.runScript("foo.mt");
assertThat("FAIL: " + result, result.getStatus(), is(PlaybackStatus.ERROR));
assertThat(result.getMessage(),
is("command 'Device * VerifyImage' must have a file path as its first arg"));
assertThat(output, containsString("START"));
assertThat(
output,
containsString("COMPLETE : ERROR : command 'Device * VerifyImage' must have a file path as its first arg"));
}
@Test
public void testWithDirectoryAsExpected() throws IOException {
String directoryName = "testVerifyWithDirectoryAsExpected_directory";
File directory = new File(scriptDir, directoryName);
directory.mkdirs();
tempScript("foo.mt", "Device * VerifyImage " + directoryName, scriptDir);
ScriptProcessor processor = new ScriptProcessor(HOST, PORT, scriptDir);
processor.setPlaybackListener(LISTENER_WITH_OUTPUT);
PlaybackResult result = processor.runScript("foo.mt");
assertThat("FAIL: " + result, result.getStatus(), is(PlaybackStatus.ERROR));
assertThat(result.getMessage(), is("command 'Device * VerifyImage " + directoryName
+ "' - expectedImageFile '" + directoryName
+ "' is not a regular file, perhaps a folder?"));
assertThat(output, containsString("START"));
assertThat(output, containsString("COMPLETE : ERROR : command 'Device * VerifyImage "
+ directoryName + "' - expectedImageFile '" + directoryName
+ "' is not a regular file, perhaps a folder?"));
}
@Test
public void testWithAbsoluteAsExpected() throws IOException {
String absoluteName = "/testWithAbsoluteAsExpected_directory/1/2/3/banana.png";
tempScript("foo.mt", "Device * VerifyImage " + absoluteName, scriptDir);
ScriptProcessor processor = new ScriptProcessor(HOST, PORT, scriptDir);
processor.setPlaybackListener(LISTENER_WITH_OUTPUT);
PlaybackResult result = processor.runScript("foo.mt");
assertThat("FAIL: " + result, result.getStatus(), is(PlaybackStatus.ERROR));
assertThat(
result.getMessage(),
is("command 'Device * VerifyImage "
+ absoluteName
+ "' - expectedImageFile '"
+ absoluteName
+ "' is an absolute path reference"
+ "' - the expected image file path must be specified relative to the project directory"));
assertThat(output, containsString("START"));
assertThat(
output,
containsString("COMPLETE : ERROR : command 'Device * VerifyImage "
+ absoluteName
+ "' - expectedImageFile '"
+ absoluteName
+ "' is an absolute path reference"
+ "' - the expected image file path must be specified relative to the project directory"));
}
@Test
public void testWithBadTolerance() throws IOException {
doTestWithBadTolerance("rewrewrew");
doTestWithBadTolerance("-1");
doTestWithBadTolerance("-32876");
doTestWithBadTolerance("256");
doTestWithBadTolerance("25632");
doTestWithBadTolerance("256323398219038209182098312");
doTestWithBadTolerance("-256323398219038209182098312");
doTestWithBadTolerance("16.8328");
doTestWithBadTolerance("-116.8328");
doTestWithBadTolerance("-0.8328");
doTestWithBadTolerance(".8328");
doTestWithBadTolerance("047AFE");
}
private void doTestWithBadTolerance(String badTolerance) throws IOException {
tempScript("foo.mt", "Device * VerifyImage dummy.file " + badTolerance, scriptDir);
ScriptProcessor processor = new ScriptProcessor(HOST, PORT, scriptDir);
processor.setPlaybackListener(LISTENER_WITH_OUTPUT);
PlaybackResult result = processor.runScript("foo.mt");
assertThat("FAIL: " + result, result.getStatus(), is(PlaybackStatus.ERROR));
assertThat(result.getMessage(), is("command 'Device * VerifyImage dummy.file "
+ badTolerance + "' - tolerance '" + badTolerance
+ "' is invalid: must be an integer" + " between " + ImageUtils.MIN_TOLERANCE
+ " and " + ImageUtils.MAX_TOLERANCE));
assertThat(output, containsString("START"));
assertThat(output,
containsString("COMPLETE : ERROR : command 'Device * VerifyImage dummy.file "
+ badTolerance + "' - tolerance '" + badTolerance
+ "' is invalid: must be an integer" + " between "
+ ImageUtils.MIN_TOLERANCE + " and " + ImageUtils.MAX_TOLERANCE));
}
@Test
public void testWithAgentError() throws IOException {
doTestWithErrorResponse("Device * VerifyImage testWithAgentError.png", " - SOME ERROR");
}
@Test
public void testWithEmptyAgentMessage() throws IOException {
doTestWithErrorResponse("Device * VerifyImage testWithEmptyAgentMessage.png",
" - no message from agent");
}
@Test
public void testWithNullAgentMessage() throws IOException {
doTestWithErrorResponse("Device * VerifyImage testWithEmptyAgentMessageOk.png",
" - no message from agent");
doTestWithErrorResponse("Device * VerifyImage testWithEmptyAgentMessageError.png",
" - no message from agent");
}
@Test
public void testWithFailedScreenshot() throws IOException {
doTestWithErrorResponse("Device * VerifyImage testWithFailedScreenshot.png",
" - screenshot could not be taken");
}
@Test
public void testWithMissingScreenshot() throws IOException {
doTestWithOkResponse(
"Device * VerifyImage testWithMissingScreenshot.png",
" - file '"
+ scriptDir.getPath()
+ "/testWithMissingScreenshot.png' was not found, creating it with the just-captured image");
doTestWithOkResponse(
"Device * VerifyImage testWithMissingImage.png",
" - file '"
+ scriptDir.getPath()
+ "/testWithMissingImage.png' was not found, creating it with the just-captured image");
doTestWithErrorResponse("Device * VerifyImage testWithMissingScreenshotAndImage.png",
" - no screenshot received");
}
@Test
public void testWithInvalidScreenshot() throws IOException {
doTestWithErrorResponse("Device * VerifyImage testWithInvalidScreenshot.png",
" - error cropping image");
}
@Test
public void testWithUnparseableCropBounds() throws IOException {
PlaybackResult result = doTestWithOkResponse(
"Device * VerifyImage testWithUnparseableCropBounds.png",
" - file '"
+ scriptDir.getPath()
+ "/testWithUnparseableCropBounds.png' was not found, creating it with the just-captured image");
assertThat(result.getWarning(),
containsString("could not parse component rectangle from this string: "));
}
@Test
public void testWithFailedComparison() throws IOException {
byte[] fff = Base64.decode(GOOD_SCREENSHOT_STRING);
FileUtils.writeByteArrayToFile(new File(scriptDir, "GOODSCREENSHOT2.PNG"), fff);
PlaybackResult result = doTestWithFailureResponse(
"Device * VerifyImage GOODSCREENSHOT2.PNG",
" - expected and captured images do not match.");
assertNull(result.getWarning());
}
@Test
public void testWithSuccessfulComparison() throws IOException {
byte[] fff = Base64.decode(GOOD_SCREENSHOT_STRING);
FileUtils.writeByteArrayToFile(new File(scriptDir, "GOODSCREENSHOT.PNG"), fff);
String cmd = "Device * VerifyImage GOODSCREENSHOT.PNG";
PlaybackResult result = doTestWithOkResponse(cmd, null);
assertThat(result.getMessage(), is(""));
}
@Test
public void testInvalidComponent() throws IOException {
File dir = tempDir();
tempScript("foo.mt", "Fred * VerifyImage fred.png", dir);
ScriptProcessor processor = new ScriptProcessor(HOST, PORT, dir);
CommandServer server = new CommandServer(PORT);
processor.setPlaybackListener(LISTENER_WITH_OUTPUT);
PlaybackResult result = processor.runScript("foo.mt");
server.stop();
assertThat("FAIL: " + result, result.getStatus(), is(PlaybackStatus.ERROR));
assertThat(output, containsString("START"));
assertThat(output, containsString("Fred * VerifyImage fred.png"));
// assertThat(output, containsString("Unrecognized component type: Fred"));
}
public PlaybackResult doTestWithFailureResponse(String script, String message)
throws IOException {
return doTestWithAgentResponse(script, message, PlaybackStatus.FAILURE);
}
public PlaybackResult doTestWithOkResponse(String script, String message) throws IOException {
return doTestWithAgentResponse(script, message, PlaybackStatus.OK);
}
public PlaybackResult doTestWithErrorResponse(String script, String errormessage)
throws IOException {
return doTestWithAgentResponse(script, errormessage, PlaybackStatus.ERROR);
}
public PlaybackResult doTestWithAgentResponse(String script, String errormessage,
PlaybackStatus expectedStatus) throws IOException {
String host = "localhost";
int port = 5432;
// tempScript("foo.mt", script, scriptDir);
Command command = new Command(script);
ScriptProcessor processor = new ScriptProcessor(host, port, scriptDir);
processor.setPlaybackListener(LISTENER_WITH_OUTPUT);
VerifyImageServer agentMock = new VerifyImageServer(port);
PlaybackResult result = null;
try {
Scope scope = new Scope();
scope.setCurrentCommand(command);
result = new VerifyImage(command, scope, LISTENER_WITH_OUTPUT, processor, scriptDir)
.verifyImage();
} finally {
agentMock.stop();
}
assertThat("FAIL: " + result, result.getStatus(), is(expectedStatus));
if (errormessage != null) {
String _errormessage = "command '" + script + "'" + errormessage;
assertThat(result.getMessage(), is(_errormessage));
assertThat(output, containsString(expectedStatus.name() + " : " + _errormessage));
}
assertThat(agentMock.getCommands().toString(), containsString(script));
return result;
}
public static class CommandServer extends JsonServer {
private List<Command> commands;
private List<String> jsons;
public CommandServer(int port) throws IOException {
super(port);
commands = new ArrayList<Command>();
jsons = new ArrayList<String>();
}
/**
* Get the list of all captured MonkeyTalk commands.
*
* @return the commands
*/
public List<Command> getCommands() {
return commands;
}
/**
* Get the list of all captured MonkeyTalk commands in their raw JSON format.
*
* @return the commands
*/
public List<String> getRawJSONCommands() {
return jsons;
}
@Override
public Response serve(String uri, String method, Map<String, String> headers,
JSONObject json) {
jsons.add(json.toString());
Command cmd = new Command(json);
// ignore blank commands (aka PINGs)
if (!"* * *".equals(cmd.toString())) {
commands.add(new Command(json));
}
return new Response(HttpStatus.OK, "{result:\"OK\"}");
}
}
private static class VerifyImageServer extends CommandServer {
VerifyImageServer(int port) throws IOException {
super(port);
}
@Override
public Response serve(String uri, String method, Map<String, String> headers,
JSONObject json) {
super.serve(uri, method, headers, json);
if (json.toString().contains("AgentError")) {
return new Response(HttpStatus.OK, "{result:\"ERROR\",message=\"SOME ERROR\"}");
} else if (json.toString().contains("FailedScreenshot")) {
return new Response(HttpStatus.OK,
"{result:\"ERROR\",message=\"screenshot could not be taken\"}");
} else if (json.toString().contains("EmptyAgentMessage")) {
return new Response(HttpStatus.OK, "{result:\"ERROR\",message=\"\"}");
} else if (json.toString().contains("NullAgentMessageOk")) {
return new Response(HttpStatus.OK, "{result:\"OK\"}");
} else if (json.toString().contains("NullAgentMessageError")) {
return new Response(HttpStatus.OK, "{result:\"ERROR\"}");
} else if (json.toString().contains("MissingImage")) {
return new Response(HttpStatus.OK, "{\"result\":\"OK\","
+ "\"message\":\"2 2 20 20\"," + "\"screenshot\"=\""
+ GOOD_SCREENSHOT_STRING + "\"}");
} else if (json.toString().contains("MissingScreenshotAndImage")) {
return new Response(HttpStatus.OK, "{\"result\":\"OK\","
+ "\"message\":\"2 2 400 500\"}");
} else if (json.toString().contains("MissingScreenshot")) {
return new Response(HttpStatus.OK, "{\"result\":\"OK\","
+ "\"message\":\"2 2 20 20\"," + "\"image\"=\"" + GOOD_SCREENSHOT_STRING
+ "\"}");
} else if (json.toString().contains("InvalidScreenshot")) {
return new Response(HttpStatus.OK, "{\"result\":\"OK\","
+ "\"message\":\"2 2 20 20\","
+ "\"screenshot\"=\"iVBORw0KGg48i8JgP8PcEwFnYsg4J4AAAAASUVORK5CYII=\","
+ "\"image\"=\"iVBORw0KGg48i8JgP8PcEwFnYsg4J4AAAAASUVORK5CYII=\"}");
} else if (json.toString().contains("UnparseableCropBounds")) {
return new Response(HttpStatus.OK, "{\"result\":\"OK\","
+ "\"message\":\"this_is_a_bunch_of crap\"," + "\"screenshot\"=\""
+ GOOD_SCREENSHOT_STRING + "\"," + "\"image\"=\"" + GOOD_SCREENSHOT_STRING
+ "\"}");
} else if (json.toString().contains("GOODSCREENSHOT.PNG")) {
return new Response(HttpStatus.OK, "{\"result\":\"OK\","
+ "\"message\":\"0 0 50 22\"," + "\"screenshot\"=\""
+ GOOD_SCREENSHOT_STRING + "\"," + "\"image\"=\"" + GOOD_SCREENSHOT_STRING
+ "\"}");
} else if (json.toString().contains("GOODSCREENSHOT2.PNG")) {
return new Response(HttpStatus.OK, "{\"result\":\"OK\","
+ "\"message\":\"2 2 20 20\"," + "\"screenshot\"=\""
+ GOOD_SCREENSHOT_STRING2 + "\"," + "\"image\"=\""
+ GOOD_SCREENSHOT_STRING2 + "\"}");
}
return new Response(HttpStatus.OK, "{\"result\":\"OK\"," + "\"message\":\"2 2 20 20\","
+ "\"screenshot\"=\"" + GOOD_SCREENSHOT_STRING + "\"," + "\"image\"=\""
+ GOOD_SCREENSHOT_STRING + "\"}");
}
}
private static final String GOOD_SCREENSHOT_STRING = "iVBORw0KGgoAAAANSUhEUgAAADIAAAAWCAYAAACCAs"
+ "+RAAADOUlEQVR42u2WSSh1YRjHr8zEgitDxsTCRpQMCSULWZDuwkISiVAUF1lYYKEsxEqKrEh"
+ "KptzFpdQ1JFaIopQxw0YyZvh//Z+v83b18X26Vr7Ov06d9/Se93l+z3SOAf+JDDqIDqKDfA3k6ekJx8fHeH5"
+ "+xsPDw88EGRwchNFoRElJCQYGBhAXF/czQdLT01FXVycPfixIZWUlfH19ERMTg87Ozj9ALi8vYTKZ4O/"
+ "vj6ioKNnz8vKCq6srpKWlYWtrS/ZdXFzIenR0VL1bWlqKiYkJud/b20NeXh5CQ0ORm5uL1dVVtW9qagr0Y3"
+ "JyEvHx8djd3cXZ2RnMZrPYjI2NRXt7O97e3j4HWVxcFIiKigpsbGy8A+GLPJiGbTYbxsbGBIiHUtHR0ejr65N"
+ "7OmwwGFBUVCTru7s7uLq6Ynt7W6D9/PyQn5+P2dlZNDc3w9vbG5ubm6oKgoOD5eyamhrZX11djYKCAiwtLaG3"
+ "txeBgYEYGRn5e2klJSUph+xBZmZmxDlmRVN/fz98fHwEsqqqSjne0NCAjIwMhIWFyXp+fh4hISFy39raioiIi"
+ "HcRzc7ORn19vbJJOwykJoL39PSo9dzcnFwOgXR0dEi27LW+vi5GT05OJAvh4eHyPCUlRcDd3d1xeHiItrY2K"
+ "S0qJydHbHR1dakrMzNTnms2WXL24uBhRplFBu/09PTfzf4ZCCPGyNmLUSPI0dERrq+v4ezsjP39fSmV29tbyQ"
+ "pLICsrS5VCYmIiEhISpFzsr+7u7k8HzOvrKywWC4qLixEQEAAXFxcpS4dAmFoOAja3fWl5eHioZ6mpqaitr"
+ "UVycrKsmYny8nJ4eXmpkiwsLFTR17S8vCx99xHIzc0NhoeHBYbit43DgFl0COTg4EDSq0X28fFRHOdg0E"
+ "TH6XRjY6OsFxYW4OnpKVnQND4+LvBWq1VBsHnp7Ecg7KXIyEj5vmkBo82ysjLHQKihoSFxlBOKTc6S4VTR"
+ "xKnCUpuenpb1/f093Nzc0NLS8s4QQZ2cnKRM2EdNTU2q+T8qLdrlOUFBQdI/HO07Ozvf+9diqtfW1uQX5jt"
+ "iAFZWVuSb89X9zN75+bn+96uD6CA6yG/9ApyxZm12V7NxAAAAAElFTkSuQmCC";
private static final String GOOD_SCREENSHOT_STRING2 = "iVBORw0KGgoAAAANSUhEUgAAADIAAAAdCAIAAABnp6gFAAABY0lEQVR42u2WsWvCUBCHHTJkzOCQoUMdBRfBQddAF6GD2RQcSqYSn"
+ "KSDZBPpFDoUpyJuz0FwEXSzf1u/ePIa7GAEY0J5xxuS8y75vPu9e6lUjBkzZuyiDYYDtVK7/U6tld/zS8HkPXmH7wNA47dxNImarWa"
+ "WLPfBJTFHLFDAqjfqV2WFozD+jHPEmr3PwOLfZ0+xbXuz3eSF1Wl34o8YSYEli8rpn6JpRGdFcPidqqObjkensOj+jbH8vr9YLnh0"
+ "8BJwjUcXg0UheeX8a04AYZKF+NgiiRxXihRWRjneoImJ1KzfW4pKjH493NwWr63uc5cYPTtKgGUlEDJE6FfBWH93Q/FY0jJRNHpCZ2"
+ "yI4rEAOvOUoolyFqVjgtcyVOs4RR3nND9rjzVmWBoLIwBneojkjiW1AY6Dj1kPARdnWHKSUjDmLcq7y060EjKpGSNevhSoTRqLWpIo"
+ "NSPYfBwaM/bP7Ad1jBSGO1V5MAAAAABJRU5ErkJggg==";
}