Package com.googlecode.goclipse.builder

Source Code of com.googlecode.goclipse.builder.GoTestRunner$TestConfig

package com.googlecode.goclipse.builder;

import static melnorme.utilbox.core.Assert.AssertNamespace.assertUnreachable;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;

import melnorme.lang.ide.core.utils.process.RunExternalProcessTask;
import melnorme.utilbox.core.CommonException;
import melnorme.utilbox.misc.MiscUtil;
import melnorme.utilbox.process.ExternalProcessHelper.ExternalProcessResult;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;

import com.googlecode.goclipse.Activator;
import com.googlecode.goclipse.core.GoCore;
import com.googlecode.goclipse.core.GoProjectPrefConstants;
import com.googlecode.goclipse.core.operations.GoToolManager;
import com.googlecode.goclipse.go.CodeContext;
import com.googlecode.goclipse.go.lang.model.Function;
import com.googlecode.goclipse.tooling.GoCommandConstants;
import com.googlecode.goclipse.tooling.env.GoEnvironmentConstants;

/**
*
*/
public class GoTestRunner {
 
  private static GoTestRunner instance = new GoTestRunner();
 
  private Queue<TestConfig>    testQueue     = new LinkedList<TestConfig>();
 
  /**
   * queue guard is used to prevent the same test from existing in the
   * queue more than once at any given time.
   */
  private Map<String, String>  queueGuard    = Collections.synchronizedMap(new HashMap<String, String>());
  private Thread               testRunner    = new Thread("Go Test Runner");
  private TestConfig           activeTest    = null;
  private boolean              running       = true;
 
  /**
   *
   */
  private Runnable runnable = new Runnable() {
   
    @Override
    public void run() {
     
      while(running){
       
        // get test off of queue
        if (testQueue.size() > 0) {
          synchronized (instance.testQueue) {
            activeTest = testQueue.remove();
            queueGuard.remove(buildQueueGuardKey(activeTest));
                    }
        }
       
        if (activeTest != null) {
          runTest();
          activeTest = null;
        }
       
        try {
          synchronized (instance.testQueue) {
            while (testQueue.size() == 0) {
              testQueue.wait();
            }
          }
                } catch (InterruptedException e) {
                  Activator.logError(e);
                }
      }
    }

    /**
         *
         */
        private void runTest() {
           
              final ProcessBuilder testProcessBuilder = configureProcess();
             
                // timeout kill process
                new Thread(new Runnable() {
         
          @Override
          public void run() {
            try {
              int maxTime = GoProjectPrefConstants.AUTO_UNIT_TEST_MAX_TIME.get(activeTest.project);
                          Thread.sleep(maxTime);
                          Runtime rt = Runtime.getRuntime();
                          if(activeTest!=null) {
                            if (MiscUtil.OS_IS_WINDOWS) {
                              rt.exec("taskkill /F /IM " + activeTest.workingDir.getName()+ ".test.exe");
                        } else if (MiscUtil.OS_IS_MAC) {
                          rt.exec("killall -c " + activeTest.workingDir.getName() + ".test");
                        } else {
                          rt.exec("pkill " + activeTest.workingDir.getName() + ".test");
                        }
                          }
                        } catch (InterruptedException e) {
                           Activator.logError(e);
                        } catch (IOException e) {
                          Activator.logError(e);
                        }
           
          }
        }).start();
               
            try {
              RunExternalProcessTask runTestsTask = GoToolManager.getDefault().
                  newRunToolTask(testProcessBuilder, null, new NullProgressMonitor());
               
                ExternalProcessResult processResult = runTestsTask.runProcess();
               
                String stdout = processResult.getStdOutBytes().toString();
                String stderr = processResult.getStdErrBytes().toString();
               
                markErrors(stdout, stderr);
               
            } catch (CoreException e) {
              GoCore.logError("Error executing tests runner for " + activeTest.pkgPath, e);
      }
        }
       
        /**
         * @return
         */
        private ProcessBuilder configureProcess() {
            String[] testCmd = { activeTest.compilerPath,
                                 GoCommandConstants.GO_TEST_COMMAND,
                                 "-test.run="+GoProjectPrefConstants.AUTO_UNIT_TEST_REGEX.get(activeTest.project)
                               };
           
            final ProcessBuilder testProcessBuilder = new ProcessBuilder(testCmd).directory(activeTest.workingDir);
            testProcessBuilder.environment().put(GoEnvironmentConstants.GOROOT, activeTest.goroot);
            testProcessBuilder.environment().put(GoEnvironmentConstants.GOPATH, activeTest.goPath);
            testProcessBuilder.environment().put("PATH", activeTest.path);
            return testProcessBuilder;
        }
       
        private void markErrors(String stdout, String stderr) {
            List<String> lines = StreamAsLines.parseLinesFromOutput(stdout, stderr);
      if (lines.size() > 0) {
        processTestOutput(lines, activeTest);
            }
        }
   
  };
 
  /**
   *
   */
  private GoTestRunner(){
    testRunner = new Thread(runnable, "Go Test Runner");
    testRunner.start();
  }
 
  /**
   * A naive key generator.
   * @param config
   * @return
   */
  private String buildQueueGuardKey(TestConfig config) {
    return config.project.getName()+":"+config.pkgPath;
  }
 
    public static void scheduleTest(final IProject project,    final String compilerPath,
                                final IFile    file,       final String pkgPath,
                                    final File     workingDir, final String goPath,
                                    final String goroot,
                                    final int      errorCount) {
    String path = System.getenv("PATH");
     
      if ( errorCount == 0 && GoProjectPrefConstants.ENABLE_AUTO_UNIT_TEST.get(project)) {
     
        TestConfig t = instance.new TestConfig(project, compilerPath, file, pkgPath, workingDir, goPath, path, goroot);
       
        synchronized (instance.testQueue) {
          String key = instance.buildQueueGuardKey(t);
          if(!instance.queueGuard.containsKey(key)){
            instance.testQueue.add(t);
            instance.queueGuard.put(key, key);
            instance.testQueue.notify();
          }
            }
      }
    }
   
    private static void processTestOutput(List<String> lines, TestConfig activeTest) {
       
      List<String> failedTests = new ArrayList<String>();
     
      try {
        boolean    success = true;
          IContainer parent  = activeTest.file.getParent();
         
          for(int i = 0; i < lines.size(); i++) {
           
            String line = lines.get(i);
           
            if(line.startsWith("panic:")) {
             
              success = false;
              String stackTrace = "";
             
              for (;i < lines.size(); i++) {
                line = lines.get(i);
                stackTrace+=line+"\n";
               
                if (line.matches("(^.*_test.go:[0-9]+.*)") ) {
                  String[] parts = line.split(":");
                 
                  if(parts.length > 0) {
                    String[] fileParts = parts[0].trim().split(File.separatorChar=='\\' ? "\\\\" : File.separator);
                    String filename = fileParts[fileParts.length-1];
                    IResource testFile = parent.findMember(filename);
                     
                        if(parts.length > 1){
                          parts = parts[1].split("\\+");
                        }

                        int lineNo = 1;
                        lineNo = Integer.parseInt(parts[0].trim());
                        MarkerUtilities.addMarker(testFile, lineNo, "A panic occurs during this test.\n"+stackTrace, IMarker.SEVERITY_ERROR);
                  }
                } else if (line.contains("main.main()")) {
                 
                  break;
                } else {
                  continue;
                }
              }
            } else if (line.matches("(^.*_test.go:[0-9]+:[0-9]+:.*)") ) {
              success = false;
              String[] parts = line.split(":");
             
              String message = "";
              if(parts.length > 3) {
                message = parts[3];
              }
             
              int lineNo = 1;
              lineNo = Integer.parseInt(parts[1]);
              IResource testFile = parent.findMember(parts[0].trim());
              MarkerUtilities.addMarker(testFile, lineNo, message, IMarker.SEVERITY_ERROR);
             
            } else if (line.matches("(^.*_test.go:[0-9]+:.*)") ) {
              success = false;
              String[] parts = line.split(":");
             
              String message = "";
              if(parts.length > 2){
                message = parts[2];
              }
             
              int lineNo = 1;
              lineNo = Integer.parseInt(parts[1]);
              IResource testFile = parent.findMember(parts[0].trim());
              MarkerUtilities.addMarker(testFile, lineNo, "Test: "+message, IMarker.SEVERITY_ERROR);
         
            } else if (line.matches("(^.*--- FAIL:.*)") ) {
              success = false;
              failedTests.add(line.substring(0, line.indexOf('('))
                  .replace("--- FAIL: ", "").trim());
            }
          }
         
          if (success) {
            MarkerUtilities.addMarker(parent, 1, parent.getName()
                + " tests were successful at "
                + new Date(), IMarker.SEVERITY_INFO);
          } else {
            // parse test file and mark correctly failed tests
            File        f       = parent.getLocation().toFile();
            CodeContext context = CodeContext.getTestCodeContext(activeTest.project, f);
           
            for (String name:failedTests){
              Function func = context.getFunctionForName(name+"()");
              if(func != null) {
                IResource res = parent.findMember(func.getFile().getName());
                MarkerUtilities.addMarker(res, func.getLine(), name+" failed.", IMarker.SEVERITY_ERROR);
              }
            }
          }
         
        } catch (NumberFormatException e) {
          Activator.logError(e);
        } catch (IOException | CommonException e) {
          Activator.logError(e);
        }
    }
   
    /**
     *
     */
    class TestConfig {
    IProject project;
    String   compilerPath;
        IFile    file;
        String   pkgPath;
        File     workingDir;
        String   goPath;
        String   path;
        String   goroot;
       
        public TestConfig(final IProject project,     final String compilerPath,
                          final IFile    file,        final String pkgPath,
                          final File     workingDir,  final String goPath,
                          final String   path,        final String goroot) {
         
          this.project      = project;
          this.compilerPath = compilerPath;
          this.file         = file;
          this.pkgPath      = pkgPath;
          this.workingDir   = workingDir;
          this.goPath       = goPath;
          this.path         = path;
          this.goroot       = goroot;
         
        }
  }
}

class StreamAsLines {
 
  protected List<String> lines = new ArrayList<String>();
 
  public static List<String> parseLinesFromOutput(String stdout, String stderr) {
    try {
      return parseLinesFromOutput(new StringReader(stdout), new StringReader(stderr));
    } catch (IOException e) {
      throw assertUnreachable(); // StringReader doesn't throw IOException
    }
  }
 
  public static List<String> parseLinesFromOutput(Reader stdoutReader, Reader stderrReader) throws IOException {
    StreamAsLines sal = new StreamAsLines();
    sal.processTestStream(stdoutReader);
    sal.processTestStream(stderrReader);
    return sal.lines;
  }
 
  public void processTestStream(Reader isr) throws IOException {
    String line;
    BufferedReader br = new BufferedReader(isr);
   
    while ((line = br.readLine()) != null) {
      if ("# command-line-arguments".equals(line)){
      } else {
        lines.add(line);
      }
    }
  }
 
}
TOP

Related Classes of com.googlecode.goclipse.builder.GoTestRunner$TestConfig

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.