package com.jetbrains.env; import com.google.common.collect.Lists; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.text.StringUtil; import com.intellij.testFramework.UsefulTestCase; import com.intellij.util.SystemProperties; import com.intellij.util.ui.UIUtil; import com.jetbrains.python.fixtures.PyTestCase; import org.hamcrest.Matchers; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.junit.Assume; import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.HashSet; import java.util.List; /** * @author traff */ public abstract class PyEnvTestCase extends UsefulTestCase { private static final Logger LOG = Logger.getInstance(PyEnvTestCase.class.getName()); private static final String TAGS_FILE = "tags.txt"; private static final String PYCHARM_PYTHON_ENVS = "PYCHARM_PYTHON_ENVS"; private static final String PYCHARM_PYTHON_VIRTUAL_ENVS = "PYCHARM_PYTHON_VIRTUAL_ENVS"; protected static final boolean IS_ENV_CONFIGURATION = System.getProperty("pycharm.env") != null; public static final boolean RUN_REMOTE = SystemProperties.getBooleanProperty("pycharm.run_remote", false); public static final boolean RUN_LOCAL = SystemProperties.getBooleanProperty("pycharm.run_local", true); /** * Tags that should exist between all tags, available on all interpreters for test to run. * See {@link #PyEnvTestCase(String...)} */ @Nullable private final String[] myRequiredTags; /** * @param requiredTags tags that should exist on some interpreter for this test to run. * if some of these tags do not exist on any interpreter, all test methods would be skipped using * {@link org.junit.Assume}. * See Assume manual. * Check [IDEA-122939] and [TW-25043] as well. */ @SuppressWarnings("JUnitTestCaseWithNonTrivialConstructors") protected PyEnvTestCase(@NotNull final String... requiredTags) { myRequiredTags = requiredTags.length > 0 ? requiredTags.clone() : null; PyTestCase.initPlatformPrefix(); } @Override public void setUp() throws Exception { super.setUp(); if (myRequiredTags != null) { // Ensure all tags exist between available interpreters Assume.assumeThat( "Can't find some tags between all available interpreter, test (all methods) will be skipped", getAvailableTags(), Matchers.hasItems(myRequiredTags) ); } } /** * @return all tags available between all interpreters */ @NotNull private static Collection getAvailableTags() { final Collection allAvailableTags = new HashSet(); for (final String pythonRoot : getPythonRoots()) { allAvailableTags.addAll(loadEnvTags(pythonRoot)); } return allAvailableTags; } @Override protected void invokeTestRunnable(@NotNull final Runnable runnable) throws Exception { if (runInWriteAction()) { UIUtil.invokeAndWaitIfNeeded(new Runnable() { public void run() { ApplicationManager.getApplication().runWriteAction(runnable); } }); } else { runnable.run(); } } @Override protected boolean runInDispatchThread() { return false; } protected boolean runInWriteAction() { return false; } public void runPythonTest(final PyTestTask testTask) { runTest(testTask, getTestName(false)); } public void runTest(@NotNull PyTestTask testTask, @NotNull String testName) { if (notEnvConfiguration()) { fail("Running under teamcity but not by Env configuration. Skipping."); return; } List roots = getPythonRoots(); if (roots.size() == 0) { String msg = testName + ": environments are not defined. Skipping. \nSpecify either " + PYCHARM_PYTHON_ENVS + " or " + PYCHARM_PYTHON_VIRTUAL_ENVS + " environment variable."; LOG.warn(msg); System.out.println(msg); return; } doRunTests(testTask, testName, roots); } protected void doRunTests(PyTestTask testTask, String testName, List roots) { if (RUN_LOCAL) { PyEnvTaskRunner taskRunner = new PyEnvTaskRunner(roots); taskRunner.runTask(testTask, testName); } } public static boolean notEnvConfiguration() { return UsefulTestCase.IS_UNDER_TEAMCITY && !IS_ENV_CONFIGURATION; } public static List getPythonRoots() { List roots = Lists.newArrayList(); String envs = System.getenv(PYCHARM_PYTHON_ENVS); if (envs != null) { roots.addAll(Lists.newArrayList(envs.split(File.pathSeparator))); } String virtualEnvs = System.getenv(PYCHARM_PYTHON_VIRTUAL_ENVS); if (virtualEnvs != null) { roots.addAll(readVirtualEnvRoots(virtualEnvs)); } return roots; } protected static List readVirtualEnvRoots(@NotNull String envs) { List result = Lists.newArrayList(); String[] roots = envs.split(File.pathSeparator); for (String root : roots) { File virtualEnvRoot = new File(root); File[] virtualenvs = virtualEnvRoot.listFiles(); if (virtualenvs != null) { for (File f : virtualenvs) { result.add(f.getAbsolutePath()); } } else { LOG.error(root + " is not a directory of doesn't exist"); } } return result; } public static List loadEnvTags(String env) { List envTags; try { File parent = new File(env); if (parent.isFile()) { parent = parent.getParentFile(); } envTags = com.intellij.openapi.util.io.FileUtil.loadLines(new File(parent, TAGS_FILE)); } catch (IOException e) { envTags = Lists.newArrayList(); } return envTags; } public static String joinStrings(Collection roots, String rootsName) { return roots.size() > 0 ? rootsName + StringUtil.join(roots, ", ") + "\n" : ""; } }