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.ide.eclipse.adt.AdtUtils;
     19 import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectCreator;
     20 import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState;
     21 import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState.Mode;
     22 import com.android.ide.eclipse.tests.SdkTestCase;
     23 import com.android.sdklib.IAndroidTarget;
     24 import com.android.sdklib.SdkConstants;
     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 SdkTestCase {
     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                 public void run(boolean fork, boolean cancelable, IRunnableWithProgress runnable)
    104                         throws InvocationTargetException, InterruptedException {
    105                     runnable.run(new NullProgressMonitor());
    106                 }
    107             };
    108             NewProjectWizardState state = new NewProjectWizardState(Mode.SAMPLE);
    109             state.projectName = name;
    110             state.target = target;
    111             state.packageName = "com.android.samples";
    112             state.activityName = name;
    113             state.applicationName = name;
    114             state.chosenSample = new File(path);
    115             state.useDefaultLocation = false;
    116             state.createActivity = false;
    117 
    118             NewProjectCreator creator = new NewProjectCreator(state, context);
    119             creator.createAndroidProjects();
    120             iproject = validateProjectExists(name);
    121             validateNoProblems(iproject);
    122         }
    123         catch (CoreException e) {
    124             sLogger.log(Level.SEVERE,
    125                     String.format("Unexpected exception when creating sample project %s " +
    126                             "for target %s", name, target.getName()));
    127             throw e;
    128         } finally {
    129             if (iproject != null) {
    130                 iproject.delete(false, true, new NullProgressMonitor());
    131             }
    132         }
    133     }
    134 
    135     private void prepareProject(String path, IAndroidTarget target) {
    136         if (target.getVersion().isPreview()) {
    137             // need to explicitly set preview's version in manifest for project to compile
    138             final String manifestPath = path + File.separatorChar +
    139                     SdkConstants.FN_ANDROID_MANIFEST_XML;
    140             AndroidManifestWriter manifestWriter =
    141                 AndroidManifestWriter.parse(manifestPath);
    142             assertNotNull(String.format("could not read manifest %s", manifestPath),
    143                     manifestWriter);
    144             assertTrue(manifestWriter.setMinSdkVersion(target.getVersion().getApiString()));
    145         }
    146     }
    147 
    148     private IProject validateProjectExists(String name) {
    149         IProject iproject = getIProject(name);
    150         assertTrue(String.format("%s project not created", name), iproject.exists());
    151         assertTrue(String.format("%s project not opened", name), iproject.isOpen());
    152         return iproject;
    153     }
    154 
    155     private IProject getIProject(String name) {
    156         IProject iproject = ResourcesPlugin.getWorkspace().getRoot()
    157                 .getProject(name);
    158         return iproject;
    159     }
    160 
    161     private void validateNoProblems(IProject iproject) throws CoreException {
    162         waitForBuild(iproject);
    163 
    164         boolean hasErrors = false;
    165         StringBuilder failureBuilder = new StringBuilder(String.format("%s project has errors:",
    166                 iproject.getName()));
    167         IMarker[] markers = iproject.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
    168         if (markers != null && markers.length > 0) {
    169             // the project has marker(s). even though they are "problem" we
    170             // don't know their severity. so we loop on them and figure if they
    171             // are warnings or errors
    172             for (IMarker m : markers) {
    173                 int s = m.getAttribute(IMarker.SEVERITY, -1);
    174                 if (s == IMarker.SEVERITY_ERROR) {
    175                     hasErrors = true;
    176                     failureBuilder.append("\n");
    177                     failureBuilder.append(m.getAttribute(IMarker.MESSAGE, ""));
    178                 }
    179             }
    180         }
    181         failureBuilder.append("Project location: " + AdtUtils.getAbsolutePath(iproject));
    182         assertFalse(failureBuilder.toString(), hasErrors);
    183     }
    184 
    185     /**
    186      * Waits for build to complete.
    187      *
    188      * @param iproject
    189      */
    190     private void waitForBuild(final IProject iproject) {
    191 
    192         final BuiltProjectDeltaVisitor deltaVisitor = new BuiltProjectDeltaVisitor(iproject);
    193         IResourceChangeListener newBuildListener = new IResourceChangeListener() {
    194 
    195             public void resourceChanged(IResourceChangeEvent event) {
    196                 try {
    197                     event.getDelta().accept(deltaVisitor);
    198                 }
    199                 catch (CoreException e) {
    200                     fail();
    201                 }
    202             }
    203 
    204         };
    205         iproject.getWorkspace().addResourceChangeListener(newBuildListener,
    206           IResourceChangeEvent.POST_BUILD);
    207 
    208         // poll build listener to determine when build is done
    209         // loop max of 1200 times * 50 ms = 60 seconds
    210         final int maxWait = 1200;
    211         for (int i=0; i < maxWait; i++) {
    212             if (deltaVisitor.isProjectBuilt()) {
    213                 return;
    214             }
    215             try {
    216                 Thread.sleep(50);
    217             }
    218             catch (InterruptedException e) {
    219                 // ignore
    220             }
    221            if (Display.getCurrent() != null) {
    222                Display.getCurrent().readAndDispatch();
    223            }
    224         }
    225 
    226         sLogger.log(Level.SEVERE, "expected build event never happened?");
    227         fail(String.format("Expected build event never happened for %s", iproject.getName()));
    228     }
    229 
    230     /**
    231      * Scans a given IResourceDelta looking for a "build event" change for given IProject
    232      *
    233      */
    234     private class BuiltProjectDeltaVisitor implements IResourceDeltaVisitor {
    235 
    236         private IProject mIProject;
    237         private boolean  mIsBuilt;
    238 
    239         public BuiltProjectDeltaVisitor(IProject iproject) {
    240             mIProject = iproject;
    241             mIsBuilt = false;
    242         }
    243 
    244         public boolean visit(IResourceDelta delta) {
    245             if (mIProject.equals(delta.getResource())) {
    246                 setBuilt(true);
    247                 return false;
    248             }
    249             return true;
    250         }
    251 
    252         private synchronized void setBuilt(boolean b) {
    253             mIsBuilt = b;
    254         }
    255 
    256         public synchronized boolean isProjectBuilt() {
    257             return mIsBuilt;
    258         }
    259     }
    260 }
    261