1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.0 (the "License"); you 5 * may not use this file except in compliance with the License. You may obtain a 6 * copy of the License at 7 * 8 * http://www.eclipse.org/org/documents/epl-v10.php 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 package com.android.ide.eclipse.tests.functests.sampleProjects; 17 18 import com.android.SdkConstants; 19 import com.android.ide.eclipse.adt.AdtUtils; 20 import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectCreator; 21 import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState; 22 import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState.Mode; 23 import com.android.ide.eclipse.tests.SdkLoadingTestCase; 24 import com.android.sdklib.IAndroidTarget; 25 26 import org.eclipse.core.resources.IMarker; 27 import org.eclipse.core.resources.IProject; 28 import org.eclipse.core.resources.IResource; 29 import org.eclipse.core.resources.IResourceChangeEvent; 30 import org.eclipse.core.resources.IResourceChangeListener; 31 import org.eclipse.core.resources.IResourceDelta; 32 import org.eclipse.core.resources.IResourceDeltaVisitor; 33 import org.eclipse.core.resources.ResourcesPlugin; 34 import org.eclipse.core.runtime.CoreException; 35 import org.eclipse.core.runtime.NullProgressMonitor; 36 import org.eclipse.jface.operation.IRunnableContext; 37 import org.eclipse.jface.operation.IRunnableWithProgress; 38 import org.eclipse.swt.widgets.Display; 39 40 import java.io.File; 41 import java.lang.reflect.InvocationTargetException; 42 import java.util.logging.Level; 43 import java.util.logging.Logger; 44 45 /** 46 * Test case that verifies all SDK sample projects can be imported, and built in 47 * Eclipse. 48 * <p/> 49 * TODO: add support for deploying apps onto emulator and verifying successful 50 * execution there 51 * 52 */ 53 public class SampleProjectTest extends SdkLoadingTestCase { 54 55 private static final Logger sLogger = Logger.getLogger(SampleProjectTest.class.getName()); 56 57 /** 58 * Finds all samples projects in set SDK and verify they can be built in Eclipse. 59 * <p/> 60 * TODO: add install and run on emulator test 61 * @throws CoreException 62 */ 63 public void testSamples() throws CoreException { 64 // TODO: For reporting purposes, it would be better if a separate test success or failure 65 // could be reported for each sample 66 IAndroidTarget[] targets = getSdk().getTargets(); 67 for (IAndroidTarget target : targets) { 68 doTestSamplesForTarget(target); 69 } 70 } 71 72 private void doTestSamplesForTarget(IAndroidTarget target) throws CoreException { 73 String path = target.getPath(IAndroidTarget.SAMPLES); 74 File samples = new File(path); 75 if (samples.isDirectory()) { 76 File[] files = samples.listFiles(); 77 for (File file : files) { 78 if (file.isDirectory()) { 79 doTestSampleProject(file.getName(), file.getAbsolutePath(), target); 80 } 81 } 82 } 83 } 84 85 /** 86 * Tests the sample project with the given name 87 * 88 * @param target - SDK target of project 89 * @param name - name of sample project to test 90 * @param path - absolute file system path 91 * @throws CoreException 92 */ 93 private void doTestSampleProject(String name, String path, IAndroidTarget target) 94 throws CoreException { 95 IProject iproject = null; 96 try { 97 sLogger.log(Level.INFO, String.format("Testing sample %s for target %s", name, 98 target.getName())); 99 100 prepareProject(path, target); 101 102 IRunnableContext context = new IRunnableContext() { 103 @Override 104 public void run(boolean fork, boolean cancelable, IRunnableWithProgress runnable) 105 throws InvocationTargetException, InterruptedException { 106 runnable.run(new NullProgressMonitor()); 107 } 108 }; 109 NewProjectWizardState state = new NewProjectWizardState(Mode.SAMPLE); 110 state.projectName = name; 111 state.target = target; 112 state.packageName = "com.android.samples"; 113 state.activityName = name; 114 state.applicationName = name; 115 state.chosenSample = new File(path); 116 state.useDefaultLocation = false; 117 state.createActivity = false; 118 119 NewProjectCreator creator = new NewProjectCreator(state, context); 120 creator.createAndroidProjects(); 121 iproject = validateProjectExists(name); 122 validateNoProblems(iproject); 123 } 124 catch (CoreException e) { 125 sLogger.log(Level.SEVERE, 126 String.format("Unexpected exception when creating sample project %s " + 127 "for target %s", name, target.getName())); 128 throw e; 129 } finally { 130 if (iproject != null) { 131 iproject.delete(false, true, new NullProgressMonitor()); 132 } 133 } 134 } 135 136 private void prepareProject(String path, IAndroidTarget target) { 137 if (target.getVersion().isPreview()) { 138 // need to explicitly set preview's version in manifest for project to compile 139 final String manifestPath = path + File.separatorChar + 140 SdkConstants.FN_ANDROID_MANIFEST_XML; 141 AndroidManifestWriter manifestWriter = 142 AndroidManifestWriter.parse(manifestPath); 143 assertNotNull(String.format("could not read manifest %s", manifestPath), 144 manifestWriter); 145 assertTrue(manifestWriter.setMinSdkVersion(target.getVersion().getApiString())); 146 } 147 } 148 149 private IProject validateProjectExists(String name) { 150 IProject iproject = getIProject(name); 151 assertTrue(String.format("%s project not created", name), iproject.exists()); 152 assertTrue(String.format("%s project not opened", name), iproject.isOpen()); 153 return iproject; 154 } 155 156 private IProject getIProject(String name) { 157 IProject iproject = ResourcesPlugin.getWorkspace().getRoot() 158 .getProject(name); 159 return iproject; 160 } 161 162 private void validateNoProblems(IProject iproject) throws CoreException { 163 waitForBuild(iproject); 164 165 boolean hasErrors = false; 166 StringBuilder failureBuilder = new StringBuilder(String.format("%s project has errors:", 167 iproject.getName())); 168 IMarker[] markers = iproject.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE); 169 if (markers != null && markers.length > 0) { 170 // the project has marker(s). even though they are "problem" we 171 // don't know their severity. so we loop on them and figure if they 172 // are warnings or errors 173 for (IMarker m : markers) { 174 int s = m.getAttribute(IMarker.SEVERITY, -1); 175 if (s == IMarker.SEVERITY_ERROR) { 176 hasErrors = true; 177 failureBuilder.append("\n"); 178 failureBuilder.append(m.getAttribute(IMarker.MESSAGE, "")); 179 } 180 } 181 } 182 failureBuilder.append("Project location: " + AdtUtils.getAbsolutePath(iproject)); 183 assertFalse(failureBuilder.toString(), hasErrors); 184 } 185 186 /** 187 * Waits for build to complete. 188 * 189 * @param iproject 190 */ 191 private void waitForBuild(final IProject iproject) { 192 193 final BuiltProjectDeltaVisitor deltaVisitor = new BuiltProjectDeltaVisitor(iproject); 194 IResourceChangeListener newBuildListener = new IResourceChangeListener() { 195 196 @Override 197 public void resourceChanged(IResourceChangeEvent event) { 198 try { 199 event.getDelta().accept(deltaVisitor); 200 } 201 catch (CoreException e) { 202 fail(); 203 } 204 } 205 206 }; 207 iproject.getWorkspace().addResourceChangeListener(newBuildListener, 208 IResourceChangeEvent.POST_BUILD); 209 210 // poll build listener to determine when build is done 211 // loop max of 1200 times * 50 ms = 60 seconds 212 final int maxWait = 1200; 213 for (int i=0; i < maxWait; i++) { 214 if (deltaVisitor.isProjectBuilt()) { 215 return; 216 } 217 try { 218 Thread.sleep(50); 219 } 220 catch (InterruptedException e) { 221 // ignore 222 } 223 if (Display.getCurrent() != null) { 224 Display.getCurrent().readAndDispatch(); 225 } 226 } 227 228 sLogger.log(Level.SEVERE, "expected build event never happened?"); 229 fail(String.format("Expected build event never happened for %s", iproject.getName())); 230 } 231 232 /** 233 * Scans a given IResourceDelta looking for a "build event" change for given IProject 234 * 235 */ 236 private class BuiltProjectDeltaVisitor implements IResourceDeltaVisitor { 237 238 private IProject mIProject; 239 private boolean mIsBuilt; 240 241 public BuiltProjectDeltaVisitor(IProject iproject) { 242 mIProject = iproject; 243 mIsBuilt = false; 244 } 245 246 @Override 247 public boolean visit(IResourceDelta delta) { 248 if (mIProject.equals(delta.getResource())) { 249 setBuilt(true); 250 return false; 251 } 252 return true; 253 } 254 255 private synchronized void setBuilt(boolean b) { 256 mIsBuilt = b; 257 } 258 259 public synchronized boolean isProjectBuilt() { 260 return mIsBuilt; 261 } 262 } 263 } 264