/*
Copyright 2011-2012 Opera Software ASA
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 com.opera.core.systems;
import com.google.common.hash.Hashing;
import com.google.common.io.Files;
import com.opera.core.systems.model.ScreenCaptureReply;
import com.opera.core.systems.runner.OperaRunnerException;
import com.opera.core.systems.runner.launcher.OperaLauncherRunner;
import com.opera.core.systems.testing.Ignore;
import com.opera.core.systems.testing.NoDriver;
import com.opera.core.systems.testing.OperaDriverTestCase;
import com.opera.core.systems.testing.drivers.TestDriverBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.Platform;
import org.openqa.selenium.net.PortProber;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.opera.core.systems.OperaProduct.DESKTOP;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.matchers.JUnitMatchers.containsString;
import static org.junit.matchers.JUnitMatchers.hasItem;
@NoDriver
public class OperaLauncherRunnerTest extends OperaDriverTestCase {
public static final String OLD_OPERA_PATH = System.getenv(OperaBinary.OPERA_PATH_ENV_VAR);
public Logger logger = Logger.getLogger(getClass().getName());
public OperaSettings settings;
public TestOperaLauncherRunner runner;
@Before
public void beforeEach() {
settings = new OperaSettings();
settings.setRunner(OperaLauncherRunner.class);
settings.setBinary(TestDriverBuilder.detect().getSettings().getBinary());
settings.logging().setLevel(Level.FINE);
}
@After
public void afterEach() {
try {
if (runner != null && runner.isOperaRunning()) {
runner.stopOpera();
assertFalse(runner.isOperaRunning());
}
} catch (Exception e) {
logger.warning("Got exception while attempting to stop Opera: " + e);
} finally {
if (runner != null) {
runner.shutdown();
}
runner = null;
settings = null;
}
}
@After
public void resetEnvironmentPath() {
environment.set(OperaBinary.OPERA_PATH_ENV_VAR, OLD_OPERA_PATH);
}
@Test
public void constructor() {
runner = new TestOperaLauncherRunner();
assertNotNull(runner);
}
@Test
public void constructorWithSettingsBinary() {
settings.setBinary(OperaBinary.find());
runner = new TestOperaLauncherRunner(settings);
assertNotNull(runner);
}
@Test
public void verifyDefaultStateOfOperaRunning() {
runner = new TestOperaLauncherRunner(settings);
assertFalse(runner.isOperaRunning());
}
@Test
@Ignore
public void launcherInDefaultLocationIsOverwritten()
throws IOException, NoSuchAlgorithmException {
OperaDriverTestCase.removeDriver();
File outdatedLauncher = resources.executableBinary();
try {
Files.copy(outdatedLauncher, OperaLauncherRunner.LAUNCHER_DEFAULT_LOCATION);
} catch (FileNotFoundException e) {
fail("Opera instance from previous was not shutdown, and leaked over into this test: " +
e.getMessage());
}
try {
runner = new TestOperaLauncherRunner(settings);
assertFalse("launcher should have been replaced by extracted launcher",
Arrays.equals(md5(outdatedLauncher),
md5(OperaLauncherRunner.LAUNCHER_DEFAULT_LOCATION)));
} catch (OperaRunnerException e) {
if (e.getMessage().contains("Timeout")) {
fail("launcher was not replaced");
}
}
}
@Test
public void defaultProductIsDesktop() {
assertEquals(OperaProduct.DESKTOP, settings.getProduct());
}
@Test
public void unableToFindProductForGogi() {
environment.unset(OperaBinary.OPERA_PATH_ENV_VAR);
settings.setBinary(null);
settings.setProduct(OperaProduct.CORE);
try {
runner = new TestOperaLauncherRunner(settings);
fail("Expected exception");
} catch (RuntimeException e) {
assertThat(e, is(instanceOf(OperaRunnerException.class)));
assertThat(e.getMessage(), containsString("Unable to find executable for product " +
OperaProduct.CORE.toString()));
}
}
@Test
public void profileArgumentNotSetIfProductIsAll() {
settings.setProduct(OperaProduct.ALL);
assertThat(TestOperaLauncherRunner.buildArguments(settings), hasItem(not("-profile")));
}
@Test
public void profileArgumentSetIfProductIsSpecified() {
OperaProduct product = OperaProduct.DESKTOP;
settings.setProduct(product);
List<String> arguments = TestOperaLauncherRunner.buildArguments(settings);
assertThat(arguments, hasItem("-profile"));
assertThat(arguments, hasItem(product.getDescriptionString()));
}
@Test
public void profileArgumentNotSetIfProductIsCore() {
settings.setProduct(OperaProduct.CORE);
settings.setBinary(OperaBinary.find(OperaProduct.ALL));
assertThat(TestOperaLauncherRunner.buildArguments(settings), hasItem(not("-profile")));
}
@Test
public void testDefaultCrashedState() {
runner = new TestOperaLauncherRunner(settings);
assertFalse(runner.hasOperaCrashed());
}
@Test
public void testDefaultIsOperaRunning() {
runner = new TestOperaLauncherRunner(settings);
assertFalse(runner.isOperaRunning());
}
@Test
public void testStartAndStopOpera() {
runner = new TestOperaLauncherRunner(settings);
runner.startOpera();
assertTrue(runner.isOperaRunning());
runner.stopOpera();
assertFalse(runner.isOperaRunning());
}
@Test
public void startAfterShutdownShouldThrow() {
runner = new TestOperaLauncherRunner(settings);
runner.startOpera();
assertTrue(runner.isOperaRunning());
runner.shutdown();
assertFalse(runner.isOperaRunning());
try {
runner.startOpera();
fail("Expected OperaRunnerException");
} catch (RuntimeException e) {
assertThat(e, is(instanceOf(OperaRunnerException.class)));
assertThat(e.getMessage(), containsString("launcher was shutdown"));
}
}
@Test(expected = OperaRunnerException.class)
public void stopAfterShutdownShouldThrow() {
runner = new TestOperaLauncherRunner(settings);
runner.shutdown();
runner.stopOpera();
}
@Test
public void shutdownShouldNotThrow() {
runner = new TestOperaLauncherRunner(settings);
runner.shutdown();
}
@Test
public void shutdownTwiceShouldNotThrow() {
runner = new TestOperaLauncherRunner(settings);
runner.shutdown();
runner.shutdown();
}
@Test
public void constructorWithSettingsArguments() {
runner = new TestOperaLauncherRunner(settings);
runner.startOpera();
assertTrue(runner.isOperaRunning());
}
@Test
@Ignore(products = DESKTOP, value = "mzajaczkowski_watir_1_cleaned contains fix for this")
public void testStartAndStopOperaTenTimes() {
runner = new TestOperaLauncherRunner(settings);
for (int i = 0; i < 10; i++) {
runner.startOpera();
assertTrue(runner.isOperaRunning());
runner.stopOpera();
assertFalse(runner.isOperaRunning());
}
runner.shutdown();
}
@Test
public void badLauncherShouldThrow() throws IOException {
assertTrue("Imposter launcher exists", resources.executableBinary().exists());
settings.setLauncher(resources.executableBinary());
try {
runner = new TestOperaLauncherRunner(settings);
fail("Expected OperaRunnerException");
} catch (RuntimeException e) {
assertThat(e, is(instanceOf(OperaRunnerException.class)));
if (Platform.getCurrent().is(Platform.WINDOWS)) {
assertThat(e.getMessage(), containsString("exited immediately"));
} else {
assertThat(e.getMessage(), containsString("Timeout waiting for launcher to connect"));
}
}
}
@Test
public void isOperaRunning() {
runner = new TestOperaLauncherRunner(settings);
assertFalse(runner.isOperaRunning());
runner.startOpera();
assertTrue(runner.isOperaRunning());
}
@Test
public void isOperaRunningShouldNotThrowAfterShutdown() {
runner = new TestOperaLauncherRunner(settings);
runner.shutdown();
assertFalse(runner.isOperaRunning());
}
@Test
// TODO(andreastt): Trigger something which actually generates a crashlog
public void testGetOperaDefaultCrashlog() {
runner = new TestOperaLauncherRunner(settings);
runner.startOpera();
String crashlog = runner.getOperaCrashlog();
assertNull(crashlog);
}
@Test
public void saveScreenshot() {
runner = new TestOperaLauncherRunner(settings);
ScreenCaptureReply screenshot = runner.captureScreen();
assertNotNull(screenshot);
}
@Test
public void saveScreenshotAfterShutdownShouldThrow() {
runner = new TestOperaLauncherRunner(settings);
runner.shutdown();
try {
runner.captureScreen();
fail("Expected OperaRunnerException");
} catch (RuntimeException e) {
assertThat(e, is(instanceOf(OperaRunnerException.class)));
assertThat(e.getMessage(), containsString("launcher was shutdown"));
}
}
@Test
public void displayArgumentDoesContainColon() {
int display = 42;
settings.setDisplay(display);
List<String> arguments = TestOperaLauncherRunner.buildArguments(settings);
String displayArgument = null;
String displayArgumentValue = null;
for (int i = 0; i < arguments.size(); ++i) {
String argument = arguments.get(i);
if (argument.startsWith("-display")) {
displayArgument = argument;
displayArgumentValue = arguments.get(i + 1);
}
}
if (displayArgument == null) {
fail("List of launcher arguments did not contain -display");
}
assertThat(displayArgument, containsString("display"));
assertThat(displayArgumentValue, containsString(":"));
assertThat(displayArgumentValue, containsString(String.valueOf(display)));
}
@Test
public void testLoggingLevel() {
assertEquals(Level.SEVERE, TestOperaLauncherRunner.toLauncherLoggingLevel(Level.SEVERE));
}
@Test
public void testLoggingLevelToAll() {
assertEquals(Level.FINEST, TestOperaLauncherRunner.toLauncherLoggingLevel(Level.ALL));
}
@Test
public void testLoggingLevelToConfig() {
assertEquals(Level.FINE, TestOperaLauncherRunner.toLauncherLoggingLevel(Level.CONFIG));
}
@Test
public void testLoggingLevelToFiner() {
assertEquals(Level.FINE, TestOperaLauncherRunner.toLauncherLoggingLevel(Level.FINER));
}
@Test
public void testLoggingLevelToOff() {
assertEquals(Level.OFF, TestOperaLauncherRunner.toLauncherLoggingLevel(Level.OFF));
}
/**
* Get the MD5 hash of the given file.
*
* @param file file to compute a hash on
* @return a byte array of the MD5 hash
* @throws IOException if file cannot be found
* @throws NoSuchAlgorithmException if MD5 is not available
*/
private static byte[] md5(File file) throws NoSuchAlgorithmException, IOException {
return Files.hash(file, Hashing.md5()).asBytes();
}
private static class TestOperaLauncherRunner extends OperaLauncherRunner {
public TestOperaLauncherRunner() {
super();
}
public TestOperaLauncherRunner(OperaSettings settings) {
super(settings);
}
public static List<String> buildArguments(OperaSettings settings) {
return OperaLauncherRunner.buildArguments(settings, PortProber.findFreePort());
}
public static Level toLauncherLoggingLevel(Level javaLevel) {
return OperaLauncherRunner.toLauncherLoggingLevel(javaLevel);
}
}
}