| /******************************************************************************* |
| * Copyright (c) 2000, 2017 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Martin Oberhuber (Wind River) - [306573] Add tests for import from snapshot |
| *******************************************************************************/ |
| package org.eclipse.core.tests.resources.perf; |
| |
| import java.io.ByteArrayInputStream; |
| import java.net.URI; |
| import java.util.Random; |
| import junit.framework.Test; |
| import junit.framework.TestSuite; |
| import org.eclipse.core.resources.*; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.core.tests.harness.PerformanceTestRunner; |
| import org.eclipse.core.tests.resources.ResourceTest; |
| |
| /** |
| * Basic performance calculations for standard workspace operations. |
| */ |
| public class WorkspacePerformanceTest extends ResourceTest { |
| private static final String chars = "abcdefghijklmnopqrstuvwxyz"; |
| static final int REPEATS = 5; |
| private static final int TREE_WIDTH = 10; |
| private static final int DEFAULT_TOTAL_RESOURCES = 10000; |
| |
| private final Random random = new Random(); |
| IFolder testFolder; |
| IProject testProject; |
| |
| public static Test suite() { |
| return new TestSuite(WorkspacePerformanceTest.class); |
| // TestSuite suite = new TestSuite(); |
| // suite.addTest(new WorkspacePerformanceTest("testRefreshProject")); |
| // return suite; |
| } |
| |
| public WorkspacePerformanceTest() { |
| super(); |
| } |
| |
| public WorkspacePerformanceTest(String name) { |
| super(name); |
| } |
| |
| IFolder copyFolder() { |
| IFolder destination = testProject.getFolder("CopyDestination"); |
| try { |
| testFolder.copy(destination.getFullPath(), IResource.NONE, getMonitor()); |
| } catch (CoreException e) { |
| fail("Failed to copy project in performance test", e); |
| } |
| return destination; |
| } |
| |
| /** |
| * Creates a project and fills it with contents |
| */ |
| void createAndPopulateProject(final int totalResources) { |
| try { |
| getWorkspace().run((IWorkspaceRunnable) monitor -> { |
| testProject.create(getMonitor()); |
| testProject.open(getMonitor()); |
| createFolder(testFolder, totalResources); |
| }, getMonitor()); |
| } catch (CoreException e) { |
| fail("Failed to create project in performance test", e); |
| } |
| } |
| |
| private byte[] createBytes(int length) { |
| byte[] bytes = new byte[length]; |
| random.nextBytes(bytes); |
| return bytes; |
| } |
| |
| /** |
| * Creates and returns a folder with lots of contents |
| */ |
| IFolder createFolder(IFolder topFolder, int totalResources) throws CoreException { |
| topFolder.create(IResource.NONE, true, getMonitor()); |
| //tree depth is log of total resource count with the width as the log base |
| int depth = (int) (Math.log(totalResources) / Math.log(TREE_WIDTH)); |
| recursiveCreateChildren(topFolder, depth - 1); |
| return topFolder; |
| } |
| |
| private String createString(int length) { |
| StringBuilder buf = new StringBuilder(length); |
| //fill the string with random characters up to the desired length |
| for (int i = 0; i < length; i++) { |
| buf.append(chars.charAt(random.nextInt(chars.length()))); |
| } |
| return buf.toString(); |
| } |
| |
| /** |
| * Deletes the test project without deleting content, and then recreates |
| * the project without discovering content on disk. This sets us up |
| * for benchmarking performance of refresh local. |
| */ |
| void deleteAndRecreateProject() throws CoreException { |
| //delete without deleting contents |
| testProject.delete(IResource.NEVER_DELETE_PROJECT_CONTENT, null); |
| //recreate project but don't discover content |
| testProject.create(null); |
| testProject.open(IResource.NONE, null); |
| } |
| |
| IFolder moveFolder() { |
| IFolder destination = testFolder.getProject().getFolder("MoveDestination"); |
| try { |
| testFolder.move(destination.getFullPath(), IResource.NONE, getMonitor()); |
| } catch (CoreException e) { |
| fail("Failed to move folder during performance test", e); |
| } |
| return destination; |
| } |
| |
| /** |
| * Create children of the given folder, and recurse to the given depth |
| */ |
| private void recursiveCreateChildren(IFolder parentFolder, int depth) throws CoreException { |
| //create TREE_WIDTH files |
| for (int i = 0; i < TREE_WIDTH; i++) { |
| IFile file = parentFolder.getFile(createString(10)); |
| file.create(new ByteArrayInputStream(createBytes(5000)), IResource.NONE, getMonitor()); |
| } |
| if (depth <= 0) { |
| return; |
| } |
| //create TREE_WIDTH folders |
| for (int i = 0; i < TREE_WIDTH; i++) { |
| IFolder folder = parentFolder.getFolder(createString(6)); |
| folder.create(IResource.NONE, true, getMonitor()); |
| recursiveCreateChildren(folder, depth - 1); |
| } |
| } |
| |
| @Override |
| protected void setUp() throws Exception { |
| testProject = getWorkspace().getRoot().getProject("Project"); |
| testFolder = testProject.getFolder("TopFolder"); |
| } |
| |
| /** |
| * Benchmark test of creating a project and populating it with folders and files. |
| */ |
| public void testCreateResources() { |
| PerformanceTestRunner runner = new PerformanceTestRunner() { |
| @Override |
| protected void setUp() { |
| waitForBackgroundActivity(); |
| } |
| |
| @Override |
| protected void tearDown() throws CoreException { |
| testProject.delete(IResource.FORCE, null); |
| } |
| |
| @Override |
| protected void test() { |
| createAndPopulateProject(DEFAULT_TOTAL_RESOURCES); |
| } |
| }; |
| runner.run(this, REPEATS, 1); |
| } |
| |
| public void testDeleteProject() { |
| //create the project contents |
| PerformanceTestRunner runner = new PerformanceTestRunner() { |
| @Override |
| protected void setUp() { |
| createAndPopulateProject(DEFAULT_TOTAL_RESOURCES); |
| waitForBackgroundActivity(); |
| } |
| |
| @Override |
| protected void test() { |
| try { |
| testProject.delete(IResource.NONE, null); |
| } catch (CoreException e) { |
| fail("Failed to delete project during performance test", e); |
| } |
| } |
| }; |
| runner.run(this, REPEATS, 1); |
| } |
| |
| public void testFolderCopy() { |
| //create the project contents |
| new PerformanceTestRunner() { |
| @Override |
| protected void setUp() { |
| createAndPopulateProject(DEFAULT_TOTAL_RESOURCES); |
| waitForBackgroundActivity(); |
| } |
| |
| @Override |
| protected void tearDown() throws CoreException { |
| testProject.delete(IResource.FORCE, null); |
| } |
| |
| @Override |
| protected void test() { |
| copyFolder(); |
| } |
| }.run(this, REPEATS, 1); |
| } |
| |
| public void testFolderMove() { |
| //create the project contents |
| new PerformanceTestRunner() { |
| @Override |
| protected void setUp() { |
| createAndPopulateProject(DEFAULT_TOTAL_RESOURCES); |
| waitForBackgroundActivity(); |
| } |
| |
| @Override |
| protected void tearDown() throws CoreException { |
| testProject.delete(IResource.FORCE, null); |
| } |
| |
| @Override |
| protected void test() { |
| moveFolder(); |
| } |
| }.run(this, REPEATS, 1); |
| } |
| |
| public void testRefreshProject() { |
| PerformanceTestRunner runner = new PerformanceTestRunner() { |
| @Override |
| protected void setUp() throws CoreException { |
| createAndPopulateProject(50000); |
| deleteAndRecreateProject(); |
| waitForBackgroundActivity(); |
| } |
| |
| @Override |
| protected void tearDown() throws CoreException { |
| testProject.delete(IResource.FORCE, null); |
| } |
| |
| @Override |
| protected void test() { |
| try { |
| testProject.refreshLocal(IResource.DEPTH_INFINITE, null); |
| } catch (CoreException e) { |
| fail("Failed to refresh during testRefreshProject", e); |
| } |
| } |
| }; |
| runner.setFingerprintName("Refresh Project"); |
| runner.run(this, REPEATS, 1); |
| } |
| |
| public void testCloseOpenProject() { |
| // 8 minutes total test time, 400 msec test execution time (*3 inner loops) |
| new PerformanceTestRunner() { |
| @Override |
| protected void setUp() { |
| createAndPopulateProject(50000); |
| waitForBackgroundActivity(); |
| } |
| |
| @Override |
| protected void tearDown() throws CoreException { |
| testProject.delete(IResource.FORCE, null); |
| } |
| |
| @Override |
| protected void test() { |
| try { |
| testProject.close(null); |
| testProject.open(null); |
| } catch (CoreException e) { |
| fail("Failed to close/open during testCloseOpenProject", e); |
| } |
| } |
| }.run(this, REPEATS, 3); |
| } |
| |
| public void testLoadSnapshot() { |
| // 2 minutes total test time, 528 msec test execution time |
| IProject snapProject = getWorkspace().getRoot().getProject("SnapProject"); |
| ensureExistsInWorkspace(snapProject, true); |
| final URI snapshotLocation = snapProject.getFile("snapshot.zip").getLocationURI(); |
| createAndPopulateProject(50000); |
| waitForBackgroundActivity(); |
| try { |
| testProject.saveSnapshot(IProject.SNAPSHOT_TREE, snapshotLocation, null); |
| testProject.delete(IResource.FORCE, null); |
| } catch (CoreException e) { |
| fail("Failed to create snapshot during testLoadSnapshot"); |
| } |
| waitForBackgroundActivity(); |
| new PerformanceTestRunner() { |
| @Override |
| protected void setUp() { |
| } |
| |
| @Override |
| protected void tearDown() throws CoreException { |
| testProject.delete(IResource.FORCE, null); |
| } |
| |
| @Override |
| protected void test() { |
| try { |
| testProject.create(null); |
| testProject.loadSnapshot(IProject.SNAPSHOT_TREE, snapshotLocation, null); |
| testProject.open(null); |
| } catch (CoreException e) { |
| fail("Failed to load snapshot during testLoadSnapshot", e); |
| } |
| } |
| }.run(this, REPEATS, 1); |
| } |
| |
| /** |
| * Waits until background activity settles down before running a performance test. |
| * |
| */ |
| public void waitForBackgroundActivity() { |
| waitForSnapshot(); |
| waitForRefresh(); |
| waitForBuild(); |
| } |
| |
| /** |
| * Wait for snapshot to complete by running and joining a workspace modification job. |
| * This job will get queued to run behind any scheduled snapshot job. |
| */ |
| private void waitForSnapshot() { |
| Job wait = new Job("Wait") { |
| @Override |
| protected IStatus run(IProgressMonitor monitor) { |
| return Status.OK_STATUS; |
| } |
| }; |
| wait.setRule(getWorkspace().getRoot()); |
| wait.schedule(); |
| try { |
| wait.join(); |
| } catch (InterruptedException e) { |
| //ignore interruption |
| } |
| } |
| } |