• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.cts;
18 
19 import java.io.IOException;
20 import java.util.Collection;
21 
22 /**
23  * Represents a runtime session for a test plan, takes charge in running a
24  * plan and the setup&tear-downs.
25  */
26 public class TestSession {
27     private SessionObserver mSessionObserver;
28     private TestSessionLog mSessionLog;
29     private TestDevice mDevice;
30 
31     private int mId;
32     private STATUS mStatus;
33 
34     private static int sIdCounter = 0;
35 
36     enum STATUS {
37         INIT, STARTED, INSTALLING, RUNNING, PAUSED, RESUMED, STOPPED, FINISHED
38     }
39 
40     private int mRequiredDeviceNumber;
41     private boolean mTestStop;
42     private TestSessionThread mTestThread;
43     private boolean mNeedRestartAdbServer;
44     private static boolean mADBServerRestartedMode;
45 
46     /** Running count of tests executed since last reboot. */
47     private static long mTestCount;
48 
TestSession(final TestSessionLog sessionLog, final int requiredDeviceNum)49     public TestSession(final TestSessionLog sessionLog,
50             final int requiredDeviceNum) {
51         mStatus = STATUS.INIT;
52 
53         mNeedRestartAdbServer = false;
54         mADBServerRestartedMode = false;
55         mTestCount = 0;
56         mSessionLog = sessionLog;
57         mDevice = null;
58         mRequiredDeviceNumber = requiredDeviceNum;
59         mTestStop = false;
60         mId = sIdCounter++;
61     }
62 
63     /**
64      * Get the last session ID.
65      *
66      * @return The last session ID.
67      */
getLastSessionId()68     public static int getLastSessionId() {
69         return sIdCounter-1;
70     }
71 
72     /**
73      * Set ADB server restarted mode.
74      */
setADBServerRestartedMode()75     public static void setADBServerRestartedMode() {
76         mADBServerRestartedMode = true;
77     }
78 
79     /**
80      * Reset ADB server restarted mode.
81      */
resetADBServerRestartedMode()82     public static void resetADBServerRestartedMode() {
83         mADBServerRestartedMode = false;
84     }
85 
86     /**
87      * Check if it's in ADB server restarted mode.
88      *
89      * @return If in ADB server restarted mode, return true; else, return false.
90      */
isADBServerRestartedMode()91     public static boolean isADBServerRestartedMode() {
92         return mADBServerRestartedMode;
93     }
94 
95     /**
96      * Increase the test count.
97      */
incTestCount()98     public static void incTestCount() {
99         mTestCount++;
100     }
101 
102     /**
103      * Reset the test count.
104      */
resetTestCount()105     public static void resetTestCount() {
106         mTestCount = 0;
107     }
108 
109     /**
110      * Get the test count recently has been run.
111      *
112      * @return The test count recently has been run.
113      */
getTestCount()114     public static long getTestCount() {
115         return mTestCount;
116     }
117 
118     /**
119      * Check if the test count exceeds the max test count. If the max test count is disabled
120      * (HostConfig.getMaxTestCount() <= 0), this method always returns false.
121      *
122      * @return true, if the max count is enabled and exceeded.
123      */
exceedsMaxCount()124     public static boolean exceedsMaxCount() {
125         final long maxTestCount = HostConfig.getMaxTestCount();
126         return (maxTestCount > 0) && (mTestCount >= maxTestCount);
127     }
128 
129     /**
130      * Get status.
131      *
132      * @return The status.
133      */
getStatus()134     public STATUS getStatus() {
135         return mStatus;
136     }
137 
138     /**
139      * Get device ID.
140      *
141      * @return device ID.
142      */
getDeviceId()143     public String getDeviceId() {
144         if (mDevice == null) {
145             return null;
146         }
147         return mDevice.getSerialNumber();
148     }
149 
150     /**
151      * Get the test device.
152      *
153      * @return the test device.
154      */
getDevice()155     public TestDevice getDevice() {
156         return mDevice;
157     }
158 
159     /**
160      * Get the number of required devices.
161      *
162      * @return The number of required devices.
163      */
getNumOfRequiredDevices()164     public int getNumOfRequiredDevices() {
165         return mRequiredDeviceNumber;
166     }
167 
168     /**
169      * Get ID.
170      *
171      * @return ID.
172      */
getId()173     public int getId() {
174         return mId;
175     }
176 
177     /**
178      * Start the single test with full name.
179      *
180      * @param testFullName The test full name.
181      */
start(final String testFullName)182     public void start(final String testFullName) throws TestNotFoundException,
183             IllegalTestNameException, ADBServerNeedRestartException {
184 
185         if ((testFullName == null) || (testFullName.length() == 0)) {
186             throw new IllegalArgumentException();
187         }
188 
189         // The test full name follows the following rule:
190         //     java_package_name.class_name#method_name.
191         // Other forms will be treated as illegal.
192         if (!testFullName.matches("(\\w+.)+\\w+")) {
193             throw new IllegalTestNameException(testFullName);
194         }
195 
196         Test test = null;
197         TestPackage pkg = null;
198         if (-1 != testFullName.indexOf(Test.METHOD_SEPARATOR)) {
199             test = searchTest(testFullName);
200             if (test == null) {
201                 throw new TestNotFoundException(
202                         "The specific test does not exist: " + testFullName);
203             }
204 
205             mTestThread = new TestSessionThread(this, test);
206             CUIOutputStream.println("start test " + testFullName);
207         } else {
208             pkg = searchTestPackage(testFullName);
209             if (pkg == null) {
210                 throw new TestNotFoundException(
211                         "The specific test package does not exist: " + testFullName);
212             }
213 
214             mTestThread = new TestSessionThread(this, pkg, testFullName);
215             CUIOutputStream.println("start java package " + testFullName);
216         }
217 
218         mStatus = STATUS.STARTED;
219         startImpl();
220     }
221 
222     /**
223      * Implement starting/resuming session.
224      */
startImpl()225     private void startImpl() throws ADBServerNeedRestartException {
226         String resultPath = mSessionLog.getResultPath();
227         if ((resultPath == null) || (resultPath.length() == 0)) {
228             mSessionLog.setStartTime(System.currentTimeMillis());
229         }
230         resetTestCount();
231         mTestThread.start();
232         try {
233             mTestThread.join();
234         } catch (InterruptedException e) {
235             e.printStackTrace();
236         }
237         if (mNeedRestartAdbServer && HostConfig.getMaxTestCount() > 0) {
238             throw new ADBServerNeedRestartException("Need restart ADB server");
239         }
240     }
241 
242     /**
243      * Resume the test session.
244      */
resume()245     public void resume() throws ADBServerNeedRestartException {
246         mStatus = STATUS.RESUMED;
247         mTestThread = new TestSessionThread(this);
248         if (!isADBServerRestartedMode()) {
249             CUIOutputStream.println("resume test plan " + getSessionLog().getTestPlanName()
250                 + " (session id = " + mId + ")");
251         }
252         startImpl();
253     }
254 
255     /**
256      * Search the test with the test full name given among the test
257      * packages contained within this session.
258      *
259      * @param testFullName The full name of the test.
260      * @return The test with the full name given.
261      */
searchTest(final String testFullName)262     private Test searchTest(final String testFullName) {
263         Test test = null;
264         for (TestPackage pkg : mSessionLog.getTestPackages()) {
265             test = pkg.searchTest(testFullName);
266             if (test != null) {
267                 break;
268             }
269         }
270 
271         return test;
272     }
273 
274     /**
275      * Search the test package with the specified java package name.
276      *
277      * @param javaPkgName The java package name.
278      * @return The test package with the specified java package name.
279      */
searchTestPackage(String javaPkgName)280     private TestPackage searchTestPackage(String javaPkgName) {
281         for (TestPackage pkg : mSessionLog.getTestPackages()) {
282             Collection<Test> tests = pkg.getTests();
283             for (Test test : tests) {
284                 String testFullName = test.getFullName();
285                 if (testFullName.startsWith(javaPkgName)) {
286                     //adjust the java package name to make it equal to some java package name
287                     if (testFullName.charAt(javaPkgName.length()) != '.') {
288                         javaPkgName = javaPkgName.substring(0, javaPkgName.lastIndexOf("."));
289                     }
290                     return pkg;
291                 }
292             }
293         }
294 
295         return null;
296     }
297     /**
298      * Start a new test session thread to execute the specific test plan.
299      */
start()300     public void start() throws ADBServerNeedRestartException {
301         mStatus = STATUS.STARTED;
302         mSessionLog.setStartTime(System.currentTimeMillis());
303         mTestThread = new TestSessionThread(this);
304 
305         CUIOutputStream.println("start test plan " + getSessionLog().getTestPlanName());
306         startImpl();
307     }
308 
309     /**
310      * Set observer.
311      *
312      * @param so Session observer.
313      */
setObserver(final SessionObserver so)314     public void setObserver(final SessionObserver so) {
315         mSessionObserver = so;
316     }
317 
318     /**
319      * Print the message by appending the new line mark.
320      *
321      * @param msg The message to be print.
322      */
println(final String msg)323     private void println(final String msg) {
324         if (!mTestStop) {
325             CUIOutputStream.println(msg);
326         }
327     }
328 
329     /**
330      * Set the {@link TestDevice} which will run the test.
331      *
332      * @param device The {@link TestDevice} will run the test.
333      */
setTestDevice(final TestDevice device)334     public void setTestDevice(final TestDevice device) {
335         mDevice = device;
336     }
337 
338     /**
339      * Get the session log of this session.
340      *
341      * @return The session log of this session.
342      */
getSessionLog()343     public TestSessionLog getSessionLog() {
344         return mSessionLog;
345     }
346 
347     /**
348      * Get the test packages contained within this session.
349      *
350      * @return The test packages contained within this session.
351      */
getTestPackages()352     public Collection<TestPackage> getTestPackages() {
353         return mSessionLog.getTestPackages();
354     }
355 
356     /**
357      * The Thread to be run the {@link TestSession}
358      */
359     class TestSessionThread extends Thread {
360         private final int MSEC_PER_SECOND = 1000;
361 
362         private TestSession mTestSession;
363         private Test mTest;
364         private TestPackage mTestPackage;
365         private String mJavaPackageName;
366         private ResultObserver mResultObserver;
367 
TestSessionThread(final TestSession ts)368         public TestSessionThread(final TestSession ts) {
369             mTestSession = ts;
370             mResultObserver = ResultObserver.getInstance();
371         }
372 
TestSessionThread(final TestSession ts, final Test test)373         public TestSessionThread(final TestSession ts, final Test test) {
374             mTestSession = ts;
375             mResultObserver = ResultObserver.getInstance();
376             mTest = test;
377         }
378 
TestSessionThread(final TestSession ts, final TestPackage pkg, final String javaPkgName)379         public TestSessionThread(final TestSession ts,
380                 final TestPackage pkg, final String javaPkgName) {
381             mTestSession = ts;
382             mResultObserver = ResultObserver.getInstance();
383             mTestPackage = pkg;
384             mJavaPackageName = javaPkgName;
385         }
386 
387         /** {@inheritDoc} */
388         @Override
run()389         public void run() {
390             Log.d("Start a test session.");
391             mNeedRestartAdbServer = false;
392             mResultObserver.setTestSessionLog(getSessionLog());
393             mResultObserver.start();
394 
395             try {
396                 if (mTest != null) {
397                     TestPackage pkg = mTest.getTestPackage();
398                     pkg.setSessionThread(this);
399                     pkg.runTest(mDevice, mTest);
400                 } else if (mTestPackage != null) {
401                     mTestPackage.setSessionThread(this);
402                     mTestPackage.run(mDevice, mJavaPackageName, mSessionLog);
403                 } else {
404                     for (TestPackage pkg : mSessionLog.getTestPackages()) {
405                         if (!pkg.isAllTestsRun()) {
406                             pkg.setSessionThread(this);
407                             pkg.run(mDevice, null, mSessionLog);
408                             if (!isAllTestsRun()) {
409                                 if (HostConfig.getMaxTestCount() > 0) {
410                                     // ADB server restart enabled
411                                     markNeedRestartADBServer();
412                                     return;
413                                 }
414                             } else {
415                                 Log.d("All tests have been run.");
416                                 break;
417                             }
418                         }
419                     }
420                     mNeedRestartAdbServer = false;
421                     displayTestResultSummary();
422                 }
423             } catch (IOException e) {
424                 Log.e("Got exception when running the package", e);
425             } catch (DeviceDisconnectedException e) {
426                 Log.e("Device " + e.getMessage() + " disconnected ", null);
427             } catch (ADBServerNeedRestartException e) {
428                 Log.d(e.getMessage());
429                 if (mTest == null) {
430                     markNeedRestartADBServer();
431                     return;
432                 }
433             } catch (InvalidApkPathException e) {
434                 Log.e(e.getMessage(), null);
435             } catch (InvalidNameSpaceException e) {
436                 Log.e(e.getMessage(), null);
437             }
438 
439             long startTime = getSessionLog().getStartTime().getTime();
440             displayTimeInfo(startTime, System.currentTimeMillis());
441 
442             mStatus = STATUS.FINISHED;
443             mTestSession.getSessionLog().setEndTime(System.currentTimeMillis());
444             mSessionObserver.notifyFinished(mTestSession);
445             notifyResultObserver();
446         }
447 
448         /**
449          * Mark need restarting ADB server.
450          */
markNeedRestartADBServer()451         private void markNeedRestartADBServer() {
452             Log.d("mark mNeedRestartAdbServer to true");
453             mNeedRestartAdbServer = true;
454             mStatus = STATUS.FINISHED;
455             notifyResultObserver();
456             return;
457         }
458 
459         /**
460          * Notify result observer.
461          */
notifyResultObserver()462         private void notifyResultObserver() {
463             mResultObserver.notifyUpdate();
464             mResultObserver.finish();
465         }
466 
467         /**
468          * Check if all tests contained in all of the test packages has been run.
469          *
470          * @return If all tests have been run, return true; else, return false.
471          */
isAllTestsRun()472         private boolean isAllTestsRun() {
473             Collection<TestPackage> pkgs = getTestPackages();
474             for (TestPackage pkg : pkgs) {
475                 if (!pkg.isAllTestsRun()) {
476                     return false;
477                 }
478             }
479             return true;
480         }
481 
482         /**
483          * Display the summary of test result.
484          */
displayTestResultSummary()485         private void displayTestResultSummary() {
486             int passNum = mSessionLog.getTestList(CtsTestResult.CODE_PASS).size();
487             int failNum = mSessionLog.getTestList(CtsTestResult.CODE_FAIL).size();
488             int notExecutedNum = mSessionLog.getTestList(CtsTestResult.CODE_NOT_EXECUTED).size();
489             int timeOutNum = mSessionLog.getTestList(CtsTestResult.CODE_TIMEOUT).size();
490             int total = passNum + failNum + notExecutedNum + timeOutNum;
491 
492             println("Test summary:   pass=" + passNum
493                     + "   fail=" + failNum
494                     + "   timeOut=" + timeOutNum
495                     + "   notExecuted=" + notExecutedNum
496                     + "   Total=" + total);
497         }
498 
499         /**
500          * Display the time information of running a test plan.
501          *
502          * @param startTime start time in milliseconds.
503          * @param endTime end time in milliseconds.
504          */
displayTimeInfo(final long startTime, final long endTime)505         private void displayTimeInfo(final long startTime, final long endTime) {
506             long diff = endTime - startTime;
507             long seconds = diff / MSEC_PER_SECOND;
508             long millisec = diff % MSEC_PER_SECOND;
509             println("Time: " + seconds + "." + millisec + "s\n");
510         }
511     }
512 
513     /**
514      * Update test result after executing each test.
515      * During running test, the process may be interrupted. To avoid
516      * test result losing, it's needed to update the test result into
517      * xml file after executing each test, which is done by this observer.
518      * The possible reasons causing interruption to the process include:
519      * <ul>
520      *    <li> Device disconnected
521      *    <li> Run time exception
522      *    <li> System crash
523      *    <li> User action to cause the system exit
524      * </ul>
525      *
526      */
527    static class ResultObserver {
528         static private boolean mFinished = false;
529         static private boolean mNotified = false; //used for avoiding race condition
530         static private boolean mNeedUpdate = true;
531         static private TestSessionLog mSessionLog;
532         static final ResultObserver sInstance = new ResultObserver();
533 
534         private Observer mObserver;
535         /**
536          * Get the static instance.
537          *
538          * @return The static instance.
539          */
getInstance()540         public static final ResultObserver getInstance() {
541             return sInstance;
542         }
543 
544         /**
545          * Set TestSessionLog.
546          *
547          * @param log The TestSessionLog.
548          */
setTestSessionLog(TestSessionLog log)549         public void setTestSessionLog(TestSessionLog log) {
550             mSessionLog = log;
551         }
552 
553         /**
554          * Notify this updating thread to update the test result to xml file.
555          */
notifyUpdate()556         public void notifyUpdate() {
557             if (mObserver != null) {
558                 synchronized (mObserver) {
559                     mNotified = true;
560                     mObserver.notify();
561                 }
562             }
563         }
564 
565         /**
566          * Start the observer.
567          */
start()568         public void start() {
569             mFinished = false;
570             mNeedUpdate = true;
571             mObserver = new Observer();
572             mObserver.start();
573         }
574 
575         /**
576          * Finish updating.
577          */
finish()578         public void finish() {
579             mFinished = true;
580             mNeedUpdate = false;
581             notifyUpdate();
582             try {
583                 mObserver.join();
584                 mObserver = null;
585             } catch (InterruptedException e) {
586             }
587         }
588 
589         /**
590          * Observer which updates the test result to result XML file.
591          *
592          */
593         class Observer extends Thread {
594 
595             /** {@inheritDoc} */
596             @Override
run()597             public void run() {
598                 while (!mFinished) {
599                     try {
600                         synchronized (this) {
601                             if ((!mNotified) && (!mFinished)) {
602                                 wait();
603                             }
604 
605                             mNotified = false;
606                         }
607 
608                         if (mNeedUpdate && (mSessionLog != null)) {
609                             mSessionLog.sessionComplete();
610                         }
611                     } catch (InterruptedException e) {
612                     }
613                 }
614             }
615         }
616     }
617 }
618