Package org.uiautomation.ios.instruments

Source Code of org.uiautomation.ios.instruments.InstrumentsCommandLine

/*
* Copyright 2012-2013 eBay Software Foundation and ios-driver committers
*
* 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.uiautomation.ios.instruments;

import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.remote.Response;
import org.uiautomation.ios.Device;
import org.uiautomation.ios.IOSCapabilities;
import org.uiautomation.ios.RealDevice;
import org.uiautomation.ios.ServerSideSession;
import org.uiautomation.ios.application.IOSRunningApplication;
import org.uiautomation.ios.command.UIAScriptRequest;
import org.uiautomation.ios.command.UIAScriptResponse;
import org.uiautomation.ios.command.uiautomation.StopInstrumentsRunLoop;
import org.uiautomation.ios.instruments.commandExecutor.CURLIAutomationCommandExecutor;
import org.uiautomation.ios.instruments.commandExecutor.UIAutomationCommandExecutor;
import org.uiautomation.ios.utils.AppleMagicString;
import org.uiautomation.ios.utils.ClassicCommands;
import org.uiautomation.ios.utils.Command;
import org.uiautomation.ios.utils.CommandOutputListener;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import static org.uiautomation.ios.instruments.commandExecutor.CommunicationMode.CURL;

public class InstrumentsCommandLine implements Instruments {

  private static final Logger log = Logger.getLogger(InstrumentsCommandLine.class.getName());
  private static final int MAX_TIME_FOR_INSTRUMENT_TO_DIE = 2000;
  private final String uuid;
  private final File template;
  private final IOSRunningApplication application;
  private final File output;
  private final String sessionId;
  private final List<String> envtParams;
  private final Command instruments;
  private final CURLIAutomationCommandExecutor channel;
  private final InstrumentsVersion version;
  private final TakeScreenshotService screenshotService;
  private final IOSCapabilities caps;
  private final String desiredSDKVersion;
  private final ServerSideSession session;
  private long instrumentsPid = -1;
  private boolean properlyStarted = false;

  public InstrumentsCommandLine(ServerSideSession session) {
    Device device = session.getDevice();
    if (device instanceof RealDevice) {
      uuid = ((RealDevice) device).getUuid();
    } else {
      uuid = null;
    }
    this.caps = session.getCapabilities();
    this.version = session.getIOSServerManager().getHostInfo().getInstrumentsVersion();
    this.sessionId = session.getSessionId();
    this.application = session.getApplication();
    this.envtParams = caps.getExtraSwitches();
    this.session = session;
    this.desiredSDKVersion = caps.getSDKVersion();
    template = ClassicCommands.getAutomationTemplate();

    String appPath = application.getDotAppAbsolutePath();

    int port = session.getOptions().getPort();
    File
        scriptPath =
        new ScriptHelper().getScript(port, appPath, sessionId, CURL, caps.isAcceptAllCerts());
    output = createTmpOutputFolder();

    instruments = createInstrumentCommand(scriptPath);
    instruments.setWorkingDirectory(output);

    channel = new CURLIAutomationCommandExecutor(session);

    screenshotService = new InstrumentsAppleScreenshotService(this, sessionId);
  }


  @Override
  public void start(long timeout) throws InstrumentsFailedToStartException {
    boolean success = false;
    try {
      instruments.start();

      if (version.getMajor() >= 6 && caps.getReuseContentAndSettings()) {
        // If we launch instruments w/o clearing the content and settings folder in xcode 6, the 1st launch just
        // launches the simulator but fails to launch the app with the following error
        //    "Instruments Trace Error : Target failed to run: The operation couldn’t be completed.
        //    (FBSOpenApplicationErrorDomain error 8.) : Failed to launch process with bundle identifier
        //    '<bundle name>'"
        // So we need to launch instruments twice.

        long startTime = System.currentTimeMillis();
        instruments.waitFor(10000);
        long endTime = System.currentTimeMillis();
        if (endTime - startTime >= 10000) {
          throw new WebDriverException("Wait for instruments timed out. It probably means Apple has fixed this issue "
              + "and we can just get rid of the parent if block.");
        }
        instruments.start();

        // Another alternate way would be to run
        //       xcrun simctl launch <uuid> <bundle name> [<args>]
        // We will also have to update the instruments js to respond back after the app comes to foreground
      }

      // for the no delay instruments, the command launches a script that in turn launches instruments.
      // need to keep the pid of intruments itself to be able to kill it.

      // let the process spawn
      Thread.sleep(2000);
      instrumentsPid = ClassicCommands.getHighestPidForName("instruments");

      log.fine("waiting for registration request");
      long waitStartTime = System.currentTimeMillis();
      success = channel.waitForUIScriptToBeStarted(timeout);
      synchronized (this) {
        properlyStarted = success;
      }
      log.fine("registration request received" + session.getCachedCapabilityResponse());
      if (!success) {
        log.warning("instruments crashed (" + ((System.currentTimeMillis() - waitStartTime) / 1000) + " sec)".toUpperCase());
        throw new InstrumentsFailedToStartException(
            "Didn't get the capability back.Most likely, instruments crashed at startup.");
      }
    } catch (InterruptedException e) {
      throw new InstrumentsFailedToStartException("instruments was interrupted while starting.");
    } finally {
      // appears only in ios6. : Automation Instrument ran into an exception
      // while trying to run the script. UIAScriptAgentSignaledException
      if (!success) {
        instruments.forceStop();
      }
    }
  }

  @Override
  public int waitForProcessToDie() {
    return instruments.waitFor(MAX_TIME_FOR_INSTRUMENT_TO_DIE);
  }

  public boolean isProperlyStarted() {
    synchronized (this) {
      return properlyStarted;
    }
  }

  @Override
  public void stop() {
    if (isProperlyStarted()) {

      try {
        new StopInstrumentsRunLoop(session).handle();
        synchronized (this) {
          properlyStarted = false;
        }
      } catch (Exception e) {
        // ignore. If we can't kill instruments properly, forcestop will do it.
      }
    }
    channel.stop();

    if (session.getDevice() instanceof RealDevice) {
      try {
        Thread.sleep(1500);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    instruments.forceStop();
    try {
      ClassicCommands.kill(instrumentsPid);
    } catch (Exception e) {
        log.warning("couldn't kill " + instrumentsPid);
    }
  }

  private Command createInstrumentCommand(File script) {
    List<String> args = new ArrayList<>();

    args.add(getInstrumentsClient());
    args.add("-v");
    if (uuid != null) {
      args.add("-w");
      args.add(uuid);
    } else if (application.isSimulator() && Double.parseDouble(version.getBuild()) >= 55044) {
      // newer instruments require to specify the simulator SDK and device type
      args.add("-w");
      args.add(AppleMagicString.getDeviceSpecification(caps.getDevice(), caps.getDeviceVariation(),
                                                       desiredSDKVersion, version));
    }
    args.add("-t");
    args.add(template.getAbsolutePath());
    args.add(application.getDotAppAbsolutePath());
    args.add("-e");
    args.add("UIASCRIPT");
    args.add(script.getAbsolutePath());
    args.add("-e");
    args.add("UIARESULTSPATH");
    args.add(output.getAbsolutePath());
    args.addAll(envtParams);
    return new Command(args, false);
  }

  private File createTmpOutputFolder() {
    try {
      File output = File.createTempFile(sessionId, null);
      output.delete();
      output.mkdir();
      output.deleteOnExit();
      return output;
    } catch (IOException e) {
      throw new WebDriverException(
          "Cannot create the tmp folder where all the instruments tmp files"
          + "will be stored.", e);
    }
  }

  private String getInstrumentsClient() {
    return InstrumentsNoDelayLoader.getInstance(version).getInstruments().getAbsolutePath();
  }

  @Override
  public Response executeCommand(UIAScriptRequest request) {
    UIAScriptResponse res = channel.executeCommand(request);
    return res.getResponse();
  }

  @Override
  public UIAutomationCommandExecutor getChannel() {
    return channel;
  }

  @Override
  public TakeScreenshotService getScreenshotService() {
    return screenshotService;
  }

  @Override
  public boolean isCompatible(ServerSideSession session) {
    if (session.isSafariRealDevice()) {
      return false;
    } else {
      return true;
    }
  }

  @Override
  public void registerOutputListener(CommandOutputListener listener) {
    if (instruments!=null){
      instruments.registerListener(listener);
    }else{
      log.warning("trying to register an output listener on instruments, but instruments is null, not created yet.");
    }
  }


  public File getOutput() {
    return output;
  }


}
TOP

Related Classes of org.uiautomation.ios.instruments.InstrumentsCommandLine

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.