Home | History | Annotate | Download | only in sampleProjects
      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