diff options
author | Yongqin Liu <yongqin.liu@linaro.org> | 2015-01-03 17:46:21 +0800 |
---|---|---|
committer | Yongqin Liu <yongqin.liu@linaro.org> | 2015-01-03 17:46:21 +0800 |
commit | cf7013d6e23f0a0da3bcae5fb9d8e20639b1d21f (patch) | |
tree | 4888505a53fc2070d376945391ae48bbee333166 |
first commit
Signed-off-by: Yongqin Liu <yongqin.liu@linaro.org>
196 files changed, 18326 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e6b6fb3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +.idea +.testrepository +dist +lava_test.egg-info +*~ +*.tmp +*.py[co] +lava_android_test.egg-info +.bzrignore diff --git a/.gitreview b/.gitreview new file mode 100644 index 0000000..aea5df9 --- /dev/null +++ b/.gitreview @@ -0,0 +1,4 @@ +[gerrit] +host=git.linaro.org +port=29418 +project=lava/lava-android-test diff --git a/.project b/.project new file mode 100644 index 0000000..4766155 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>lava-android-test</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.python.pydev.PyDevBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.python.pydev.pythonNature</nature> + </natures> +</projectDescription> diff --git a/.pydevproject b/.pydevproject new file mode 100644 index 0000000..0466f44 --- /dev/null +++ b/.pydevproject @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<?eclipse-pydev version="1.0"?> + +<pydev_project> + <pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property> + <pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property> + <pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH"> +<path>/lava-android-test</path> +</pydev_pathproperty> +</pydev_project> @@ -0,0 +1,676 @@ + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. + diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..aaf3983 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,17 @@ +include COPYING +include README +include .testr.conf +include lava_android_test/test_definitions/monkey/* +include lava_android_test/test_definitions/monkey_long_run/* +include lava_android_test/test_definitions/android-0xbenchmark/* +include lava_android_test/test_definitions/busybox/* +include lava_android_test/test_definitions/cts/* +include lava_android_test/test_definitions/glmark2/* +include lava_android_test/test_definitions/gatortest/* +include lava_android_test/test_definitions/usbhardware/* +include lava_android_test/test_definitions/ime/* +include lava_android_test/test_definitions/pm_qa/* +include lava_android_test/test_definitions/shells/* +include lava_android_test/test_definitions/hostshells/* +include lava_android_test/test_definitions/methanol/* + @@ -0,0 +1,11 @@ +Lava-test is an automated testing framework with pre-defined tests and the +ability to define additional tests as needed. Tests can be +automatically installed, executed, and the results can be parsed and +uploaded to an external server. + +External dependency +------------------- +The following debian packages are needed: +* python-apt +* usbutils +* python-testrepository - for running unit tests
\ No newline at end of file diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/__init__.py b/build/lib.linux-x86_64-2.7/lava_android_test/__init__.py new file mode 100644 index 0000000..7074800 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/__init__.py @@ -0,0 +1,16 @@ +# Copyright (c) 2010, 2011 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +__version__ = (0, 16, 3, "final", 0) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/adb.py b/build/lib.linux-x86_64-2.7/lava_android_test/adb.py new file mode 100644 index 0000000..5bedb8c --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/adb.py @@ -0,0 +1,401 @@ +# Copyright (c) 2011 - 2012 Linaro +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import re +import subprocess +import tempfile +import threading +import time + +from Queue import Queue +from lava_android_test.config import get_config + +config = get_config() + + +class ADB(object): + ERR_CHMOD = 260 + ERR_WRAPPER = 300 + ERR_SHELL = 350 + ERR_PUSH = 400 + ERR_INSTALL = 450 + ERR_UNINSTALL = 450 + adb = 'adb' + serial = None + + target_dir = config.tempdir_android + + def __init__(self, serial=None, quiet=True): + self.cmdExecutor = CommandExecutor(quiet) + if serial is not None: + self.serial = serial + self.adb = 'adb -s %s' % serial + else: + self.serial = self.get_serial() + + def get_serial(self): + if not self.serial: + serial_ary = self.run_cmd_host('adb get-serialno')[1] + serial = serial_ary[0].strip() + if not serial or serial == 'unknown': + return '' + else: + return serial + else: + return self.serial + + def push(self, source=None, target=None): + if source is None: + return (-1, None) + + target_dir = self.target_dir + if target is None: + target = os.path.join(self.target_dir, os.path.basename(source)) + else: + target_dir = os.path.dirname(target) + + self.cmdExecutor.run('%s shell mkdir %s' % (self.adb, target_dir)) + s = self.cmdExecutor.run('%s push %s %s' % (self.adb, source, target)) + ret = s.returncode + return (ret, target) + + def pull(self, source=None, target=None): + if source is None: + return -1 + + if target is None: + cmd = '%s pull %s' % (self.adb, source) + else: + cmd = '%s pull %s %s' % (self.adb, source, target) + s = self.cmdExecutor.run(cmd) + return s.returncode + + def shell(self, command=None, stdout=None, stderr=None): + if command is None: + return 0 + tmpdir = config.tempdir_host + if not os.path.exists(tmpdir): + os.mkdir(tmpdir) + (tmpshell, tmpshell_name) = tempfile.mkstemp(suffix='.sh', + prefix='lava-android-test', + dir=tmpdir) + tmpfile_path = os.path.join(tmpdir, tmpshell_name) + os.write(tmpshell, '#/system/bin/sh\n') + os.write(tmpshell, 'base=/system\n') + os.write(tmpshell, ("export PATH=/sbin:/vendor/bin:/system/sbin:" + "/system/bin:/system/xbin\n")) + org_cmd = command + if stdout is not None: + command = '%s 1>>%s' % (command, stdout) + if stderr is not None: + command = '%s 2>>%s' % (command, stderr) + + os.write(tmpshell, command + '\n') + os.write(tmpshell, 'RET_CODE=$?\n') + if stdout is not None: + os.write(tmpshell, + 'echo ANDROID_TEST_COMMAND="%s">>%s\n' % (org_cmd, stdout)) + os.write(tmpshell, + 'echo ANDROID_TEST_RET_CODE=${RET_CODE} >>%s\n' % (stdout)) + + os.write(tmpshell, 'echo RET_CODE=${RET_CODE}\n') + os.close(tmpshell) + + (ret_code, target_path) = self.push(tmpfile_path) + os.remove(tmpfile_path) + if ret_code != 0: + return self.ERR_PUSH + + s = self.cmdExecutor.run( + '%s shell chmod 777 %s' % (self.adb, target_path)) + ret_code = s.returncode + if ret_code != 0: + return self.ERR_CHMOD + ret_code + #check the whether the output is empty + if len(s.stdout) != 0: + return self.ERR_CHMOD + + self.cmdExecutor.say('Begin to execute shell command: %s' % command) + s = self.cmdExecutor.run('%s shell %s' % (self.adb, target_path)) + ret_code = s.returncode + if ret_code != 0: + return self.ERR_SHELL + ret_code + output = s.stdout + ret_code_line = output[len(output) - 1] + self.cmdExecutor.run('%s shell rm %s' % (self.adb, target_path)) + + ret_code_pattern = "^RET_CODE=(?P<ret_code>\d+)\s*$" + pat = re.compile(ret_code_pattern) + match = pat.search(ret_code_line) + if not match: + return self.ERR_SHELL + else: + data = match.groupdict() + return int(data['ret_code'], 10) + + def exists(self, path): + ret_code = self.shell("ls %s" % path) + return ret_code == 0 + + def installapk(self, apkpath): + cmd = '%s install %s' % (self.adb, apkpath) + s = self.cmdExecutor.run(cmd) + ret_code = s.returncode + if ret_code != 0: + return self.ERR_INSTALL + ret_code + return 0 + + def uninstallapk(self, package): + cmd = '%s uninstall %s' % (self.adb, package) + s = self.cmdExecutor.run(cmd) + ret_code = s.returncode + if ret_code != 0: + return self.ERR_UNINSTALL + ret_code + return 0 + + def makedirs(self, path): + parent_path = os.path.dirname(path) + if parent_path == '/' or self.exists(parent_path): + return self.shell("mkdir %s" % path) + else: + ret = self.makedirs(parent_path) + if ret == 0: + return self.shell("mkdir %s" % path) + else: + return ret + + def rmtree(self, dirpath): + ret_code = self.shell("rm -r %s" % dirpath) + return ret_code + + def move(self, srcdir, destdir): + if srcdir is None: + return 0 + if destdir is None: + return 0 + ret_code = self.shell("mv %s %s" % (srcdir, destdir)) + return ret_code + + def copy(self, source_file, target_file): + if source_file is None: + return 0 + if target_file is None: + return 0 + if not self.exists(source_file): + return 0 + + ret_code = self.shell("dd if=%s of=%s" % (source_file, target_file)) + return ret_code + + def listdir(self, dirpath): + if self.exists(dirpath): + (ret_code, output) = self.run_cmd_host( + '%s shell ls %s ' % (self.adb, dirpath)) + return (ret_code, output) + else: + return (1, None) + + def read_file(self, filepath): + tmpfile_name = tempfile.mkstemp( + prefix='read_file_', dir=config.tempdir_host)[1] + ret_code = self.pull(filepath, tmpfile_name) + if ret_code != 0: + return None + data = None + try: + with open(tmpfile_name) as fd: + data = fd.read() + finally: + os.remove(tmpfile_name) + return data + + def get_shellcmdoutput(self, cmd=None, quiet=True): + return self.get_shellcmdoutput_with_stderr(cmd=cmd, quiet=True)[0:2] + + def run_adb_cmd(self, cmd, quiet=True): + return self.run_adb_cmd_with_stderr(cmd=cmd, quiet=quiet)[0:2] + + def run_cmd_host(self, cmd, quiet=True): + return self.run_cmd_host_with_stderr(cmd, quiet=quiet)[0:2] + + def get_shellcmdoutput_with_stderr(self, cmd=None, quiet=True): + if cmd is None: + return None + return self.run_adb_cmd_with_stderr(cmd='shell %s' % cmd, quiet=quiet) + + def run_adb_cmd_with_stderr(self, cmd, quiet=True): + if not self.isDeviceConnected(): + print ("Reconnect adb connection of device(%s) " + "for running command[%s]") % (self.get_serial(), cmd) + if not self.reconnect(): + raise Exception('Failed to connect the device(%s)' % ( + self.get_serial())) + return self.run_cmd_host_with_stderr(cmd='%s %s' % (self.adb, cmd), + quiet=quiet) + + def run_cmd_host_with_stderr(self, cmd, quiet=True): + result = self.cmdExecutor.run(cmd, quiet=quiet) + return (result.returncode, result.stdout, result.stderr) + + def run_adb_shell_for_test(self, cmd, stdoutlog=None, + stderrlog=None, quiet=False): + (ret_code, stdout, stderr) = self.get_shellcmdoutput_with_stderr( + cmd=cmd, + quiet=quiet) + if ret_code != 0: + return ret_code + self.push_stream_to_device(stdout, stdoutlog) + self.push_stream_to_device(stderr, stderrlog) + return ret_code + + def push_stream_to_device(self, stream_lines, path): + if self.serial: + android_info = 'android(%s)' % self.serial + else: + android_info = 'android' + + if not self.isDeviceConnected(): + if not self.reconnect(): + raise Exception('Failed to pull file(%s) to %s, ' + 'because the device is not connected' % ( + path, android_info)) + basename = os.path.basename(path) + tmp_path = os.path.join(config.tempdir_host, basename) + if self.exists(path): + retcode = self.pull(path, tmp_path) + if retcode != 0: + raise Exception( + 'Failed to pull file(%s) to %s' % (path, android_info)) + + with open(tmp_path, 'a') as tmp_fd: + tmp_fd.writelines(stream_lines) + tmp_fd.close() + + if self.push(tmp_path, path)[1] is None: + raise Exception( + 'Failed to pull file(%s) to %s' % (path, android_info)) + os.remove(tmp_path) + + def devices(self): + return self.run_cmd_host('%s devices' % self.adb) + + def isDeviceConnected(self): + lines = self.run_cmd_host('%s get-state' % self.adb)[1] + for line in lines: + if 'device' in line: + return True + return False + + def connect(self): + if self.serial: + self.run_cmd_host('adb connect %s' % self.serial, quiet=False) + return self.isDeviceConnected() + return False + + def disconnect(self): + if self.serial: + self.run_cmd_host('adb disconnect %s' % self.serial, quiet=False) + return not self.isDeviceConnected() + return False + + def reconnect(self): + for i in range(1, 5): + print "LAVA: try to reconnect the device(%s) %i/5 times" % ( + self.serial, i) + if self.disconnect(): + time.sleep(2) + if self.connect(): + return True + time.sleep(5) + return False + + +class CommandExecutor(object): + def __init__(self, quiet=True): + self._queue = Queue() + self.quiet = quiet + self.stdout = [] + self.stderr = [] + + def say(self, text, *args, **kwargs): + if not self.quiet: + print "LAVA:", text.format(*args, **kwargs) + + def display_subprocess_output(self, stream_name, line): + if stream_name == 'stdout': + self.say('(stdout) {0}', line.rstrip()) + elif stream_name == 'stderr': + self.say('(stderr) {0}', line.rstrip()) + + def _drain_queue(self): + while True: + args = self._queue.get() + if args is None: + break + self.display_subprocess_output(*args) + + def _read_stream(self, stream, stream_name): + if stream is None: + return + for line in iter(stream.readline, ''): + output_line = (stream_name, line) + self._queue.put(output_line) + if stream_name == 'stdout': + self.stdout.append(line) + elif stream_name == 'stderr': + self.stderr.append(line) + + def run(self, cmd, quiet=True): + self.quiet = quiet + self.stdout = [] + self.stderr = [] + self.say("Begin to execute command: %s" % + cmd.replace('{', '{{').replace('}', '}}')) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + shell=True) + + stdout_reader = threading.Thread( + target=self._read_stream, args=(proc.stdout, "stdout")) + stderr_reader = threading.Thread( + target=self._read_stream, args=(proc.stderr, "stderr")) + ui_printer = threading.Thread( + target=self._drain_queue) + + ui_printer.start() + stdout_reader.start() + stderr_reader.start() + try: + proc.wait() + except KeyboardInterrupt: + proc.kill() + finally: + stdout_reader.join() + stderr_reader.join() + self._queue.put(None) + ui_printer.join() + return CommandResult(proc.returncode, self.stdout, self.stderr) + + +class CommandResult(object): + def __init__(self, returncode, stdout=[], stderr=[]): + self.returncode = returncode + self.stdout = stdout + self.stderr = stderr diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/api.py b/build/lib.linux-x86_64-2.7/lava_android_test/api.py new file mode 100644 index 0000000..624422e --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/api.py @@ -0,0 +1,44 @@ +""" +Public API for extending Abrek +""" +from abc import abstractmethod + + +class ITest(object): + """ + Abrek test. + + Something that can be installed and invoked by abre. + """ + + @abstractmethod + def install(self): + """ + Install the test suite. + + This creates an install directory under the user's XDG_DATA_HOME + directory to mark that the test is installed. The installer's + install() method is then called from this directory to complete any + test specific install that may be needed. + """ + + @abstractmethod + def uninstall(self): + """ + Uninstall the test suite. + + Uninstalling just recursively removes the test specific directory under + the user's XDG_DATA_HOME directory. This will both mark the test as + removed, and clean up any files that were downloaded or installed under + that directory. Dependencies are intentionally not removed by this. + """ + + @abstractmethod + def run(self, quiet=False): + # TODO: Document me + pass + + @abstractmethod + def parse(self, resultname): + # TODO: Document me + pass diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/commands.py b/build/lib.linux-x86_64-2.7/lava_android_test/commands.py new file mode 100644 index 0000000..eb46c78 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/commands.py @@ -0,0 +1,935 @@ +# Copyright (c) 2011, 2012 Linaro +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +import base64 +import os +import re +import urlparse +import versiontools +import zipfile + +from tempfile import mkdtemp +from uuid import uuid4 + +from lava_tool.interface import Command as LAVACommand +from lava_tool.interface import LavaCommandError +from linaro_dashboard_bundle.io import DocumentIO + +from lava_android_test.adb import ADB +from lava_android_test.config import get_config +from lava_android_test.provider import TestProvider +from lava_android_test.repository import GitRepository +from lava_android_test.testdef import AndroidTest +from lava_android_test.testdef import AndroidTestRunner, \ + AndroidTestInstaller, \ + AndroidTestParser +from lava_android_test import utils + + +class Command(LAVACommand): + + def __init__(self, parser, args): + super(Command, self).__init__(parser, args) + self.config = get_config() +# self._test_loader = TestLoader(self._config) + + @classmethod + def register_arguments(cls, parser): + parser.add_argument( + "-q", "--quiet", + action="store_true", + default=False, + help="Be less verbose about undertaken actions") + parser.add_argument( + "-Q", "--quiet-subcommands", + action="store_true", + default=False, + help="Hide the output of all sub-commands (including tests)") + + def say(self, text, *args, **kwargs): + print "LAVA:", text.format(*args, **kwargs) + + def say_begin(self, text, *args, **kwargs): + print "LAVA: --Start Operation: ", text.format(*args, **kwargs) + + def say_end(self, text, *args, **kwargs): + print "LAVA: --End Operation: ", text.format(*args, **kwargs), + + def display_subprocess_output(self, stream_name, line): + if self.args.quiet_subcommands: + return + if stream_name == 'stdout': + self.say('(stdout) {0}', line.rstrip()) + elif stream_name == 'stderr': + self.say('(stderr) {0}', line.rstrip()) + + +class extract_attachments(Command): + """ + Extract the attachment files from the result bundle file + generated by the -o option of run command + or from the output of parse command + """ + @classmethod + def register_arguments(self, parser): + super(extract_attachments, self).register_arguments(parser) + parser.add_argument("result_file", + help="The result bundle json file") + group = parser.add_argument_group("specify the output directory") + group.add_argument("-d", "--directory", + default=None, + metavar="directory", + help=("specify the directory where all the " + "attachment files will be put")) + + def invoke(self): + + if not os.path.exists(self.args.result_file): + raise LavaCommandError("The specified result file(%s) " + "does not exist." % self.args.result_file) + msg = "extract attachment file from result bundle file(%s)" % ( + self.args.result_file) + self.say_begin(msg) + badchars = "[^a-zA-Z0-9\._-]" + with open(self.args.result_file) as stream: + jobdata = stream.read() + result_data = DocumentIO.loads(jobdata)[1] + test_runs = result_data.get('test_runs') + if not self.args.directory: + attachment_dir = mkdtemp(prefix='attachments-', + dir=os.path.curdir) + elif not os.path.exists(self.args.directory): + os.makedirs(self.args.directory) + attachment_dir = self.args.directory + elif not os.path.isdir(self.args.directory): + raise LavaCommandError( + "The specified path(%s) is not a directory." + % self.args.directory) + else: + attachment_dir = self.args.directory + + for test in test_runs: + test_id = test.get('test_id').replace(" ", "_") + test_id = re.sub(badchars, "_", test_id) + target_dir = mkdtemp(prefix='%s' % test_id, dir=attachment_dir) + print "The test id is: %s" % test_id + attachments = test.get('attachments', []) + for attach in attachments: + pathname = attach.get('pathname') + file_name = os.path.basename(pathname) + content_decoded = base64.standard_b64decode( + attach.get("content")) + with open(os.path.join(target_dir, file_name), 'w') as fd: + fd.write(content_decoded) + self.say("All attachment files are put under directory(%s)" % + (attachment_dir)) + self.say_end(msg) + + +class list_devices(Command): + """ + List available devices + program::lava-android-test list-devices + """ + + def invoke(self): + + self.adb = ADB() + try: + output = self.adb.devices()[1] + if output is not None: + for line in output: + print line.strip() + else: + print "No device attached" + except OSError: + print "No device attached" + + +class list_tests(Command): + """ + List available tests + program:: lava-android-test list-tests + """ + + def invoke(self): + self.say("Known tests:") + for provider in TestProvider().get_test_provider_list(): + for test in provider().list_test(): + self.say(" - {test_id}", test_id=test) + + +class version(Command): + """ + Show LAVA Test version + """ + + def invoke(self): + self.say("version details:") + for framework in self._get_frameworks(): + self.say(" - {framework}: {version}", + framework=framework.__name__, + version=versiontools.format_version( + framework.__version__, framework)) + + def _get_frameworks(self): + import lava_tool + import lava_android_test + import linaro_dashboard_bundle + return [ + lava_android_test, + lava_tool, + linaro_dashboard_bundle] + + +class AndroidCommand(Command): + + @classmethod + def register_arguments(self, parser): + super(AndroidCommand, self).register_arguments(parser) + group = parser.add_argument_group("specify device serial number") + group.add_argument("-s", "--serial", + default=None, + metavar="serial", + help=("specify the device with serial number" + "that this command will be run on")) + + def test_installed(self, test_id): + if self.adb is None: + self.adb = ADB() + test_dir = os.path.join(self.config.installdir_android, test_id) + return self.adb.exists(test_dir) + + def get_device_serial(self): + return ADB(self.args.serial).get_serial() + + def assertDeviceIsConnected(self): + if not self.adb.isDeviceConnected(): + if self.adb.serial: + raise Exception("Device '%s' is not connected" % + self.adb.serial) + else: + raise Exception("No device found") + + def invoke(self): + serial = self.get_device_serial() + if not serial: + raise LavaCommandError("No device attached") + self.serial = serial + self.adb = ADB(self.serial) + + try: + self.assertDeviceIsConnected() + except Exception as err: + raise LavaCommandError(err) + + self.invoke_sub() + + def invoke_sub(self): + raise NotImplementedError + + +class AndroidTestCommand(AndroidCommand): + @classmethod + def register_arguments(self, parser): + super(AndroidTestCommand, self).register_arguments(parser) + parser.add_argument("test_id", + help="Test identifier") + + def get_tip_msg(self, text): + if self.args.serial: + tip_msg = "%s (%s) on device(%s)" % (text, + self.args.test_id, + self.args.serial) + else: + tip_msg = "%s (%s)" % (text, self.args.test_id) + return tip_msg + + +class AndroidResultCommand(AndroidCommand): + @classmethod + def register_arguments(self, parser): + super(AndroidResultCommand, self).register_arguments(parser) + parser.add_argument("result_id", + help="Test result identifier") + + +class AndroidResultsCommand(AndroidCommand): + @classmethod + def register_arguments(self, parser): + super(AndroidResultsCommand, self).register_arguments(parser) + parser.add_argument("result_id", nargs="+", + help="One or more result identifiers") + + +class list_installed(AndroidCommand): + """ + List installed tests for specified device. + program:: lava-android-test list-tests + program:: lava-android-test list-tests -s device_serial + """ + def invoke_sub(self): + + self.say("Installed tests:") + try: + output = self.adb.listdir(self.config.installdir_android)[1] + if output is not None: + for dir_name in output: + self.say(" - {test_id}", test_id=dir_name.strip()) + else: + self.say("No tests installed") + except OSError: + self.say("No tests installed") + + +class list_results(AndroidCommand): + """ + List results of tests that has been run on the specified device. + program:: lava-android-test list-results + program:: lava-android-test list-results -s device_serial + """ + def invoke_sub(self): + self.say("Saved results:") + try: + (ret_code, output) = self.adb.listdir( + self.config.resultsdir_android) + if ret_code != 0: + raise OSError() + for dir_name in output: + self.say(" - {result_id}", result_id=dir_name.strip()) + except OSError: + self.say("No results found") + + +class install(AndroidTestCommand): + """ + Install test to the specified device. + program:: lava-android-test install test-id + program:: lava-android-test install test-id -s device_serial + """ + + @classmethod + def register_arguments(cls, parser): + super(cls, install).register_arguments(parser) + parser.add_argument('-o', '--install-option') + + def invoke_sub(self): + tip_msg = self.get_tip_msg("Install test") + self.say_begin(tip_msg) + + if self.test_installed(self.args.test_id): + raise LavaCommandError("The test (%s) has already installed." % + self.args.test_id) + test = TestProvider().load_test(self.args.test_id, self.args.serial) + try: + test.install(self.args.install_option) + except Exception as strerror: + raise LavaCommandError("Test installation error: %s" % strerror) + + self.say_end(tip_msg) + + +class uninstall(AndroidTestCommand): + """ + Unistall test of the specified device. + program:: lava-android-test uninstall test-id + program:: lava-android-test uninstall test-id -s device_serial + """ + def invoke_sub(self): + tip_msg = self.get_tip_msg("Uninstall test") + self.say_begin(tip_msg) + + test = TestProvider().load_test(self.args.test_id, self.args.serial) + try: + test.uninstall() + except Exception as strerror: + raise LavaCommandError("Test uninstall error: %s" % strerror) + self.say_end(tip_msg) + + +class run(AndroidTestCommand): + """ + Run a previously installed test program on the specified device + program:: lava-android-test run test-id + program:: lava-android-test run test-id -s device_serial + program:: lava-android-test run test-id -s device_serial -o outputfile + """ + + @classmethod + def register_arguments(cls, parser): + super(run, cls).register_arguments(parser) + parser.add_argument('-O', '--run-option', + help=("Specified in the job file for using in " + "the real test action, so that we can customize" + " some test when need")) + group = parser.add_argument_group("specify the bundle output file") + group.add_argument("-o", "--output", + default=None, + metavar="FILE", + help=("After running the test parse the result" + " artefacts, fuse them with the initial" + " bundle and finally save the complete bundle" + " to the specified FILE.")) + + def invoke_sub(self): + tip_msg = self.get_tip_msg("Run test") + self.say_begin(tip_msg) + + if not self.test_installed(self.args.test_id): + raise LavaCommandError( + "The test (%s) has not been installed yet." % + self.args.test_id) + test = TestProvider().load_test(self.args.test_id, self.args.serial) + + if not self.test_installed(test.testname): + raise LavaCommandError( + "The test (%s) has not been installed yet." + % self.args.test_id) + + try: + result_id = test.run(quiet=self.args.quiet, + run_options=self.args.run_option) + if self.args.output: + output_dir = os.path.dirname(self.args.output) + if output_dir and (not os.path.exists(output_dir)): + os.makedirs(output_dir) + bundle = generate_bundle(self.args.serial, result_id) + with open(self.args.output, "wt") as stream: + DocumentIO.dump(stream, bundle) + + except Exception as strerror: + raise LavaCommandError("Test execution error: %s" % strerror) + + self.say_end(tip_msg) + + +class run_custom(AndroidCommand): + """ + Run the command(s) that specified by the -c option in the command line + program:: lava-android-test run-custom -c 'cm1' -c 'cmd2' -p 'parse-regex1' + program:: lava-android-test run test-id -s device_serial + program:: lava-android-test run test-id -s device_serial -o outputfile + """ + + @classmethod + def register_arguments(cls, parser): + super(run_custom, cls).register_arguments(parser) + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('-c', '--android-command', action='append', + help=("Specified in the job file for using" + " in the real test action, so that " + "we can customize some test when need")) + group.add_argument('-f', '--command-file', + help=("Specified the command file that will be " + "pushed into android and run.")) + parser.add_argument('-p', '--parse-regex', + help=("Specified the regular expression used" + " for analyzing command output")) + group = parser.add_argument_group("specify the bundle output file") + group.add_argument("-o", "--output", + default=None, + metavar="FILE", + help=("After running the test parse the result" + " artefacts, fuse them with the initial" + " bundle and finally save the complete bundle" + " to the specified FILE.")) + + def invoke_sub(self): + + test_name = 'custom' + ADB_SHELL_STEPS = [] + STEPS_HOST_PRE = [] + STEPS_ADB_PRE = [] + file_name = None + if self.args.android_command: + ADB_SHELL_STEPS = self.args.android_command + cmds_str = ','.join(ADB_SHELL_STEPS) + if len(cmds_str) > 40: + cmds_str = '%s...' % (cmds_str[:40]) + test_name_suffix = 'command=[%s]' % (cmds_str) + elif self.args.command_file: + file_url = self.args.command_file + urlpath = urlparse.urlsplit(file_url).path + file_name = os.path.basename(urlpath) + target_path = os.path.join(self.config.installdir_android, + test_name, file_name) + STEPS_HOST_PRE = ["wget %s -O %s" % (file_url, file_name)] + STEPS_ADB_PRE = ["push %s %s" % (file_name, target_path)] + ADB_SHELL_STEPS = ["chmod 777 %s" % target_path, + target_path] + file_name_str = file_name + if len(file_name_str) > 40: + file_name_str = '%s...' % (cmds_str[:40]) + test_name_suffix = 'command_file=%s' % (file_name_str) + + PATTERN = None + if self.args.parse_regex: + PATTERN = self.args.parse_regex + + tip_msg = '' + if self.args.serial: + tip_msg = ("Run following custom test(s) on device(%s):" + "\n\tcommands=%s" + "\n\tcommand-file=%s\n") % ( + self.args.serial, + '\n\t\t'.join(ADB_SHELL_STEPS), + file_name) + else: + tip_msg = ("Run following custom test(s):" + "\n\t\tcommands=%s" + "\n\tcommand-file=%s\n") % ( + '\n\t\t'.join(ADB_SHELL_STEPS), + file_name) + + self.say_begin(tip_msg) + + inst = AndroidTestInstaller() + + run = AndroidTestRunner(steps_host_pre=STEPS_HOST_PRE, + steps_adb_pre=STEPS_ADB_PRE, + adbshell_steps=ADB_SHELL_STEPS) + parser = AndroidTestParser(pattern=PATTERN) + test = AndroidTest(testname=test_name, + installer=inst, runner=run, parser=parser) + test.parser.results = {'test_results': []} + test.setadb(self.adb) + + if not self.test_installed(test.testname): + test.install() + + try: + result_id = test.run(quiet=self.args.quiet) + if self.args.output: + output_dir = os.path.dirname(self.args.output) + if output_dir and (not os.path.exists(output_dir)): + os.makedirs(output_dir) + bundle = generate_bundle(self.args.serial, + result_id, test=test, + test_id='%s(%s)' % (test_name, test_name_suffix)) + with open(self.args.output, "wt") as stream: + DocumentIO.dump(stream, bundle) + + except Exception as strerror: + raise LavaCommandError("Test execution error: %s" % strerror) + self.say_end(tip_msg) + + +class run_monkeyrunner(AndroidCommand): + """ + Run the monkeyrunner scripts that stored in the specified git repository + program:: lava-android-test run-monkeyrunner -g giturl -r resultfilelist + """ + + @classmethod + def register_arguments(cls, parser): + super(run_monkeyrunner, cls).register_arguments(parser) + parser.add_argument("url", + help="The repository url of the test scripts") + parser.add_argument('-t', '--repo-type', + default='git', + help=("Specify the type of the repository")) + group = parser.add_argument_group("specify the bundle output file") + group.add_argument("-o", "--output", + default=None, + metavar="FILE", + help=("After running the test parse the result" + " artefacts, fuse them with the initial" + " bundle and finally save the complete bundle" + " to the specified FILE.")) + + def invoke_sub(self): + + if not utils.check_command_exist('monkeyrunner'): + raise LavaCommandError('The command monkeyrunner can not be found') + + if self.args.repo_type == 'git': + target_dir = mkdtemp(prefix='git_repo', + dir=self.config.tempdir_host) + os.chmod(target_dir, 0755) + GitRepository(self.args.url).checkout(target_dir) + else: + raise LavaCommandError("The repository type(%s) is not supported" + % self.args.repo_type) + + script_list = utils.find_files(target_dir, '.py') + + test_id = self.args.url + if len(test_id) > 40: + test_id = '%s...' % (test_id[:40]) + test_id = 'monkeyrunner_%s' % test_id + + tip_msg = ("Run monkeyrunner scripts in following url on device(%s):" + "\n\turl=%s") % ( + self.serial, + self.args.url) + + self.say_begin(tip_msg) + bundles = [] + for script in script_list: + if "monkeycommon.py" == os.path.basename(script): + continue + sub_bundle = {} + from datetime import datetime + starttime = datetime.utcnow() + test_case_id = script.replace('%s/' % target_dir, '') + if len(test_case_id) > 50: + test_case_id = '%s...' % (test_case_id[:50]) + try: + sub_bundle = self.run_monkeyrunner_test(script, self.serial, + test_case_id) + test_result = {"test_case_id": test_case_id, + "result": 'pass'} + if sub_bundle: + sub_bundle['test_runs'][0]['test_results'].append( + test_result) + except Exception as strerror: + self.say('Failed to run script(%s) with error:\n%s' % ( + script, + strerror)) + + test_result = {"test_case_id": test_case_id, + "result": 'fail'} + TIMEFORMAT = '%Y-%m-%dT%H:%M:%SZ' + sub_bundle['test_runs'] = [{'test_results': [test_result], + 'test_id': 'monkeyrunner(%s)' % test_case_id, + 'time_check_performed': False, + 'analyzer_assigned_uuid': str(uuid4()), + 'analyzer_assigned_date': starttime.strftime(TIMEFORMAT)}] + if sub_bundle: + bundles.append(sub_bundle) + + if self.args.output: + output_dir = os.path.dirname(self.args.output) + if output_dir and (not os.path.exists(output_dir)): + os.makedirs(output_dir) + with open(self.args.output, "wt") as stream: + DocumentIO.dump(stream, merge_bundles(bundles)) + + self.say_end(tip_msg) + + def run_monkeyrunner_test(self, script, serial, test_case_id=None): + + inst = AndroidTestInstaller() + run = AndroidTestRunner(steps_host_pre=[ + 'monkeyrunner %s %s' % (script, serial)]) + parser = MonkeyrunnerTestParser() + parser.monkeyrunner_result = os.path.join(os.path.dirname(script), + 'results.txt') + test = AndroidTest(testname='monkeyrunner', + installer=inst, runner=run, parser=parser) + test.parser.results = {'test_results': []} + test.setadb(self.adb) + + ##By calling the install function, we will create the directory + ##on the target, and the the output file and error file + ##will be pushed there + if not self.test_installed(test.testname): + test.install() + + ##The png files here are generated to the host by the monkeyrunner + ##monkeyrunner is run on host, not on the target + bundle = {} + org_png_file_list = utils.find_files(self.config.tempdir_host, + '.%s' % 'png') + result_id = test.run(quiet=self.args.quiet) + if self.args.output: + cur_all_png_list = utils.find_files(self.config.tempdir_host, + '.%s' % 'png') + new_png_list = set(cur_all_png_list).difference(org_png_file_list) + test_id = 'monkeyrunner(%s)' % (test_case_id) + bundle = generate_bundle(self.args.serial, + result_id, test=test, + test_id=test_id, + attachments=list(new_png_list)) + utils.delete_files(new_png_list) + + return bundle + + +class MonkeyrunnerTestParser(AndroidTestParser): + ''' + Before this method is called, self.monkeyrunner_result must be set + to the right value + ''' + + + def real_parse(self, result_filename=None, output_filename=None, + test_name=''): + self.res_pattern = ("^\s*(?P<test_case_id>.*?)\s*=" + "\s*(?P<result>(true|false))\s*$") + self.measurement_pattern = ("^\s*(?P<test_case_id>.*?)\s*=" + "\s*(?P<measurement>[\.\d]+)\s*$") + self.measurement_units_pattern = ("^\s*(?P<test_case_id>.*?)\s*=" + "\s*(?P<measurement>[\.\d]+)\s+(?P<units>\S+)\s*$") + + res_pat = re.compile(self.res_pattern) + measurement_pat = re.compile(self.measurement_pattern) + measurement_units_pat = re.compile(self.measurement_units_pattern) + + + if not os.path.exists(self.monkeyrunner_result): + return + with open(self.monkeyrunner_result) as stream: + for lineno, line in enumerate(stream, 1): + match = res_pat.search(line) + if not match: + match = measurement_pat.search(line) + if not match: + match = measurement_units_pat.search(line) + if not match: + continue + data = match.groupdict() + data["log_filename"] = result_filename + data["log_lineno"] = lineno + if data.get('result') is None: + data['result'] = 'pass' + + self.results['test_results'].append(data) + + +class parse(AndroidResultsCommand): + """ + Parse the results of previous test that run on the specified device + program:: lava-android-test parse test-result-id + """ + def invoke_sub(self): + bundle = generate_combined_bundle(self.args.serial, + self.args.result_id) + try: + print DocumentIO.dumps(bundle) + except IOError: + pass + + +class parse_custom(AndroidResultsCommand): + """ + Parse the results of previous test that run with run-custom command + on the specified device + program:: lava-android-test parse-custom test-result-id -P + """ + @classmethod + def register_arguments(cls, parser): + super(parse_custom, cls).register_arguments(parser) + parser.add_argument('-p', '--parse-regex', + help=("Specified the regular expression used" + " for analyzing command output")) + + def invoke_sub(self): + PATTERN = None + if self.args.parse_regex: + PATTERN = self.args.parse_regex + test_name = 'custom' + inst = AndroidTestInstaller() + run = AndroidTestRunner() + parser = AndroidTestParser(pattern=PATTERN) + test = AndroidTest(testname=test_name, installer=inst, + runner=run, parser=parser) + test.parser.results = {'test_results': []} + test.setadb(self.adb) + + bundle = generate_combined_bundle(self.args.serial, + self.args.result_id, test=test) + try: + print DocumentIO.dumps(bundle) + except IOError: + pass + + +def generate_combined_bundle(serial=None, result_ids=None, test=None, + test_id=None): + if result_ids is None: + return {} + + bundle = None + + for rid in result_ids: + b = generate_bundle(serial, rid, test, test_id) + if rid == result_ids[0]: + bundle = b + else: + bundle['test_runs'].append(b['test_runs'][0]) + + return bundle + + +def merge_bundles(bundles=[]): + config = get_config() + merged_bundles = {"format": config.bundle_format, + 'test_runs': []} + for bundle in bundles: + if bundle['test_runs']: + merged_bundles['test_runs'].append(bundle['test_runs'][0]) + return merged_bundles + + +def generate_bundle(serial=None, result_id=None, test=None, + test_id=None, attachments=[]): + if result_id is None: + return {} + config = get_config() + adb = ADB(serial) + resultdir = os.path.join(config.resultsdir_android, result_id) + if not adb.exists(resultdir): + raise Exception("The result (%s) is not existed." % result_id) + + bundle_text = adb.read_file(os.path.join(resultdir, "testdata.json")) + bundle = DocumentIO.loads(bundle_text)[1] + test_tmp = None + if test: + test_tmp = test + else: + test_tmp = TestProvider().load_test(bundle['test_runs'][0]['test_id'], + serial) + if test_id: + bundle['test_runs'][0]['test_id'] = test_id + else: + attrs = bundle['test_runs'][0].get('attributes') + if attrs: + run_options = attrs.get('run_options') + if run_options: + test_id = '%s(%s)' % (bundle['test_runs'][0]['test_id'], + run_options) + bundle['test_runs'][0]['test_id'] = test_id + + test_tmp.parse(result_id) + stdout_text = adb.read_file(os.path.join(resultdir, + os.path.basename(test_tmp.org_ouput_file))) + if stdout_text is None: + stdout_text = '' + stderr_text = adb.read_file(os.path.join(resultdir, 'stderr.log')) + if stderr_text is None: + stderr_text = '' + bundle['test_runs'][0]["test_results"] = test_tmp.parser.results[ + "test_results"] + + ## following part is used for generating the attachment for normal test + attachment_bundles = [] + for attachment in test_tmp.attachments: + data_bundle = attachment.generate_bundle(adb=adb, resultsdir=resultdir) + if data_bundle: + attachment_bundles.append(data_bundle) + + bundle['test_runs'][0]["attachments"] = attachment_bundles + + ##following used for the attachment for monkeyrunner test + for attach in attachments: + if os.path.exists(attach): + with open(attach, 'rb') as stream: + data = stream.read() + if data: + bundle['test_runs'][0]["attachments"].append({ + "pathname": os.path.basename(attach), + "mime_type": 'image/png', + "content": base64.standard_b64encode(data)}) + return bundle + +class show(AndroidResultCommand): + """ + Display the output from a previous test that run on the specified device + program:: lava-android-test show result-id + program:: lava-android-test show result-id -s device_serial + """ + def invoke_sub(self): + resultsdir = os.path.join(self.config.resultsdir_android, + self.args.result_id) + if not self.adb.exists(resultsdir): + raise LavaCommandError( + "The result (%s) is not existed." % self.args.result_id) + + stdout = os.path.join(resultsdir, "stdout.log") + if not self.adb.exists(stdout): + self.say("No result found for '%s'" % self.args.result_id) + return + try: + output = self.adb.get_shellcmdoutput('cat %s' % stdout)[1] + if output is not None: + for line in output: + self.display_subprocess_output('stdout', line) + except IOError: + pass + + stderr = os.path.join(resultsdir, "stderr.log") + if not self.adb.exists(stderr): + return + try: + output = self.adb.get_shellcmdoutput('cat %s' % stderr)[1] + if output is not None: + for line in output: + self.display_subprocess_output('stderr', line) + except IOError: + pass + + +class rename(AndroidResultCommand): + """ + Rename the result's id of a previous test that run on the specified device + program:: lava-android-test rename result-id result-id-new + program:: lava-android-test remove result-id result-id-new -s device_serial + """ + + @classmethod + def register_arguments(self, parser): + super(rename, self).register_arguments(parser) + parser.add_argument("result_id_new", + help="New test result identifier") + + def invoke_sub(self): + srcdir = os.path.join(self.config.resultsdir_android, + self.args.result_id) + destdir = os.path.join(self.config.resultsdir_android, + self.args.result_id_new) + + if not self.adb.exists(srcdir): + self.say("Result (%s) not found" % self.args.result_id) + return + if self.adb.exists(destdir): + self.say("Destination result name already exists") + self.adb.move(srcdir, destdir) + + +class remove(AndroidResultsCommand): + """ + Remove the result of a previous test that run on the specified device + program:: lava-android-test remove result-id + program:: lava-android-test remove result-id0 result-id1 + program:: lava-android-test remove result-id -s device_serial + """ + + @classmethod + def register_arguments(self, parser): + super(remove, self).register_arguments(parser) + group = parser.add_argument_group("force to remove") + group.add_argument("-f", "--force", + action="store_true", + help=("give an interactive question about remove")) + + def remove(self, rid): + resultsdir = os.path.join(self.config.resultsdir_android, rid) + if not self.adb.exists(resultsdir): + self.say("No result found for '%s'" % rid) + return + if not self.args.force: + self.say("Remove result '%s' for good? [Y/N]" % rid) + response = raw_input() + if response[0].upper() != 'Y': + return + self.adb.rmtree(resultsdir) + + def invoke_sub(self): + for rid in self.args.result_id: + self.remove(rid) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/config.py b/build/lib.linux-x86_64-2.7/lava_android_test/config.py new file mode 100644 index 0000000..64bf278 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/config.py @@ -0,0 +1,51 @@ +# Copyright (c) 2010-2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os + + +class LavaAndroidTestConfig(object): + def __init__(self): + home = os.environ.get('ANDROID_TEST_HOME', '/data/local/tmp/lava-android-test/') + config = os.environ.get('ANDROID_TEST_CONFIG_HOME', + os.path.join(home, '.config')) + basedata = os.environ.get('ANDROID_TEST_DATA_HOME', + os.path.join(home, 'share')) + self.configdir = config + self.installdir_android = os.path.join(basedata, 'installed-tests') + self.resultsdir_android = os.path.join(basedata, 'results') + self.tempdir_android = os.path.join(home, 'temp') + self.tempdir_host = os.environ.get('ANDROID_TEST_TEMP_HOST', + '/tmp/lava-android-test') + self.bundle_format = "Dashboard Bundle Format 1.3" + + +_config = None + + +def get_config(): + global _config + if _config is not None: + return _config + return LavaAndroidTestConfig() + + +def set_config(config): + global _config + _config = config diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/hwprofile.py b/build/lib.linux-x86_64-2.7/lava_android_test/hwprofile.py new file mode 100644 index 0000000..1ac7b50 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/hwprofile.py @@ -0,0 +1,174 @@ +# Copyright (c) 2010 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import re +import sys +from lava_android_test.adb import ADB + +ARM_KEYMAP = { + 'Processor': 'cpu_model_name', + 'Features': 'cpu_features', + 'CPU implementer': 'cpu_implementer', + 'CPU architecture': 'cpu_architecture', + 'CPU variant': 'cpu_variant', + 'CPU part': 'cpu_part', + 'CPU revision': 'cpu_revision', +} + +ARM_VALMAP = { + 'CPU implementer': lambda value: int(value, 16), + 'CPU architecture': int, + 'CPU variant': lambda value: int(value, 16), + 'CPU part': lambda value: int(value, 16), + 'CPU revision': int, +} + + +def _translate_cpuinfo(keymap, valmap, key, value): + """ + Translate a key and value using keymap and valmap passed in + """ + newkey = keymap.get(key, key) + newval = valmap.get(key, lambda x: x)(value) + return newkey, newval + + +def get_cpu_devs(adb=ADB()): + """ + Return a list of CPU devices + """ + + pattern = re.compile('^(?P<key>.+?)\s*:\s*(?P<value>.*)$') + cpunum = 0 + devices = [] + cpudevs = [] + cpudevs.append({}) + + # TODO maybe there is other types + keymap, valmap = ARM_KEYMAP, ARM_VALMAP + + try: + (retcode, cpuinfo) = adb.get_shellcmdoutput("cat /proc/cpuinfo") + if retcode != 0 or cpuinfo is None: + raise IOError("Faile to get content of file(%s)" % "/proc/cpuinfo") + for line in cpuinfo: + match = pattern.match(line) + if match: + key, value = match.groups() + key = key.strip() + value = value.strip() + try: + key, value = _translate_cpuinfo(keymap, valmap, key, value) + except ValueError: + pass + if cpudevs[cpunum].get(key): + cpunum += 1 + cpudevs.append({}) + cpudevs[cpunum][key] = value + for c in range(len(cpudevs)): + device = {} + device['device_type'] = 'device.cpu' + device['description'] = 'Processor #{0}'.format(c) + device['attributes'] = cpudevs[c] + devices.append(device) + except IOError: + print >> sys.stderr, "WARNING: Could not read cpu information" + return devices + + +def get_board_devs(adb=ADB()): + """ + Return a list of board devices + """ + devices = [] + attributes = {} + device = {} + + try: + (retcode, cpuinfo) = adb.get_shellcmdoutput("cat /proc/cpuinfo") + if retcode != 0 or cpuinfo is None: + raise IOError("Faile to get content of file(%s)" % "/proc/cpuinfo") + pattern = re.compile("^Hardware\s*:\s*(?P<description>.+)$", re.M) + found = False + for line in cpuinfo: + match = pattern.search(line) + if match: + found = True + device['description'] = match.group('description').strip() + if not found: + return devices + except IOError: + print >> sys.stderr, "WARNING: Could not read board information" + return devices + if attributes: + device['attributes'] = attributes + device['device_type'] = 'device.board' + devices.append(device) + return devices + + +def get_mem_devs(adb=ADB()): + """ Return a list of memory devices + + This returns up to two items, one for physical RAM and another for swap + """ + devices = [] + + pattern = re.compile('^(?P<key>.+?)\s*:\s*(?P<value>.+) kB$', re.M) + + try: + (retcode, meminfo) = adb.get_shellcmdoutput("cat /proc/meminfo") + if retcode != 0 or meminfo is None: + raise IOError("Faile to get content of file(%s)" % "/proc/meminfo") + for line in meminfo: + match = pattern.search(line) + if not match: + continue + key, value = match.groups() + key = key.strip() + value = value.strip() + if key not in ('MemTotal', 'SwapTotal'): + continue + #Kernel reports in 2^10 units + capacity = int(value) << 10 + if capacity == 0: + continue + if key == 'MemTotal': + kind = 'RAM' + else: + kind = 'swap' + description = "{capacity}MiB of {kind}".format( + capacity=capacity >> 20, kind=kind) + device = {} + device['description'] = description + device['attributes'] = {'capacity': str(capacity), 'kind': kind} + device['device_type'] = "device.mem" + devices.append(device) + except IOError: + print >> sys.stderr, "WARNING: Could not read memory information" + return devices + + +def get_hardware_context(adb=ADB()): + """ + Return a dict with all of the hardware profile information gathered + """ + hardware_context = {} + devices = [] + devices.extend(get_cpu_devs(adb)) + devices.extend(get_board_devs(adb)) + devices.extend(get_mem_devs(adb)) + hardware_context['devices'] = devices + return hardware_context diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/main.py b/build/lib.linux-x86_64-2.7/lava_android_test/main.py new file mode 100644 index 0000000..cb39a72 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/main.py @@ -0,0 +1,63 @@ +# Copyright (c) 2010-2012 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +import os +import sys +import shutil +from tempfile import mkdtemp +from lava_android_test import utils +from lava_android_test.config import get_config, set_config +from lava_tool.dispatcher import LavaDispatcher, run_with_dispatcher_class + + +class LAVAAndroidTestDispatcher(LavaDispatcher): + toolname = 'lava_android_test' + description = """ + LAVA Android Test wrapper framework + """ + epilog = """ + Please report all bugs using the Launchpad bug tracker: + http://bugs.launchpad.net/lava-android-test/+filebug + """ + + +def check_adb_installed(): + return utils.check_command_exist('adb') + + +def main(): + if not check_adb_installed(): + print >> sys.stderr, "Can't find the command adb." + print >> sys.stderr, ("Please add the path of adb" + " command to PATH environment.") + sys.exit(1) + + config = get_config() + try: + if not os.path.exists(config.tempdir_host): + os.makedirs(config.tempdir_host) + #make every user can write/read this directory + os.chmod(config.tempdir_host, 0777) + config.tempdir_host = mkdtemp(dir=config.tempdir_host) + set_config(config) + os.chmod(config.tempdir_host, 0755) + run_with_dispatcher_class(LAVAAndroidTestDispatcher) + finally: + #can't remove the parent directory, because there may be other + #instance using the parent directory + shutil.rmtree(config.tempdir_host) + + +if __name__ == '__main__': + main() diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/provider.py b/build/lib.linux-x86_64-2.7/lava_android_test/provider.py new file mode 100644 index 0000000..4ded272 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/provider.py @@ -0,0 +1,276 @@ +# Copyright (c) 2012 Linaro + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import traceback + +from pkgutil import walk_packages + +from lava_android_test import testdef +from lava_android_test import test_definitions +from lava_android_test.test_definitions import commands, instruments +from lava_android_test.adb import ADB +from lava_android_test.config import get_config +from lava_android_test.utils import find_files + + +class UnfoundTest(Exception): + """ + Raise this for unfound test errors + """ + + +class TestProvider(object): + + test_prefix = '' + + def list_test(self): + """ + Return the list of this type + """ + raise NotImplementedError() + + def import_mod(self, importpath): + try: + mod = __import__(importpath) + except ImportError: + raise UnfoundTest('The module(%s) is not found!' % importpath) + for i in importpath.split('.')[1:]: + mod = getattr(mod, i) + return mod + + def list_mod(self, pkg_path): + test_list = [] + for importer, mod, ispkg in walk_packages(pkg_path): + test_list.append(mod) + return test_list + + def gen_testobj(self, testname=None, installer=None, runner=None, + parser=None, adb=ADB()): + + if installer is None: + installer = testdef.AndroidTestInstaller() + if runner is None: + runner = testdef.AndroidTestRunner() + if parser is None: + parser = testdef.AndroidTestParser() + + testobj = testdef.AndroidTest(testname=testname, + installer=installer, runner=runner, parser=parser) + + testobj.parser.results = {'test_results': []} + testobj.setadb(adb) + return testobj + + def get_test_provider_list(self): + providers_hash = {} +# module = imp.load_source("module", os.path.realpath(__file__)) + module = self.import_mod('lava_android_test.provider') + for name, cls in module.__dict__.iteritems(): + if name.endswith('TestProvider') \ + and name != 'TestProvider': + providers_hash[name] = cls + names = providers_hash.keys() + names.sort() + providers_list = [] + common_test_provider = None + for name in names: + if name != 'CommonTestProvider': + providers_list.append(providers_hash.get(name)) + else: + common_test_provider = providers_hash.get(name) + if common_test_provider is not None: + providers_list.append(common_test_provider) + return providers_list + + def load_test(self, test_name=None, serial=''): + providers = self.get_test_provider_list() + err_msg = '' + for provider in providers: + try: + testobj = provider().load_test(test_name=test_name, + serial=serial) + if testobj is not None: + return testobj + except: + err_msg = err_msg + traceback.format_exc() + raise UnfoundTest('The test(%s) is not found! + Exception:\n%s' % ( + test_name, err_msg)) + + +class CommonTestProvider(TestProvider): + + def list_test(self): + return self.list_mod(test_definitions.__path__) + + def load_test(self, test_name=None, serial=None): + importpath = "lava_android_test.test_definitions.%s" % test_name + mod = self.import_mod(importpath) + + base = mod.testobj + base.parser.results = {'test_results': []} + base.setadb(ADB(serial)) + return base + + +class CommandTestProvider(TestProvider): + + test_prefix = 'command' + + def list_test(self): + test_list = self.list_mod(commands.__path__) + ret_list = [] + for test_id in test_list: + ret_list.append('%s-%s' % (self.test_prefix, test_id)) + return ret_list + + def load_test(self, test_name=None, serial=None): + if not test_name.startswith('%s-' % self.test_prefix): + raise UnfoundTest('The test(%s) is not found!' % test_name) + mod_name = test_name.replace('%s-' % self.test_prefix, '', 1) + importpath = "lava_android_test.test_definitions.%ss.%s" % ( + self.test_prefix, mod_name) + mod = self.import_mod(importpath) + if not mod.RUN_ADB_SHELL_STEPS: + raise UnfoundTest(("RUN_ADB_SHELL_STEPS not" + " defined in the test(%s).") % test_name) + if not mod.PATTERN: + raise UnfoundTest(("PATTERN not" + " defined in the test(%s).") % test_name) + testobj = self.gen_testobj( + testname=test_name, + runner=testdef.AndroidTestRunner( + adbshell_steps=mod.RUN_ADB_SHELL_STEPS), + parser=testdef.AndroidTestParser(pattern=mod.PATTERN), + adb=ADB(serial)) + return testobj + + +class InstrumentTestProvider(TestProvider): + + test_prefix = 'instrument' + + def list_test(self): + test_list = self.list_mod(instruments.__path__) + ret_list = [] + for test_id in test_list: + ret_list.append('%s-%s' % (self.test_prefix, test_id)) + return ret_list + + def load_test(self, test_name=None, serial=None): + if not test_name.startswith('%s-' % self.test_prefix): + raise UnfoundTest('The test(%s) is not found!' % test_name) + mod_name = test_name.replace('%s-' % self.test_prefix, '', 1) + importpath = "lava_android_test.test_definitions.%ss.%s" % ( + self.test_prefix, mod_name) + mod = self.import_mod(importpath) + if not mod.RUN_ADB_SHELL_STEPS: + raise UnfoundTest(("RUN_ADB_SHELL_STEPS not" + " defined in the test(%s).") % test_name) + + testobj = self.gen_testobj( + testname=test_name, + runner=testdef.AndroidTestRunner( + adbshell_steps=mod.RUN_ADB_SHELL_STEPS), + parser=testdef.AndroidInstrumentTestParser(), + adb=ADB(serial)) + return testobj + + +class ShellTestProvider(TestProvider): + + test_prefix = 'shell' + config = get_config() + dotext = '.sh' + + def list_test(self): + dotext = '.sh' + mod = self.import_mod("lava_android_test.test_definitions.shells") + sh_files = find_files(mod.curdir, dotext) + test_list = [] + for f in sh_files: + ##Assume that the file name only has one '.sh' + f_name_no_dotext = os.path.basename(f).replace(dotext, '') + test_list.append('%s-%s' % (self.test_prefix, f_name_no_dotext)) + return test_list + + def load_test(self, test_name=None, serial=None): + if not test_name.startswith('%s-' % self.test_prefix): + raise UnfoundTest('The test(%s) is not found!' % test_name) + f_name_no_dotext = test_name.replace('%s-' % self.test_prefix, '', 1) + + mod = self.import_mod("lava_android_test.test_definitions.%ss" % + self.test_prefix) + f_name = '%s%s' % (f_name_no_dotext, self.dotext) + sh_file = '%s/%s' % (mod.curdir, f_name) + + test_sh_android_path = os.path.join(self.config.installdir_android, + test_name, f_name) + + INSTALL_STEPS_ADB_PRE = [ + 'push %s %s ' % (sh_file, test_sh_android_path), + 'shell chmod 777 %s' % test_sh_android_path] + + ADB_SHELL_STEPS = ['%s $(OPTIONS)' % test_sh_android_path] + + testobj = self.gen_testobj( + testname=test_name, + installer=testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE), + runner=testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS), + parser=testdef.AndroidSimpleTestParser(), + adb=ADB(serial)) + return testobj + + +class HostShellTestProvider(TestProvider): + + test_prefix = 'hostshell' + config = get_config() + dotext = '.sh' + + def list_test(self): + dotext = '.sh' + mod = self.import_mod("lava_android_test.test_definitions.hostshells") + sh_files = find_files(mod.curdir, dotext) + test_list = [] + for f in sh_files: + ##Assume that the file name only has one '.sh' + f_name_no_dotext = os.path.basename(f).replace(dotext, '') + test_list.append('%s-%s' % (self.test_prefix, f_name_no_dotext)) + return test_list + + def load_test(self, test_name=None, serial=None): + if not test_name.startswith('%s-' % self.test_prefix): + raise UnfoundTest('The test(%s) is not found!' % test_name) + f_name_no_prefix = test_name.replace('%s-' % self.test_prefix, '', 1) + + mod = self.import_mod("lava_android_test.test_definitions.%ss" % + self.test_prefix) + f_name = '%s%s' % (f_name_no_prefix, self.dotext) + test_sh_path = '%s/%s' % (mod.curdir, f_name) + + HOST_SHELL_STEPS = ['bash %s -s $(SERIAL) $(OPTIONS)' % test_sh_path] + + testobj = self.gen_testobj( + testname=test_name, + installer=testdef.AndroidTestInstaller(), + runner=testdef.AndroidTestRunner( + steps_host_pre=HOST_SHELL_STEPS), + parser=testdef.AndroidSimpleTestParser(), + adb=ADB(serial)) + return testobj + diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/repository.py b/build/lib.linux-x86_64-2.7/lava_android_test/repository.py new file mode 100644 index 0000000..ce57470 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/repository.py @@ -0,0 +1,83 @@ +# Copyright (C) 2012 Linaro Limited +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +import os +import subprocess + +from lava_android_test import utils + + +class RepositoryError(Exception): + """ + Raise this for repository related errors + """ + + +class Repository(object): + ''' + Base class for all repository class used to checkout files. + This class and sub classes are base the repository command. + ''' + + def __init__(self, url, repo_type, cmds=[]): + self.url = url + self.repo_type = repo_type + self.check_cmds_exist(cmds) + + def checkout(self, target_dir=None): + """ + Checkout this repository to the specified the target_dir directory + """ + raise NotImplementedError() + + def check_cmds_exist(self, cmds=[]): + """ + check whether the necessary commands are existing. + """ + for cmd in cmds: + if not utils.check_command_exist(cmd): + raise RepositoryError(("The necessary command(%) does not" + " exist, Or can't be seen from path") + % cmd) + + +class GitRepository(Repository): + + git_cmd = 'git' + + def __init__(self, url): + super(GitRepository, self).__init__(url, 'git', [self.git_cmd]) + + def checkout(self, target_dir=None): + """ + Checkout this git repository to the specified the target_dir directory + """ + cmds = [] + if not target_dir: + cmds = [self.git_cmd, 'clone', self.url] + + else: + if not os.path.exists(target_dir): + os.makedirs(target_dir) + cmds = [self.git_cmd, 'clone', self.url, target_dir] + + rc = subprocess.call(cmds) + if rc != 0: + raise RepositoryError(("Failed to clone the specified " + "repository() with exist staus=%d") + % (self.url, rc)) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/swprofile.py b/build/lib.linux-x86_64-2.7/lava_android_test/swprofile.py new file mode 100644 index 0000000..1a74e67 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/swprofile.py @@ -0,0 +1,95 @@ +# Copyright (c) 2010 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +import re +import sys +from datetime import datetime +from lava_android_test.adb import ADB + + +def get_properties(adb=ADB()): + if adb is None: + return {} + + properties = {} + try: + propinfo = adb.get_shellcmdoutput("getprop")[1] + if propinfo is None: + return properties + pattern = re.compile( + '^\[(?P<key>[^\]]+?)]\s*:\s*\[(?P<value>[^\]]+)\]\s*$', + re.M) + for line in propinfo: + match = pattern.search(line) + if match: + key, value = match.groups() + properties[key] = value + except IOError: + print >> sys.stderr, "WARNING: Could not read board information" + return properties + return properties + + +def get_image_name_from_properties(adb=ADB()): + props = get_properties(adb) + return props.get('ro.build.display.id', '') + + +def get_source_info(adb=ADB()): + + TIMEFORMAT = '%Y-%m-%dT%H:%M:%SZ' + source = [] + example = {'project_name': '', + 'branch_vcs': 'git', + 'branch_url': '', + 'branch_revision': '', + 'commit_timestamp': datetime.utcnow().strftime(TIMEFORMAT)} + source.append(example) + return source + + +def get_package_info(adb=ADB()): + + packages_info = [] + pkginfo = adb.get_shellcmdoutput('/system/bin/pm list packages -v')[1] + if pkginfo is None: + return packages_info + pattern = re.compile( + ("^\s*package:\s*(?P<package_name>[^:]+?)\s*:" + "\s*(?P<version>[^\s].+)\s*$"), re.M) + for line in pkginfo: + match = pattern.search(line) + if match: + package_name, version = match.groups() + package = {'name': package_name.strip(), + 'version': version.strip()} + packages_info.append(package) + return packages_info + + +def get_software_context(adb=ADB()): + """ Return dict used for storing software_context information + + image - the image information of the android system + sources - the source information about the android system + packages - the apk packages information in the android system + """ + if adb is None: + return {} + + software_context = {'image': {'name': get_image_name_from_properties(adb)}, + 'sources': get_source_info(adb), + 'packages': get_package_info(adb) + } + return software_context diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/0xbench.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/0xbench.py new file mode 100644 index 0000000..8327629 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/0xbench.py @@ -0,0 +1,89 @@ +# Copyright (c) 2011 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +0xbench integrates several popular benchmarks into a single Android +app that can be run to get benchmark reports for a given device. +Here by default we will run the math/2d/3d test on the target device. + +**URL:** http://code.google.com/p/0xbench/ + +**Default options:** "--ez math true --ez 2d true --ez 3d true --ez vm true" +""" + +import os +import json + +import lava_android_test.testdef + +curdir = os.path.realpath(os.path.dirname(__file__)) + +# "-timeout timeout" must be specified with at least one test +# can not only specified the "-timeout timeout" as option +DEFAULT_OPTIONS = '--ez math true --ez 2d true --ez 3d true --ez vm true' +INSTALL_STEPS_HOST_POST = [ + ("python %s/android-0xbenchmark/android_0xbenchmark_modify_path.py" + " $(SERIAL)") % curdir] + +RUN_STEPS_HOST_PRE = [ + ("python %s/android-0xbenchmark/android_0xbenchmark_kill.py" + " $(SERIAL)") % curdir] +RUN_STEPS_ADB_SHELL = ['logcat -c', + ("am start -n org.zeroxlab.zeroxbenchmark/" + "org.zeroxlab.zeroxbenchmark.Benchmark --ez autorun true $(OPTIONS)")] +RUN_STEPS_HOST_POST = [ + 'python %s/android-0xbenchmark/android_0xbenchmark_wait.py ' + '$(SERIAL) $(OPTIONS)' % curdir] + + +class ZeroXBenchmarkTestParser(lava_android_test.testdef.AndroidTestParser): + + def parse(self, result_filename=None, output_filename='0xBenchmark.bundle', + test_name=''): + """Parse test output to gather results + Use the pattern specified when the class was instantiated to look + through the results line-by-line and find lines that match it. + Results are then stored in self.results. If a fixupdict was supplied + it is used to convert test result strings to a standard format. + """ + with open(output_filename) as stream: + test_results_data = stream.read() + test_results_json = json.loads(test_results_data) + self.results['test_results'] = test_results_json[ + 'test_runs'][0]['test_results'] + if self.fixupdict: + self.fixresults(self.fixupdict) + if self.appendall: + self.appendtoall(self.appendall) + self.fixmeasurements() + self.fixids() + +save_dir = '/data/data/org.zeroxlab.zeroxbenchmark/files' +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_host_post=INSTALL_STEPS_HOST_POST) +run = lava_android_test.testdef.AndroidTestRunner( + steps_host_pre=RUN_STEPS_HOST_PRE, + adbshell_steps=RUN_STEPS_ADB_SHELL, + steps_host_post=RUN_STEPS_HOST_POST) +parser = ZeroXBenchmarkTestParser() +testobj = lava_android_test.testdef.AndroidTest(testname="0xbench", + installer=inst, runner=run, parser=parser, + org_ouput_file=os.path.join(save_dir, '0xBenchmark.bundle'), + default_options=DEFAULT_OPTIONS) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/__init__.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/__init__.py diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/android-0xbenchmark/ZeroxBench_Preference.xml b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/android-0xbenchmark/ZeroxBench_Preference.xml new file mode 100644 index 0000000..6f07a12 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/android-0xbenchmark/ZeroxBench_Preference.xml @@ -0,0 +1,5 @@ +<?xml version='1.0' encoding='utf-8' standalone='yes' ?> +<map> +<string name="KEY_RESULT_CUSTOM_DIR">/data/data/org.zeroxlab.zeroxbenchmark/files</string> +<int name="KEY_RESULT_SELECTION" value="1" /> +</map> diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/android-0xbenchmark/android_0xbenchmark_kill.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/android-0xbenchmark/android_0xbenchmark_kill.py new file mode 100755 index 0000000..17a4fd7 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/android-0xbenchmark/android_0xbenchmark_kill.py @@ -0,0 +1,69 @@ +#!/usr/bin/python + +# Copyright (c) 2011 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import re +import sys +import time +from commands import getstatusoutput + +if len(sys.argv) == 1: + adb_cmd = "adb" +else: + adb_cmd = "adb -s %s" % (sys.argv[1]) + + +def back(): + back_cmd = '%s shell input keyevent 4' % (adb_cmd) + rc, output = getstatusoutput(back_cmd) + if rc != 0: + print 'Failed to execute command %s:%s' % (back_cmd, output) + sys.exit(1) +back() +back() +back() + +##app_76 861 80 165896 28848 ffffffff afd0eb18 S +## org.zeroxlab.zeroxbenchmark +pattern = re.compile( + '^\S+\s+(?P<pid>\d+?)\s+.*org\.zeroxlab\.zeroxbenchmark\s*$') +while True: + pscmd = '%s shell ps' % (adb_cmd) + rc, output = getstatusoutput(pscmd) + if rc != 0: + print ("Failed to get process information about " + "org.zeroxlab.zeroxbenchmark:%s") % output + sys.exit(1) + pid = None + for line in output.splitlines(): + match = pattern.match(line) + if match: + pid = match.group('pid') + break + + if pid is None: + sys.exit(0) + + killcmd = '%s shell kill %s' % (adb_cmd, pid) + rc, output = getstatusoutput(killcmd) + if rc != 0: + print 'Failed to kill process(%s):%s' % (pid, output) + sys.exit(1) + time.sleep(2) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/android-0xbenchmark/android_0xbenchmark_modify_path.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/android-0xbenchmark/android_0xbenchmark_modify_path.py new file mode 100644 index 0000000..0b0d309 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/android-0xbenchmark/android_0xbenchmark_modify_path.py @@ -0,0 +1,121 @@ +#!/usr/bin/python + +# Copyright (c) 2011 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +import sys +import re +import os +from commands import getstatusoutput + +curdir = os.path.realpath(os.path.dirname(__file__)) +source = '%s/ZeroxBench_Preference.xml' % curdir +target = ("/data/data/org.zeroxlab.zeroxbenchmark/shared_prefs/" + "ZeroxBench_Preference.xml") + +if len(sys.argv) == 1: + adbcmd = 'adb' +else: + adbcmd = 'adb -s %s' % (sys.argv[1]) + +target_dir = '/data/data' +lscmd = '%s shell ls -l %s' % (adbcmd, target_dir) +rc, output = getstatusoutput(lscmd) +if rc != 0: + print 'Failed to get group and owner of directory(%s) : %s' % (target_dir, + output) + sys.exit(1) +group = None +owner = None +##drwxr-x--x app_76 app_76 2011-10-21 14:40 +## org.zeroxlab.zeroxbenchmark +pattern = re.compile( + ("^d\S+\s+(?P<group>\S+?)\s+(?P<owner>\S+?)\s+" + "\S+\s+\S+\s+org\.zeroxlab\.zeroxbenchmark\s*$")) +for line in output.splitlines(): + match = pattern.match(line) + if match: + group, owner = match.groups() + break +if (group is None) or (owner is None): + print 'Failed to get group and owner of directory(%s): %s' % (target_dir, + output) + sys.exit(1) + +target_dir = '/data/data/org.zeroxlab.zeroxbenchmark/shared_prefs' +mkdircmd = '%s shell mkdir %s' % (adbcmd, target_dir) +rc, output = getstatusoutput(mkdircmd) +if rc != 0: + print 'Failed to create directory(%s): %s' % (source, target, output) + sys.exit(1) + +chowncmd = '%s shell chown %s.%s %s' % (adbcmd, owner, group, target_dir) +rc, output = getstatusoutput(chowncmd) +if rc != 0: + print 'Failed to change group(%s) and owner(%s) of file(%s): %s' % (group, + owner, target_dir, output) + sys.exit(1) + +chmodcmd = '%s shell chmod 771 %s' % (adbcmd, target_dir) +rc, output = getstatusoutput(chmodcmd) +if rc != 0: + print 'Failed to change chmod to 771 for file(%s): %s' % (target_dir, + output) + sys.exit(1) + +pushcmd = '%s push %s %s' % (adbcmd, source, target) +rc, output = getstatusoutput(pushcmd) +if rc != 0: + print 'Failed to push file(%s) to file(%s): %s' % (source, target, + output) + sys.exit(1) + +chowncmd = '%s shell chown %s.%s %s' % (adbcmd, owner, group, target) +rc, output = getstatusoutput(chowncmd) +if rc != 0: + print 'Failed to change group(%s) and owner(%s) of file(%s): %s' % (group, + owner, target, output) + sys.exit(1) + +chmodcmd = '%s shell chmod 660 %s' % (adbcmd, target) +rc, output = getstatusoutput(chmodcmd) +if rc != 0: + print 'Failed to change chmod to 771 for file(%s): %s' % (target, output) + sys.exit(1) + +target_dir = '/data/data/org.zeroxlab.zeroxbenchmark/files' +mkdircmd = '%s shell mkdir %s' % (adbcmd, target_dir) +rc, output = getstatusoutput(mkdircmd) +if rc != 0: + print 'Failed to create directory(%s): %s' % (target_dir, output) + sys.exit(1) + +chowncmd = '%s shell chown %s.%s %s' % (adbcmd, owner, group, target_dir) +rc, output = getstatusoutput(chowncmd) +if rc != 0: + print 'Failed to change group(%s) and owner(%s) of file(%s): %s' % (group, + owner, target_dir, output) + sys.exit(1) + +chmodcmd = '%s shell chmod 771 %s' % (adbcmd, target_dir) +rc, output = getstatusoutput(chmodcmd) +if rc != 0: + print 'Failed to change chmod to 771 for file(%s): %s' % (target_dir, + output) + sys.exit(1) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/android-0xbenchmark/android_0xbenchmark_wait.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/android-0xbenchmark/android_0xbenchmark_wait.py new file mode 100755 index 0000000..dcfdbfc --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/android-0xbenchmark/android_0xbenchmark_wait.py @@ -0,0 +1,54 @@ +#!/usr/bin/python + +# Copyright (c) 2011 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +import sys +import time + +from lava_android_test.utils import stop_at_pattern + +adb_cmd = "adb" +# here assumes that there is no serial number will start with '-' +# and the options passed are start with '-' as first option +if len(sys.argv) > 1 and (not sys.argv[1].startswith('-')): + adb_cmd = "adb -s %s" % (sys.argv[1]) + +timeout = 2400 +for index in range(1, len(sys.argv)): + arg = sys.argv[index] + if arg == '-timeout' and \ + (index + 1 < len(sys.argv)) and \ + sys.argv[index + 1]: + try: + timeout = int(sys.argv[index + 1]) + except ValueError: + pass + finally: + break + +logcat_cmd = '%s logcat' % (adb_cmd) +pattern = "Displayed org.zeroxlab.zeroxbenchmark/.Report" + +if not stop_at_pattern(command=logcat_cmd, pattern=pattern, timeout=timeout): + print "0xbench Test: TIMEOUT Fail" + sys.exit(1) + +time.sleep(3) +sys.exit(0) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/bctest.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/bctest.py new file mode 100644 index 0000000..5609277 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/bctest.py @@ -0,0 +1,52 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Android Team <linaro-android@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +bctest test covers testing of a couple of binder IOCTLS. +We can think of it as a subset of "shell-binder" test, +which is much more exhaustive and is the main binder test to go for. +binder test "bctest" that is pre-intalled on Juice Android builds. + +**URL:** http://android.git.linaro.org/gitweb?p=platform/frameworks/base.git;a=blob;f=cmds/servicemanager/bctest.c + +**Default options:** "publish 1" +""" + +import lava_android_test.config +import lava_android_test.testdef + +test_name = 'bctest' + +DEFAULT_OPTIONS = 'publish 1' + +INSTALL_STEPS_ADB_PRE = [] +ADB_SHELL_STEPS = ['bctest $(OPTIONS)'] +PATTERN = "(?P<test_case_id>.*ioctl)\s(?P<result>(PASS|FAIL)?).*" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser, + default_options=DEFAULT_OPTIONS) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/big_LITTLE.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/big_LITTLE.py new file mode 100644 index 0000000..7aa6b1f --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/big_LITTLE.py @@ -0,0 +1,51 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Drives big.LITTLE test scripts that are pre-intalled on Linaro Android +builds of big.LITTLE. +By default will run all the tests on the target including tests on: +basic module and switcher/cache-coherency/data-corruption/disk-io/governor/memory/perf/switcher/vfp-ffmpeg + +**URL:** https://linaro-private.git.linaro.org/gitweb?p=bL_tests/bL_iks_tests.git;a=summary + +**Default options:** "-a" +""" + +import lava_android_test.testdef + +test_name = 'big_LITTLE' + +DEFAULT_OPTIONS='-a' + +INSTALL_STEPS_ADB_PRE = [] +ADB_SHELL_STEPS = ['run_stress_switcher_tests.sh $(OPTIONS)'] +PATTERN = "(?P<test_case_id>.*-*)\s+:\s+(?P<result>(PASS|FAIL))" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser, + default_options=DEFAULT_OPTIONS) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/blackbox.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/blackbox.py new file mode 100644 index 0000000..790569b --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/blackbox.py @@ -0,0 +1,494 @@ +# Copyright (c) 2012 Linaro Limited + +# Author: Zygmunt Krynicki <zygmunt.krynicki@linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Bridge for the black-box testing implemented by lava-blackbox. +It covers all the available tests in AOSP. +The list is available here from APMTest to ZipFileROTest + +**Sample Result URL:** http://validation.linaro.org/lava-server/dashboard/image-reports/linaro-android-member-ti_panda-linaro + +**URL:** https://github.com/zyga/lava-blackbox + +**Default options:** None +""" + +import datetime +import functools +import logging +import os +import pdb +import shutil +import subprocess +import tempfile + +from linaro_dashboard_bundle.evolution import DocumentEvolution +from linaro_dashboard_bundle.io import DocumentIO + +from lava_android_test.config import get_config + + +def debuggable_real(func): + """ + Helper for debugging functions that otherwise have their exceptions + consumed by the caller. Any exception raised from such a function will + trigger a pdb session when 'DEBUG_DEBUGGABLE' environment is set. + """ + @functools.wraps(func) + def debuggable_decorator(*args, **kwargs): + try: + return func(*args, **kwargs) + except: + logging.exception("exception in @debuggable function") + pdb.post_mortem() + return debuggable_decorator + + +def debuggable_noop(func): + return func + + +if os.getenv("DEBUG_DEBUGGABLE"): + debuggable = debuggable_real +else: + debuggable = debuggable_noop + + +class SuperAdb(object): + """ + Class that implements certain parts of ADB()-like API differently. + """ + + def __init__(self, stock_adb): + # Name of the adb executable with any required arguments, + # such as -s 'serial' + self._adb_cmd = stock_adb.adb.split() + + def __call__(self, command, *args, **kwargs): + """ + Invoke adb command. + + This call is somewhat special that it wraps two subprocess helper + functions: check_call and check_output. They are called depending + on the keyword argument 'stdout', if passed as None then output + is _not_ saved and is instantly streamed to the stdout of the running + program. In any other case stdout is buffered and saved, then returned + """ + cmd = self._adb_cmd + command + if "stdout" in kwargs and kwargs['stdout'] is None: + del kwargs['stdout'] + return subprocess.check_call(cmd, *args, **kwargs) + else: + return subprocess.check_output(cmd, *args, **kwargs) + + def listdir(self, dirname): + """ + List directory entries on the android device. + + Similar to adb.listdir() as implemented in ADB() but generates + subsequent lines instead of returning a big lump of text for the + developer to parse. Also, instead of using 'ls' on the target it + uses the special 'ls' command built into adb. + + The two special entries, . and .., are omitted + """ + for line in self(['ls', dirname]).splitlines(): + # a, b and c are various pieces of stat data + # but we don't need that here. + a, b, c, pathname = line.split(' ', 3) + if pathname not in ('.', '..'): + yield pathname + + +class AdbMixIn(object): + """ + Mix-in class that assists in setting up ADB. + + lava-android-test uses the setadb()/getadb() methods to pass the ADB object + (which encapsulates connection data for the specific device we will be + talking to). + + Since the ADB object has fixed API and changes there are beyond the scope + of this test any extra stuff we want from ADB will be provided by the + SuperAdb class. + + This mix-in class that has methods expected by lava-android-test and + exposes two properties, adb and super_adb. + """ + + adb = None + + def setadb(self, adb=None): + if self.adb is None and adb is not None: + self.adb = adb + else: + self.adb = adb + self.super_adb = SuperAdb(adb) + + def getadb(self): + return self.adb + + +class Sponge(object): + """ + A simple namespace-like object that anyone can assign and read freely. + + To get some understanding of what is going on both reads and writes are + logged. + """ + + def __getattr__(self, attr): + return super(Sponge, self).__getattr__(attr) + + def __setattr__(self, attr, value): + super(Sponge, self).__setattr__(attr, value) + + +class FutureFormatDetected(Exception): + """ + Exception raised when the code detects a new, unsupported + format that was created after this library was written. + + Since formats do not have partial ordering we can only detect + a future format when the document format is already at the "latest" + value, as determined by DocumentEvolution.is_latest(), but the actual + format is not known to us. + + Typically this won't happen often as document upgrades are not performed + unless necessary. The only case when this may happen is where the bundle + loaded from the device was already using a future format to begin with. + """ + + def __init__(self, format): + self.format = format + + def __str__(self): + "Unsupported, future format: %s" % self.format + + def __repr__(self): + return "FutureFormatDetected(%r)" % self.format + + +class BlackBoxTestBridge(AdbMixIn): + """ + Bridge for interacting with black box tests implemented as something that + looks like android test definition. + """ + + # NOTE: none of the tests will actually carry this ID, it is simply used + # here so that it's not a magic value. + testname = 'blackbox' + + def __init__(self): + """ + Initialize black-box test bridge + """ + # The sponge object is just a requirement from the API, it is not + # actually used by us in any way. The framework assigns a skeleton + # test result there but we don't really need it. The Sponge object + # is a simple 'bag' or namespace that will happily accept and record + # any values. + self.parser = Sponge() + + def install(self, install_options=None): + """ + "Install" blackbox on the test device. + + Black box tests cannot be installed, they must be pre-baked into the + image. To conform to the 'protocol' used by lava-android-test we will + perform a fake 'installation' of the black box tests by creating a + directory that lava-android-test is checking for. We do that only if + the lava-blackbox executable, which is the entry point to black box + tests exists in the image. + + ..note:: + This method is part of the lava-android-test framework API. + """ + if not self.adb.exists(self._blackbox_pathname): + # Sadly lava-android-test has no exception hierarchy that we can + # use so all problems are reported as RuntimeError + raise RuntimeError( + 'blackbox test cannot be "installed" as they must be built' + ' into the image.' + ' See https://github.com/zyga/android-lava-wrapper' + ' for details.') + else: + self.adb.makedirs(self._fake_install_path) + + def uninstall(self): + """ + Conformance method to keep up with the API required by + lava-android-test. It un-does what install() did by removing the + _fake_install_path directory from the device. + + ..note:: + This method is part of the lava-android-test framework API. + """ + if self.adb.exists(self._fake_install_path): + self.adb.rmtree(self._fake_install_path) + + @debuggable + def run(self, quiet=False, run_options=None): + """ + Run the black-box test on the target device. + + Use ADB to run the black-box executable on the device. Keep the results + in the place that lava-android-test expects us to use. + + ..note:: + This method is part of the lava-android-test framework API. + """ + # The blackbox test runner will create a directory each time it is + # started. All of those directories will be created relative to a so + # called spool directory. Instead of using the default spool directory + # (which can also change) we will use the directory where + # lava-android-test keeps all of the results. + spool_dir = get_config().resultsdir_android + logging.debug("Using spool directory for black-box testing: %r", spool_dir) + stuff_before = frozenset(self.super_adb.listdir(spool_dir)) + blackbox_command = [ + 'shell', self._blackbox_pathname, + '--spool', spool_dir, + '--run-all-tests'] + # Let's run the blackbox executable via ADB + logging.debug("Starting black-box tests...") + self.super_adb(blackbox_command, stdout=None) + logging.debug("Black-box tests have finished!") + stuff_after = frozenset(self.super_adb.listdir(spool_dir)) + # Check what got added to the spool directory + new_entries = stuff_after - stuff_before + if len(new_entries) == 0: + raise RuntimeError("Nothing got added to the spool directory") + elif len(new_entries) > 1: + raise RuntimeError("Multiple items added to the spool directory") + result_id = list(new_entries)[0] + print "The blackbox test have finished running, the result id is %r" % result_id + return result_id + + def parse(self, result_id): + """ + UNIMPLEMENTED METHOD + + Sadly this method is never called as lava-android-test crashes before + it gets to realize it is processing blackbox results and load this + class. This crash _may_ be avoided by hiding the real results of + blackbox and instead populating the results directory with dummy test + results that only let LAVA figure out that blackbox is the test to + load. Then we could monkey patch other parts and it could be + implemented. + + ONCE THIS IS FIXED THE FOLLOWING DESCRIPTION SHOULD APPLY + + Parse and save results of previous test run. + + The result_id is a name of a directory on the Android device ( + relative to the resultsdir_android configuration option). + + ..note:: + This method is part of the lava-android-test framework API. + """ + # Sadly since the goal is integration with lava lab I don't have the + # time to do it. In the lab we use lava-android-test run -o anyway. + raise NotImplementedError() + + def _get_combined_bundle(self, result_id): + """ + Compute the combined bundle of a past run and return it + """ + config = get_config() + temp_dir = tempfile.mkdtemp() + remote_bundle_dir = os.path.join(config.resultsdir_android, result_id) + try: + self._copy_all_bundles(remote_bundle_dir, temp_dir) + bundle = self._combine_bundles(temp_dir) + finally: + shutil.rmtree(temp_dir) + return bundle + + # Desired format name, used in a few methods below + _desired_format = "Dashboard Bundle Format 1.3" + + def _copy_all_bundles(self, android_src, host_dest): + """ + Use adb pull to copy all the files from android_src (android + fileystem) to host_dest (host filesystem). + """ + logging.debug("Saving bundles from %s to %s", android_src, host_dest) + for name in self.super_adb.listdir(android_src): + logging.debug("Considering file %s", name) + # NOTE: We employ simple filtering for '.json' files. This prevents + # spurious JSON parsing errors if the result directory has + # additional files of any kind. + # + # We _might_ want to lessen that eventually restriction but at this + # time blackbox is really designed to be self-sufficient so there + # is no point of additional files. + if not name.endswith('.json'): + continue + remote_pathname = os.path.join(android_src, name) + local_pathname = os.path.join(host_dest, name) + try: + logging.debug( + "Copying %s to %s", remote_pathname, local_pathname) + self.adb.pull(remote_pathname, local_pathname) + except: + logging.exception("Unable to copy bundle %s", name) + + def _combine_bundles(self, dirname): + """ + Combine all bundles from a previous test run into one bundle. + + Returns the aggregated bundle object + + Load, parse and validate each bundle from the specified directory and + combine them into one larger bundle. This is somewhat tricky. Each + bundle we coalesce may be generated by a different, separate programs + and may, thus, use different formats. + + To combine them all correctly we need to take two precautions: + 1) All bundles must be updated to a single, common format + 2) No bundle may be upgraded beyond the latest format known + to this code. Since the hypothetical 2.0 format may be widely + different that we cannot reliably interpret anything beyond + the format field. To prevent this we use the evolution API + to carefully upgrade only to the "sentinel" format, 1.3 + (at this time) + """ + # Use DocumentIO.loads() to preserve the order of entries. + # This is a very small touch but it makes reading the results + # far more pleasant. + aggregated_bundle = DocumentIO.loads( + '{\n' + '"format": "' + self._desired_format + '",\n' + '"test_runs": []\n' + '}\n')[1] + # Iterate over all files there + for name in os.listdir(dirname): + bundle_pathname = os.path.join(dirname, name) + # Process bundle one by one + try: + format, bundle = self._load_bundle(bundle_pathname) + self._convert_to_common_format(format, bundle) + self._combine_with_aggregated(aggregated_bundle, bundle) + except: + logging.exception("Unable to process bundle %s", name) + # Return the aggregated bundle + return aggregated_bundle + + def _load_bundle(self, local_pathname): + """ + Load the bundle from local_pathname. + + There are various problems that can happen here but + they should all be treated equally, the bundle not + being used. This also transparently does schema validation + so the chance of getting wrong data is lower. + """ + with open(local_pathname, 'rt') as stream: + format, bundle = DocumentIO.load(stream) + return format, bundle + + def _convert_to_common_format(self, format, bundle): + """ + Convert the bundle to the common format. + + This is a careful and possibly fragile process that may + raise FutureFormatDetected exception. If that happens + then desired_format (encoded in the function itself) must be + changed and the code reviewed for any possible changes + required to support the more recent format. + """ + while True: + # Break conditions, encoded separately for clarity + if format == self._desired_format: + # This is our desired break condition, when format + # becomes (or starts as) the desired format + break + if DocumentEvolution.is_latest(bundle): + # This is a less desired break condition, if we + # got here then the only possible explanation is + # that some program started with format > desired_format + # and the DocumentEvolution API is updated to understand + # it but we are not. In that case let's raise an exception + raise FutureFormatDetected(format) + # As long as the document format is old keep upgrading it + # step-by-step. Evolution is done in place + DocumentEvolution.evolve_document(bundle, one_step=True) + + def _combine_with_aggregated(self, aggregated_bundle, bundle): + """ + Combine the bundle with the contents of aggregated_bundle. + + This method simply transplants all the test runs as that is what + the bundle format was designed to be - a simple container for test + runs. + """ + assert bundle["format"] == self._desired_format + assert aggregated_bundle["format"] == self._desired_format + aggregated_bundle["test_runs"].extend(bundle.get("test_runs", [])) + + @property + def _blackbox_pathname(self): + """ + The path to the blackbox bridge on the device. + """ + return "/system/bin/lava-blackbox" + + @property + def _fake_install_path(self): + """ + The path that we create on the android system to + indicate that the black box test is installed. + + This is used by uninstall() and install() + """ + config = get_config() + return os.path.join(config.installdir_android, self.testname) + + def _monkey_patch_lava(self): + """ + Monkey patch the implementation of lava_android_test.commands.generate_bundle + + This change is irreversible but given the one-off nature of + lava-android-test this is okay. It should be safe to do this since + LAVA will only load the blackbox test module if we explicitly request + to run it. At that time no other tests will run in the same process. + + This method should not be used once lava-android-test grows a better + API to allow us to control how bundles are generated. + """ + from lava_android_test import commands + def _phony_generate_bundle(serial=None, result_id=None, + test=None, test_id=None, attachments=[]): + if result_id is None: + raise NotImplementedError + return self._get_combined_bundle(result_id) + commands.generate_bundle = _phony_generate_bundle + logging.warning( + "The 'blackbox' test definition has monkey-patched the function" + " lava_android_test.commands.generate_bundle() if you are _not_" + " running the blackbox test or are experiencing odd problems/crashes" + " below please look at this method first") + + +# initialize the blackbox test definition object +testobj = BlackBoxTestBridge() + +# Then monkey patch lava-android-test so that parse keeps working +testobj._monkey_patch_lava() diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/bluetooth.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/bluetooth.py new file mode 100644 index 0000000..2ca1d8c --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/bluetooth.py @@ -0,0 +1,47 @@ +# copyright (C) 2012 Linaro Limited +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +This test helps validating basic bluetooth functionality by executing the +Android BluetoothTestRunner tests. + +**URL:** http://android.git.linaro.org/gitweb?p=platform/frameworks/base.git;a=blob;f=core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestRunner.java + +**Default options:** None +""" + +import lava_android_test.testdef + +test_name = 'bluetooth' + +cmd = ("am instrument -r -e enable_iterations 2 -e discoverable_iterations 2" + " -e scan_iterations 2 -e enable_pan_iterations 2 -e pair_iterations 1 " + " -e device_address $(OPTIONS) " + " -w com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner") +RUN_ADB_SHELL_STEPS = [cmd] + +inst = lava_android_test.testdef.AndroidTestInstaller() +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=RUN_ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidInstrumentTestParser() +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/busybox.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/busybox.py new file mode 100644 index 0000000..cc32fcc --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/busybox.py @@ -0,0 +1,57 @@ +# Copyright (c) 2011 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +This is a simple test to ensure busybox is installed on an Android build and +can execute some basic busybox commands + +**URL:** http://www.busybox.net/ + +**Default Options:** None +""" + +import os +import lava_android_test.testdef +from lava_android_test.config import get_config + +test_name = 'busybox' +config = get_config() +curdir = os.path.realpath(os.path.dirname(__file__)) +test_sh_name = 'busybox_test.sh' +test_sh_path = os.path.join(curdir, test_name, test_sh_name) +test_sh_android_path = os.path.join(config.installdir_android, + test_name, test_sh_name) + +INSTALL_STEPS_ADB_PRE = ['push %s %s ' % (test_sh_path, + test_sh_android_path), + 'shell chmod 777 %s' % test_sh_android_path] + +ADB_SHELL_STEPS = [test_sh_android_path] +#PATTERN = "^(?P<test_case_id>\w+):\W+(?P<measurement>\d+\.\d+)" +PATTERN = "^\s*(?P<test_case_id>\w+)=(?P<result>\w+)\s*$" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/busybox/busybox_test.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/busybox/busybox_test.sh new file mode 100755 index 0000000..455a75e --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/busybox/busybox_test.sh @@ -0,0 +1,35 @@ +#!/system/bin/sh + +test_func(){ + if [ ! -f /system/bin/busybox ]; then + echo "busybox=unexist" + exit + fi + + if /system/bin/busybox [ $# -lt 1 ]; then + return 0 + fi + test_cmd=$1 + /system/bin/busybox "$@" 1>/dev/null 2>/dev/null + if /system/bin/busybox [ $? -ne 0 ]; then + echo "${test_cmd}=fail" + else + echo "${test_cmd}=pass" + fi +} + +rm -r /data/local/tmp/busybox 1>/dev/null 2>/dev/null + +test_func mkdir /data/local/tmp/busybox +test_func touch /data/local/tmp/busybox/test.txt +test_func ls /data/local/tmp/busybox/test.txt +test_func ps +test_func whoami +test_func which busybox +test_func basename /data/local/tmp/busybox/test.txt +test_func cp /data/local/tmp/busybox/test.txt /data/local/tmp/busybox/test2.txt +test_func rm /data/local/tmp/busybox/test2.txt +test_func dmesg +test_func grep service /init.rc + +rm -r /data/busybox 1>/dev/null 2>/dev/null diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cache_coherency.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cache_coherency.py new file mode 100644 index 0000000..72f1709 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cache_coherency.py @@ -0,0 +1,47 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Stressapptest tries to maximize randomized traffic to memory from processor +and I/O, with the intent of creating a realistic high load situation +in order to test the existing hardware devices in a computer. +Used for cache-coherency testing on big.LITTLE here. + +**URL:** http://android.git.linaro.org/gitweb?p=platform/external/stressapptest.git;a=summary + +**Default options:** None +""" +import lava_android_test.testdef + +test_name = 'cache_coherency' + +INSTALL_STEPS_ADB_PRE = [] +ADB_SHELL_STEPS = ['stressapptest -M 16 --cc_test -s 10'] +PATTERN = "^\s*(?P<test_case_id>Status?):\s+(?P<result>(PASS|FAIL)?)\s+-\s+" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/commands/__init__.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/commands/__init__.py new file mode 100644 index 0000000..075f164 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/commands/__init__.py @@ -0,0 +1,30 @@ +# copyright (C) 2012 Linaro Limited +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +This directory contains the test that only needs to run an android command and +specify the output pattern that to parse the command ouptu to get result. +Please see the example.py for a reference. +Please note this is not a test that can be run. + +**URL:** None + +**Default options:** None +""" diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/commands/bionic_libc_tests.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/commands/bionic_libc_tests.py new file mode 100644 index 0000000..4beaac3 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/commands/bionic_libc_tests.py @@ -0,0 +1,29 @@ +# Copyright (c) 2013 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +Runs the stock bionic tests. + +**URL:** http://android.git.linaro.org/gitweb?p=platform/system/extras.git;a=tree;f=tests/bionic/libc + +**Default Options:** None +""" + +RUN_ADB_SHELL_STEPS = ['run-bionic-tests.sh'] +PATTERN = "(?P<test_case_id>.*-*)\s+:\s+(?P<result>(PASS|FAIL))" diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/commands/example.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/commands/example.py new file mode 100644 index 0000000..2a175da --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/commands/example.py @@ -0,0 +1,31 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Example for how to add tests that only need to run an android command +and specify the output pattern to parse the command ouput to get result. + +**URL:** None + +**Default options:** None +""" +RUN_ADB_SHELL_STEPS = ['tjunittest'] +PATTERN = ("^\s*(?P<test_case_id>.+)\s+\.\.\.\s+(?P<result>\w+)\." + "\s+(?P<measurement>[\d\.]+)\s+(?P<units>\w+)\s*$") diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/commands/linaro_android_kernel_test.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/commands/linaro_android_kernel_test.py new file mode 100644 index 0000000..39fd33c --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/commands/linaro_android_kernel_test.py @@ -0,0 +1,30 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +Runs the linaro kernel unit tests including: + ashmem/ashmem_expanded/alarmdev/logger/binder/sync + +**URL:** https://linaro-private.git.linaro.org/gitweb?p=android/linaro-android-kernel-test.git;a=summary + +**Default Options:** None +""" + +RUN_ADB_SHELL_STEPS = ['linaro-android-kernel-tests.sh'] +PATTERN = "\s*\[(?P<test_case_id>\w+)\]:\s\w+\s(?P<result>\w+)" diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/commands/tjunittest.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/commands/tjunittest.py new file mode 100644 index 0000000..e377fc4 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/commands/tjunittest.py @@ -0,0 +1,30 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Tests the various code paths in the TurboJPEG C Wrapper + +**URL:** https://git.linaro.org/gitweb?p=people/tomgall/libjpeg-turbo/libjpeg-turbo.git;a=blob_plain;f=tjunittest.c + +**Default options:** None +""" +ADB_SHELL_STEPS = ['tjunittest'] +PATTERN = ("^\s*(?P<test_case_id>.+)\s+\.\.\.\s+(?P<result>\w+)\." + "\s+(?P<measurement>[\d\.]+)\s+(?P<units>\w+)\s*$") diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts.py new file mode 100644 index 0000000..6e0eec7 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts.py @@ -0,0 +1,70 @@ +# Copyright (C) 2012 Linaro Limited + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +This test executes the Android Compatibility Test Suite (CTS) to verify if +a given build meets all the criteria. + +**URL:** http://source.android.com/compatibility/cts-intro.html + +**Default Options:** None +""" + +import os + +from lava_android_test.testdef import (Attachment, + AndroidTest, + AndroidTestInstaller, + AndroidTestRunner, + AndroidTestParser) + +test_name = 'cts' + +curdir = os.path.realpath(os.path.dirname(__file__)) + +RUN_STEPS_HOST_PRE = ['python %s/cts/cts_wrapper.py $(SERIAL) $(OPTIONS)' % ( + curdir)] + +inst = AndroidTestInstaller() +run = AndroidTestRunner(steps_host_pre=RUN_STEPS_HOST_PRE) + +# cts-tf > [2K06-17 14:24:02 I/10.254.21.142:5555: android.acceleration. +# cts.HardwareAccelerationTest#testIsHardwareAccelerated PASS +pattern = ("^cts-tf.*\s*[\d-]+\s+[\d:]+\s+I\/\S+\:\s+(?P<test_case_id>\S+#\S+)" + "\s+(?P<result>\S+)\s*$") +parser = AndroidTestParser(pattern=pattern, + fixupdict={'PASS': 'pass', 'FAIL': 'fail'}) + +attachments = [ + Attachment(pathname="/data/local/tmp/logcat.log", + mime_type="text/plain"), + Attachment(pathname="/data/local/tmp/kmsg.log", + mime_type="text/plain"), + Attachment(pathname="/data/local/tmp/cts-results.zip", + mime_type="application/zip"), + Attachment(pathname="/data/local/tmp/device_logcat.zip", + mime_type="application/zip"), + Attachment(pathname="/data/local/tmp/host_log.zip", + mime_type="application/zip") + ] +testobj = AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser, + attachments=attachments) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts/cts_list_result_wrapper.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts/cts_list_result_wrapper.sh new file mode 100755 index 0000000..b6ef869 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts/cts_list_result_wrapper.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# Copyright (C) 2012 Linaro Limited + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +#http://source.android.com/compatibility/downloads.html + +echo "./android-cts/tools/cts-tradefed l r" +./android-cts/tools/cts-tradefed l r |tee cts_list_results.log + +exit 0
\ No newline at end of file diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts/cts_prepare.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts/cts_prepare.sh new file mode 100755 index 0000000..6b677a6 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts/cts_prepare.sh @@ -0,0 +1,131 @@ +#!/bin/bash +# Copyright (C) 2012 Linaro Limited + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +#http://source.android.com/compatibility/downloads.html +if [ -z "$cts_pkg" ]; then +cts_pkg="android-cts-linux_x86-arm-latest.zip" +fi +media_pkg="android-cts-media-latest.zip" +site_url="http://testdata.validation.linaro.org/cts/" +#site_url="http://192.168.1.127/images/cts/" +#export http_proxy=http://localhost:3128 + +cts_pkg_url="${site_url}${cts_pkg}" +media_pkg_url="${site_url}${media_pkg}" + +ADB_OPTION="" +SERIAL="" +if [ "x${1}" != "x" ]; then + ADB_OPTION="-s ${1}" + SERIAL="${1}" +fi +ADB_CMD="adb ${ADB_OPTION}" + + +function download_unzip(){ + if [ -z "$1" ] || [ -z "$2" ]; then + return + fi + url="${1}" + pkg="${2}" + + echo "wget --connect-timeout=30 -S --progress=dot -e dotbytes=2M ${url} -O ${pkg}" + wget -c -t 20 --connect-timeout=30 -S --progress=dot -e dotbytes=2M "${url}" -O ${pkg} + if [ $? -ne 0 ]; then + echo "Failed to get the package ${url}" + exit 1 + fi + echo "unzip ${pkg}" + unzip ${pkg} + if [ $? -ne 0 ]; then + echo "Faild to unzip the package " + exit 1 + fi +} + +function main(){ + rm -fr ${cts_pkg} ${media_pkg} android-cts + download_unzip "${cts_pkg_url}" ${cts_pkg} + + #1. Your phone should be running a user build (Android 4.0 and later) from source.android.com + #2. Please refer to this link on the Android developer site and set up your device accordingly. + #3. Make sure that your device has been flashed with a user build (Android 4.0and later) before you run CTS. + ####Step 1~3 is done by deployment + + #4. You need to ensure the Text To Speech files are installed on the device. + # You can check via Settings > Speech synthesis > Install voice data + # before running CTS tests. + # (Note that this assumes you have Android Market installed on the device, + # if not you will need to install the files manually via adb) + ##TODO don't know how to do this yet + + #5. Make sure the device has a SD card plugged in and the card is empty. + # Warning: CTS may modify/erase data on the SD card plugged in to the device. + #6. Do a factory data reset on the device (Settings > SD Card & phone storage >Factory data reset). + # Warning: This will erase all user data from the phone. + #7. Make sure no lock pattern is set on the device (Settings > Security > Screen Lock should be 'None'). + #8. Make sure the "USB Debugging" development option is checked (Settings >Developer options > USB debugging). + #9. Make sure Settings > Developer options > Stay Awake is checked + #10. Make sure Settings > Developer options > Allow mock locations is checked + ####Step 5~10 is done by deployment + + #11. Make sure device is connected to a functioning Wi-Fi network (Settings > WiFi) + ${ADB_CMD} shell am start -a android.intent.action.MAIN -n com.android.settings/.Settings + ${ADB_CMD} shell service call wifi 13 i32 1 + sleep 5 + + #12. Make sure the device is at the home screen at the start of CTS (Press the home button). + ${ADB_CMD} shell input keyevent 3 + sleep 3 + + #13. While a device is running tests, it must not be used for any other tasks. + #14. Do not press any keys on the device while CTS is running. + # Pressing keys or touching the screen of a test device will interfere with the running tests and may lead to test failures. + #####Steps 13~14 should be the ok because nobody will operation the test target. + + #15. Set up accessibility tests: + echo "${ADB_CMD} install -r android-cts/repository/testcases/CtsDelegatingAccessibilityService.apk" + ${ADB_CMD} install -r android-cts/repository/testcases/CtsDelegatingAccessibilityService.apk + if [ $? -ne 0 ]; then + echo "Faild to install CtsDelegatingAccessibilityService.apk" + exit 1 + fi + ## On the device, enable Settings > Accessibility > DelegatingAccessibility Service + ${ADB_CMD} push $2 /data/local/tmp/ + ${ADB_CMD} shell am start -a android.intent.action.VIEW -n com.android.settings/.Settings + ${ADB_CMD} shell uiautomator runtest ctshelper.jar -c com.linaro.ctshelper#AccessibilityHelper + + + #16. Set up device administration tests: + echo "${ADB_CMD} install -r android-cts/repository/testcases/CtsDeviceAdmin.apk" + ${ADB_CMD} install -r android-cts/repository/testcases/CtsDeviceAdmin.apk + if [ $? -ne 0 ]; then + echo "Faild to install CtsDeviceAdmin.apk" + exit 1 + fi + ## On the device, enable Settings > Security > Device Administrators >android.deviceadmin.cts.CtsDeviceAdmin* settings + ${ADB_CMD} shell am start -a android.intent.action.VIEW -n com.android.settings/.Settings + ${ADB_CMD} shell uiautomator runtest ctshelper.jar -c com.linaro.ctshelper#SecurityHelper + ${ADB_CMD} shell am start -a android.intent.action.VIEW -n com.android.launcher/com.android.launcher2.Launcher + + exit 0 +} + +main "$@" diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts/cts_redirect.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts/cts_redirect.sh new file mode 100755 index 0000000..b23b3a5 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts/cts_redirect.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# Copyright (C) 2012 Linaro Limited + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +output_file=${1} && shift +eval "$@" &> ${output_file} & +echo $! +exit 0 diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts/cts_run_wrapper.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts/cts_run_wrapper.sh new file mode 100755 index 0000000..6e4e5ba --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts/cts_run_wrapper.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# Copyright (C) 2012 Linaro Limited + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +#http://source.android.com/compatibility/downloads.html + +echo ./android-cts/tools/cts-tradefed "$@" --disable-reboot +./android-cts/tools/cts-tradefed "$@" --disable-reboot > ./cts_output.log 2>&1 +exit 0 diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts/cts_wrapper.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts/cts_wrapper.py new file mode 100755 index 0000000..deca63c --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts/cts_wrapper.py @@ -0,0 +1,346 @@ +#!/usr/bin/python + +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import re +import sys +import pexpect +import time +import xml.dom.minidom +from zipfile import ZipFile + +from lava_android_test.adb import ADB +from lava_android_test.utils import stop_at_pattern +from lava_android_test.utils import find_files + +adb = ADB(sys.argv[1]) +curdir = os.path.realpath(os.path.dirname(__file__)) + + +def stop_at_cts_pattern(command=None, pattern=None, timeout=-1): + if not command: + return + + if not pattern: + response = [pexpect.EOF] + else: + response = [pattern, pexpect.EOF] + + result = True + proc_cts = pexpect.spawn(command, logfile=sys.stdout) + time.sleep(200) + try: + match_id = proc_cts.expect(response, timeout=timeout) + if match_id == 0: + time.sleep(5) + except pexpect.TIMEOUT: + result = False + finally: + proc_cts.sendcontrol('C') + proc_cts.sendline('') + target_dir = os.path.join(os.getcwd(), + './android-cts/repository/results/') + for zip_f in find_files(target_dir, '.zip'): + ret_code = adb.push(zip_f, '/data/local/tmp/cts-results.zip')[0] + if ret_code != 0: + print "Failed to push file %s to device(%s)" % (zip_f, + adb.get_serial()) + log_target_dir = os.path.join(os.getcwd(), + './android-cts/repository/logs/') + for zip_f in find_files(log_target_dir, '.zip'): + base_name = os.path.basename(zip_f) + if base_name.startswith('device_logcat_'): + base_name = 'device_logcat.zip' + if base_name.startswith('host_log_'): + base_name = 'host_log.zip' + + ret_code = adb.push(zip_f, '/data/local/tmp/%s' % base_name)[0] + if ret_code != 0: + print "Failed to push file %s to device(%s)" % (zip_f, + adb.get_serial()) + with ZipFile(zip_f) as log_fd: + print '=========Log file [%s] starts=========>>>>>' % ( + base_name) + f_name = base_name.replace('.zip', '.txt') + for line in log_fd.open(f_name).readlines(): + print line.rstrip() + print '<<<<<=========Log file [%s] ends=========' % base_name + return result + + +def get_not_executed(): + list_result_path = os.path.join(curdir, 'cts_list_result_wrapper.sh') + list_result_cmd = "bash %s" % list_result_path + + pattern = 'CTS unknown' + if not stop_at_pattern(command=list_result_cmd, + pattern=pattern, timeout=5): + print "Failed to list the cts result for device(%s)" % adb.get_serial() + + with open('cts_list_results.log') as fd: + #0 17237 126 0 2012.06.23_03.31.49 CTS unknown + pattern = ("\s*\d+\s+\d+\s+\d+\s+(?P<no_executed>\d+)" + "\s+.+CTS\s+unknown\s*$") + pat = re.compile(pattern) + for line in fd.readlines(): + match = pat.search(line) + if not match: + continue + return match.groupdict()['no_executed'] + return 0 + + +def prepare_cts(): + cts_prepare_path = os.path.join(curdir, 'cts_prepare.sh') + cts_helper_jar_path = os.path.join(curdir, 'ctshelper.jar') + cts_prepare_cmd = "bash %s" % cts_prepare_path + if not stop_at_pattern(command="%s %s %s" % (cts_prepare_cmd, + adb.get_serial(), cts_helper_jar_path), + timeout=18000): + print "Preapration for CTS test times out" + return False + return True + + +def run_cts_with_plan(cts_cmd=None, plan='CTS', timeout=36000): + pattern = "Time:" + plan_command = '--plan %s' % plan + if cts_cmd: + plan_command = "%s %s --disable-reboot" % (cts_cmd, plan_command) + if not stop_at_cts_pattern(command=plan_command, pattern=pattern, + timeout=timeout): + print "CTS test times out" + return False + + return True + + +def run_cts_with_package(cts_cmd=None, package=None, timeout=36000): + if not package: + return True + pattern = "Time:" + plan_command = '--package %s' % package + if cts_cmd: + plan_command = "%s %s --disable-reboot" % (cts_cmd, plan_command) + if not stop_at_cts_pattern(command=plan_command, pattern=pattern, + timeout=timeout): + print "CTS test times out" + return False + + return True + + +def run_cts_with_class(cts_cmd=None, cls=None, method=None, timeout=36000): + if not cls: + return True + pattern = "Time:" + cmd = '--class %s' % cls + if method: + cmd = '%s --method %s' % (cmd, method) + + if cts_cmd: + cmd = "%s %s --disable-reboot" % (cts_cmd, cmd) + if not stop_at_cts_pattern(command=cmd, pattern=pattern, + timeout=timeout): + print "CTS test times out" + return False + + return True + + +def run_cts_continue(cts_cmd=None): + pattern = "Time:" + continue_command = '--continue-session 0' + if cts_cmd: + continue_command = "%s %s" % (cts_cmd, continue_command) + + while True: + number_of_not_executed = get_not_executed() + if number_of_not_executed and int(number_of_not_executed) > 0: + print ('Reconnect the adb connection before continuing ' + 'the CTS on device(%s)') % adb.get_serial() + if not adb.reconnect(): + print "Faile to reconnect the adb connection of device(%s)" % ( + adb.get_serial()) + break + + print "Continue the uncompleted CTS test on device(%s)" % ( + adb.get_serial()) + + if not stop_at_cts_pattern(command=continue_command, + pattern=pattern, + timeout=36000): + print "CTS test times out" + else: + break + + +def collect_log(command=None, output_file=None): + if command and output_file: + print 'Redirect the output of command[%s] to file[%s]' % (command, + output_file) + cmd = 'bash %s %s "%s"' % (os.path.join(curdir, 'cts_redirect.sh'), + output_file, command) + stdout = adb.run_cmd_host(cmd)[1] + if stdout: + return stdout[0].strip() + + return None + + +def collect_logs(): + + kmsg = {'command': + 'adb -s %s shell cat /proc/kmsg' % (adb.get_serial()), + 'output_file': 'kmsg.log'} + + logcat = {'command': + 'adb -s %s logcat -c; adb -s %s logcat -v time' % ( + adb.get_serial(), adb.get_serial()), + 'output_file': 'logcat.log'} + + ## define all the logs need to be collected + logs = [kmsg, logcat] + for log in logs: + pid = collect_log(command=log.get('command'), + output_file=log.get('output_file')) + if pid: + log['pid'] = pid + return logs + + +def push_log(logs=[]): + for log in logs: + log_file = log.get('output_file') + base_name = os.path.basename(log_file) + if log_file: + ret_code = adb.push(log_file, '/data/local/tmp/%s' % base_name)[0] + if ret_code != 0: + print "Failed to push file %s to device(%s)" % (log_file, + adb.get_serial()) + with open(log_file) as log_fd: + print '=========Log file [%s] starts=========>>>>>' % ( + log_file) + for line in log_fd.readlines(): + print line.rstrip() + print '<<<<<=========Log file [%s] ends=========' % log_file + + +def get_all_packages(plan_file=None): + if not plan_file: + return [] + if not os.path.exists(plan_file): + print "file(%s) does not exist" % plan_file + return [] + + package_list = [] + try: + dom = xml.dom.minidom.parse(plan_file) + test_plan = dom.getElementsByTagName("TestPlan")[0] + for entry in test_plan.getElementsByTagName("Entry"): + package_list.append(entry.attributes.get('uri').value) + except Exception as e: + print "Has exception to parse the xml file" + print "Exception: %s" % e + finally: + return package_list + + +def get_value_from_paras(paras=[], option=None, default=None): + if not option: + return default + + if not option in paras: + return default + + index = paras.index(option) + if len(paras) > index + 1: + return paras[index + 1] + + return default + + +def main(): + + package_name = None + plan_name = 'CTS' + class_name = None + method_name = None + timeout = 36000 + #--cts_pkg cts_package_file --package package_name --timeout 36000 + #--cts_pkg cts_package_file --plan plan_name --timeout 36000 + if len(sys.argv) > 2: + paras = sys.argv[2:] + cts_pkg = get_value_from_paras(paras=paras, option='--cts-pkg') + if cts_pkg: + os.environ["cts_pkg"] = cts_pkg + + java_home = get_value_from_paras(paras=paras, option='--java-home') + if java_home: + os.environ["PATH"] = java_home + "/bin" + os.pathsep + java_home \ + + "/jre/bin" + os.pathsep + os.environ["PATH"] + os.environ["JAVA_HOME"] = java_home + + package_name = get_value_from_paras(paras=paras, option='--package') + plan_name = get_value_from_paras(paras=paras, + option='--plan', + default='CTS') + timeout = get_value_from_paras(paras=paras, option='--timeout', + default=36000) + if timeout: + timeout = int(timeout) + + class_name = get_value_from_paras(paras=paras, option='--class') + method_name = get_value_from_paras(paras=paras, option='--method') + + run_wrapper_path = os.path.join('./android-cts/tools/cts-tradefed ') + run_wrapper_cmd = "%s" % run_wrapper_path + run_wrapper_cmd = '%s run cts --serial %s' % (run_wrapper_cmd, + adb.get_serial()) + + logs = collect_logs() + if not prepare_cts(): + sys.exit(1) + + try: + if package_name: + run_cts_with_package(cts_cmd=run_wrapper_cmd, package=package_name, + timeout=timeout) + elif class_name: + run_cts_with_class(cts_cmd=run_wrapper_cmd, cls=class_name, + method=method_name, timeout=timeout) + else: + run_cts_with_plan(cts_cmd=run_wrapper_cmd, plan=plan_name, + timeout=timeout) + + finally: + for log in logs: + pid = log.get('pid') + if pid: + adb.run_cmd_host('kill -9 %s' % pid) + + push_log(logs) + + sys.exit(0) + + +if __name__ == '__main__': + main() diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts/ctshelper.jar b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts/ctshelper.jar Binary files differnew file mode 100644 index 0000000..0c253ae --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/cts/ctshelper.jar diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/gatortest.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/gatortest.py new file mode 100644 index 0000000..a04ad6c --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/gatortest.py @@ -0,0 +1,52 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Ensures the gator daemon required by DS5 is up and running on the Android +device. + +**URL:** https://wiki.linaro.org/Platform/Android/DebugAndroidUsingDS-5 + +**Default Options:** None +""" + +import os + +import lava_android_test.testdef + +curdir = os.path.realpath(os.path.dirname(__file__)) +test_name = "gatortest" + +RUN_STEPS_HOST_POST = ['python %s/gatortest/daemoncheck.py $(SERIAL)' % curdir, + 'python %s/gatortest/modulecheck.py $(SERIAL)' % curdir] + +PATTERN = "^\s*(?P<test_case_id>\w+)\s*=\s*(?P<result>\w+)\s*$" + +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) + +run = lava_android_test.testdef.AndroidTestRunner( + steps_host_post=RUN_STEPS_HOST_POST) +# dummy installer +inst = lava_android_test.testdef.AndroidTestInstaller() + +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + runner=run, + installer=inst, + parser=parser) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/gatortest/daemoncheck.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/gatortest/daemoncheck.py new file mode 100644 index 0000000..a1fa1b9 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/gatortest/daemoncheck.py @@ -0,0 +1,20 @@ +import sys +from commands import getstatusoutput + +if len(sys.argv) == 1: + adbcmd = 'adb' +else: + adbcmd = 'adb -s %s' % (sys.argv[1]) + +cmd = '%s shell ps' % (adbcmd) +rc, output = getstatusoutput(cmd) +if rc != 0: + print 'Failed to run command %s : %s' % (cmd, output) + sys.exit(1) + +# parse output + +if output.find("gator") != -1: + print "gator_daemon_check=pass" +else: + print "gator_daemon_check=fail" diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/gatortest/modulecheck.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/gatortest/modulecheck.py new file mode 100644 index 0000000..23f0ba6 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/gatortest/modulecheck.py @@ -0,0 +1,20 @@ +import sys +from commands import getstatusoutput + +if len(sys.argv) == 1: + adbcmd = 'adb' +else: + adbcmd = 'adb -s %s' % (sys.argv[1]) + +cmd = '%s shell lsmod' % (adbcmd) +rc, output = getstatusoutput(cmd) +if rc != 0: + print 'Failed to run command %s : %s' % (cmd, output) + sys.exit(1) + +# parse output + +if output.find("gator") != -1: + print "gator_module_check=pass" +else: + print "gator_module_check=fail" diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/glmark2.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/glmark2.py new file mode 100644 index 0000000..f111c90 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/glmark2.py @@ -0,0 +1,52 @@ +# Copyright (C) 2010-2012 Linaro Limited + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Executes the glmark2 benchmark. + +**URL:** https://launchpad.net/glmark2 + +**Default Options:** None +""" + +import os +import lava_android_test.testdef +from lava_android_test.config import get_config + +test_name = 'glmark2' +config = get_config() +curdir = os.path.realpath(os.path.dirname(__file__)) +test_sh_name = 'glmark2.sh' +test_sh_path = os.path.join(curdir, test_name, test_sh_name) +RUN_STEPS_HOST_PRE = ['/bin/bash %s $(SERIAL)' % test_sh_path] + +#I/glmark2 ( 1818): [texture] texture-filter=nearest: FPS: 8 FrameTime: 125.000 ms +PATTERN = ("^\s*I/glmark2\s*\(.+\):\s+(?P<test_case_id>\[\w+\]\s+\S+)" + "\s+FPS:\s+(?P<measurement>\d+)") + +inst = lava_android_test.testdef.AndroidTestInstaller() +run = lava_android_test.testdef.AndroidTestRunner( + steps_host_pre=RUN_STEPS_HOST_PRE) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN, + appendall={'units': 'FPS'}) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/glmark2/glmark2.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/glmark2/glmark2.sh new file mode 100755 index 0000000..2a9b410 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/glmark2/glmark2.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# Copyright (C) 2012 Linaro Limited + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +ADB_CMD="adb" +prog_dir=`dirname $0` + +function main(){ + if [ "x${1}" != "x" ]; then + ADB_CMD="${ADB_CMD} -s ${1}" + fi + ${ADB_CMD} logcat -c + ${ADB_CMD} shell am start -W org.linaro.glmark2/.Glmark2Activity + python ${prog_dir}/glmark2_wait.py ${1} + #${ADB_CMD} logcat -d glmark2:I *:S + ${ADB_CMD} logcat -d +} + +main "$@" diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/glmark2/glmark2_wait.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/glmark2/glmark2_wait.py new file mode 100755 index 0000000..5c680ce --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/glmark2/glmark2_wait.py @@ -0,0 +1,51 @@ +#!/usr/bin/python + +# Copyright (C) 2012 Linaro Limited + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +import pexpect +import sys +import time + +if len(sys.argv) == 1: + adb_cmd = "adb" +else: + adb_cmd = "adb -s %s" % (sys.argv[1]) + +logcat_cmd = '%s logcat -v time' % (adb_cmd) +pattern1 = "glmark2 Score:" +#pattern1 = "\[loop\] fragment-steps=5:fragment-uniform=true: +#vertex-steps=5: FPS:" +pattern2 = "Process org.linaro.glmark2.+has died" +pattern3 = ("No suitable EGLConfig for GLES2.0 found." + " Please check that proper GLES2.0 drivers are installed.") + +try: + proc = pexpect.spawn(logcat_cmd, logfile=sys.stdout) + match_id = proc.expect([pattern1, pattern2, pattern3, pexpect.EOF], + timeout=1000) + print "in glmark2_wait.py match_id = %s\n" % match_id + if (match_id == 0) or (match_id == 1) or (match_id == 2): + proc.sendcontrol('C') +except pexpect.TIMEOUT: + print "glmark2 Test: TIMEOUT Fail\n" + sys.exit(1) +finally: + proc.sendcontrol('C') + +time.sleep(3) +sys.exit(0) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/helloworld.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/helloworld.py new file mode 100644 index 0000000..40ad04e --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/helloworld.py @@ -0,0 +1,46 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Example for how to add test wrapper for lava-android-test + +**URL:** None + +**Default options:** None +""" + +import lava_android_test.config +import lava_android_test.testdef + +test_name = 'helloworld' + +INSTALL_STEPS_ADB_PRE = [] +ADB_SHELL_STEPS = ['echo helloworld: PASS'] +PATTERN = "^\s*(?P<test_case_id>[^:]+?):\s+(?P<result>(PASS|FAIL)?)\s*$" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/hostshells/__init__.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/hostshells/__init__.py new file mode 100644 index 0000000..dcb0716 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/hostshells/__init__.py @@ -0,0 +1,31 @@ +# copyright (C) 2012 Linaro Limited +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +This directory contains the tests that only need to run a host command. +Please see the example.sh for a reference. +Please note this is not a test that can be run. + +**URL:** None + +**Default options:** None +""" + +import os +curdir = os.path.dirname(os.path.realpath(__file__)) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/hostshells/connect-lab-wifi.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/hostshells/connect-lab-wifi.sh new file mode 100755 index 0000000..d04233d --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/hostshells/connect-lab-wifi.sh @@ -0,0 +1,170 @@ +#!/bin/bash +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +function generate_wpa_conf(){ + conf=$1 && ssid=$2 passwd=$3 + if [ -z "${conf}" ];then + return + fi + + if [ -z "${ssid}" ]; then + cat >wpa_supplicant.conf <<__EOF__ +ctrl_interface=wlan0 +update_config=1 +device_type=0-00000000-0 + +__EOF__ + + elif [ -z "${passwd}" ]; then + cat >wpa_supplicant.conf <<__EOF__ +ctrl_interface=wlan0 +update_config=1 +device_type=0-00000000-0 + +network={ + ssid="${ssid}" + key_mgmt=NONE + priority=2 +} + +__EOF__ + + else + cat >wpa_supplicant.conf <<__EOF__ +ctrl_interface=wlan0 +update_config=1 +device_type=0-00000000-0 + +network={ + ssid="${ssid}" + psk="${passwd}" + key_mgmt=WPA-PSK + priority=2 +} + +__EOF__ + + fi +} + +function enable_wifi(){ + conf=$1 && ssid=$2 && serial=$3 + if [ -z "${conf}" ]; then + return + fi + ADB_OPTION="" + if [ -n "${serial}" ]; then + ADB_OPTION="-s ${serial}" + fi + + adb ${ADB_OPTION} shell am start -a android.intent.action.MAIN -n com.android.settings/.Settings + sleep 3 + adb ${ADB_OPTION} shell service call wifi 13 i32 0 + sleep 5 + adb ${ADB_OPTION} push "${conf}" /data/misc/wifi/wpa_supplicant.conf + adb ${ADB_OPTION} shell chown wifi.wifi /data/misc/wifi/wpa_supplicant.conf + adb ${ADB_OPTION} shell chmod 660 /data/misc/wifi/wpa_supplicant.conf + adb ${ADB_OPTION} shell ls -l /data/misc/wifi/wpa_supplicant.conf + adb ${ADB_OPTION} shell service call wifi 13 i32 1 + #extend the wait time because the time to turn wifi on some devices(like + #Origen) will take a little longer + sleep 60 + for i in {1..30}; do + adb ${ADB_OPTION} shell wpa_cli list_networks|grep -E "^\s*[[:digit:]]+\s+${ssid}\s+any\s+\[CURRENT\]" + if [ $? -eq 0 ];then + break + fi + sleep 5 + done + + if [ $i -eq 30 ]; then + echo "connect-lava-wifi-${ssid}=fail" + return 1 + else + echo "connect-lava-wifi-${ssid}=pass" + return 0 + fi +} + +function parse_argv() { + # Parse command line arguments + # Sets: VERBOSE, dev + while test -n "$1"; do + case "$1" in + --serial|-s) + SERIAL="$2" + shift 2 + ;; + --passwd|-p) + PASSWD="$2" + shift 2 + ;; + *) + if [ -n "${SSID}" ]; then + show_usage + exit 1 + else + SSID="$1" + shift + fi + ;; + esac + done +} + +function show_usage(){ + # Display the usage line + echo "Usage 1, Specify the ssid and pawword via command line:" + echo " $0 [--passwd|-p passwd] [--serial|-s serial] ssid" + echo "Usage 2, Specify the ssid and pawword via configuration file:" + echo " Specify the file path via 'WIFI_DEV_CONF' environment variable," + echo " /etc/lava/devices/wifi.conf is the default value if not specified" + echo " The content of this file like this:" + echo " SSID=the ssid of wifi" + echo " PASSWD=the password of the specified wifi via SSID" +} + +function main(){ + if [ -z "${WIFI_DEV_CONF}" ]; then + wifi_dev_conf="/etc/lava/devices/wifi.conf" + else + wifi_dev_conf="${WIFI_DEV_CONF}" + fi + + echo "Will use ${wifi_dev_conf} as the configuration file for wifi if exists" + if [ -f "${wifi_dev_conf}" ]; then + . "${wifi_dev_conf}" + fi + parse_argv "$@" + + if [ -z "${SSID}" ]; then + show_usage + exit 1 + fi + + wifi_conf="wpa_supplicant.conf" + generate_wpa_conf "${wifi_conf}" "${SSID}" "${PASSWD}" + enable_wifi "${wifi_conf}" "${SSID}" "${SERIAL}" + RET=$? + rm -f "${wifi_conf}" + exit $RET +} + +main "$@" diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/hostshells/example.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/hostshells/example.sh new file mode 100755 index 0000000..50c81b7 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/hostshells/example.sh @@ -0,0 +1,62 @@ +#!/bin/bash +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +function parse_argv() { + # Parse command line arguments + while test -n "$1"; do + case "$1" in + --serial|-s) + SERIAL="$2" + if [ -n "${SERIAL}" ]; then + shift 2 + else + show_usage + exit 1 + fi + ;; + --help|-h) + show_usage + exit 1 + ;; + *) + if [ -n "${OPTIONS}" ]; then + OPTIONS="${OPTIONS} $1" + else + OPTIONS="$1" + fi + shift + ;; + esac + done +} + +function show_usage(){ + # Display the usage line + echo "Usage $(basename $0) [--serial <serial>|-s <serial>] <other-option>" + echo "Usage $(basename $0) [--help|-h]" +} + +function main(){ + parse_argv "$@" + echo "hostshells-example-fail=fail" + echo "hostshells-example-pass=pass" +} + +main "$@" diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/hostshells/install-overlay.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/hostshells/install-overlay.sh new file mode 100755 index 0000000..996bcbb --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/hostshells/install-overlay.sh @@ -0,0 +1,79 @@ +#!/bin/bash +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +function parse_argv() { + # Parse command line arguments + while test -n "$1"; do + case "$1" in + --serial|-s) + SERIAL="$2" + if [ -n "${SERIAL}" ]; then + shift 2 + else + show_usage + exit 1 + fi + ;; + --url|-u) + URL="$2" + if [ -n "${URL}" ]; then + shift 2 + else + show_usage + exit 1 + fi + ;; + --help|-h) + show_usage + exit 1 + ;; + *) + if [ -n "${OPTIONS}" ]; then + OPTIONS="${OPTIONS} $1" + else + OPTIONS="$1" + fi + shift + ;; + esac + done +} + +function show_usage(){ + # Display the usage line + echo "Usage $(basename $0) [--serial <serial>|-s <serial>] <other-option>" + echo "Usage $(basename $0) [--help|-h]" +} + +function main(){ + parse_argv "$@" + # Fetch the overlay and extract it. + wget $URL overlay.tar.bz2 + tar -xvf overlay.tar.bz2 + + # Push the overlay + adb -s ${SERIAL} remount + adb -s ${SERIAL} push overlay/ / + adb -s ${SERIAL} shell sync + adb -s ${SERIAL} shell stop + adb -s ${SERIAL} shell start +} + +main "$@" diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/hostshells/sdcard-mounted.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/hostshells/sdcard-mounted.sh new file mode 100755 index 0000000..4257850 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/hostshells/sdcard-mounted.sh @@ -0,0 +1,65 @@ +#!/bin/bash +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +function parse_argv() { + # Parse command line arguments + while test -n "$1"; do + case "$1" in + --serial|-s) + SERIAL="$2" + if [ -n "${SERIAL}" ]; then + shift 2 + else + show_usage + exit 1 + fi + ;; + --help|-h) + show_usage + exit 1 + ;; + *) + shift + ;; + esac + done +} + +function show_usage(){ + # Display the usage line + echo "Usage $(basename $0) [--serial <serial>|-s <serial>]" + echo "Usage $(basename $0) [--help|-h]" +} + +function main(){ + parse_argv "$@" + ADB_OPTION='' + if [ -n "${SERIAL}" ]; then + ADB_OPTION="-s ${SERIAL}" + fi + adb ${ADB_OPTION} shell mount |grep -e '/sdcard' -e 'emulated' + if [ $? -eq 0 ]; then + echo "sdcard-mounted=pass" + else + echo "sdcard-mounted=fail" + fi +} + +main "$@" diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/hostshells/workload.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/hostshells/workload.sh new file mode 100755 index 0000000..a01a4a1 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/hostshells/workload.sh @@ -0,0 +1,146 @@ +#!/bin/bash +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +function parse_argv() { + # Parse command line arguments + while test -n "$1"; do + case "$1" in + --serial|-s) + SERIAL="$2" + if [ -n "${SERIAL}" ]; then + shift 2 + else + show_usage + exit 1 + fi + ;; + --config|-c) + CONFIG="$2" + if [ -n "${CONFIG}" ]; then + shift 2 + else + show_usage + exit 1 + fi + ;; + --git|-g) + GIT_URL="$2" + if [ -n "${GIT_URL}" ]; then + shift 2 + else + show_usage + exit 1 + fi + ;; + --help|-h) + show_usage + exit 1 + ;; + *) + if [ -n "${OPTIONS}" ]; then + OPTIONS="${OPTIONS} $1" + else + OPTIONS="$1" + fi + shift + ;; + esac + done +} + +function show_usage(){ + # Display the usage line + echo "Usage $(basename $0) [--serial|-s <serial>] [--config|-c <config_file>] [--git|g <git-url>] <other-option>" + echo "Usage $(basename $0) [--help|-h]" +} + +function parse_output_result(){ + result_f=${1} + if [ ! -f "${1}" ]; then + echo "There is no result file output/results.csv" + return + fi + + file_tmp=${result_f}.tmp + sed 's/ /_/g' ${result_f} > ${file_tmp} + keys=`head -n 1 ${file_tmp}` + values=`tail -n 1 ${file_tmp}` + for ((i=1; i<21; i++)); do + key=`echo ${keys}|cut -d , -f ${i}|sed 's/\r//'` + value=`echo ${values}|cut -d , -f ${i}|sed 's/\r//'` + + echo ${value}|grep -P '^[.\d]+$' &>/dev/null + if [ $? -ne 0 ]; then + key="${key}_${value}" + value="true" + fi + echo ${key}=${value} + done + rm -f ${file_tmp} +} + +function main(){ + local_git="file:///home/bhoj/workload-automation.git" + branch="lava" + outputdir="outputdir" + result="${outputdir}/result.csv" + + parse_argv "$@" + + config_file="config.csv" + if [ -n "${CONFIG}" ]; then + config_file="${CONFIG}" + fi + + if [ -n "${GIT_URL}" ]; then + git_url="${GIT_URL}" + else + git_url="${local_git}" + fi + + git clone "${git_url}" -b ${branch} + if [ $? -ne 0 ]; then + echo "Failed to clone git repository: ${git_url}" + exit 1 + fi + ip=`echo ${SERIAL}|sed 's/:5555//'` + cd "workload-automation" + + #update the ip address and patch config.csv file + sed -i "s/192.168.1.38/${ip}/g" workload_config.py + + python workload_setup_dependencies.py + if [ $? -ne 0 ]; then + echo "Failed to run workload_setup_dependencies.py" + exit 1 + fi + + rm -fr ${outputdir} + python workload.py ${config_file} ${outputdir}/ + if [ $? -ne 0 ]; then + echo "Failed to run workload.py config.csv outputdir/" + exit 1 + fi + cat ${result} + parse_output_result ${result} +} + +main "$@" + diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/ime.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/ime.py new file mode 100644 index 0000000..aacaef6 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/ime.py @@ -0,0 +1,57 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Performs testing of Android Input Method Manager by listing the available +input methods on the system. + +**URL:** http://android.git.linaro.org/gitweb?p=platform/frameworks/base.git;a=blob;f=cmds/ime/src/com/android/commands/ime/Ime.java + +**Default options:** None +""" + +import os +import lava_android_test.testdef +from lava_android_test.config import get_config + +test_name = 'ime' +config = get_config() +curdir = os.path.realpath(os.path.dirname(__file__)) +test_sh_name = 'ime_test.sh' +test_sh_path = os.path.join(curdir, test_name, test_sh_name) +test_sh_android_path = os.path.join(config.installdir_android, + test_name, test_sh_name) + +INSTALL_STEPS_ADB_PRE = ['push %s %s ' % (test_sh_path, + test_sh_android_path), + 'shell chmod 777 %s' % test_sh_android_path] + +ADB_SHELL_STEPS = [test_sh_android_path] +PATTERN = "^\s*(?P<test_case_id>ime)=(?P<result>\w+)\s*$" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/ime/ime_test.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/ime/ime_test.sh new file mode 100755 index 0000000..6a6d7a1 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/ime/ime_test.sh @@ -0,0 +1,13 @@ +#!/system/bin/sh + +test_func(){ + if [ ! -f /system/bin/ime ]; then + echo "ime=fail" + exit + fi + + /system/bin/ime list -a + echo "ime=pass" +} + +test_func diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/install_prep_4bench.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/install_prep_4bench.py new file mode 100644 index 0000000..2687adc --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/install_prep_4bench.py @@ -0,0 +1,46 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Remove the Linaro wallpaper before start the benchmark test + +**URL:** None + +**Default options:** None +""" +import lava_android_test.config +import lava_android_test.testdef + +test_name = 'install_prep_4bench' + +INSTALL_STEPS_ADB_PRE = [] +ADB_SHELL_STEPS = ['rm /data/system/wallpaper_info.xml', + "echo install_prep_4bench.wallpaper: PASS"] +PATTERN = "^\s*(?P<test_case_id>[^:]+?):\s+(?P<result>(PASS|FAIL)?)\s*$" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/instruments/__init__.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/instruments/__init__.py new file mode 100644 index 0000000..43e06ba --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/instruments/__init__.py @@ -0,0 +1,28 @@ +# copyright (C) 2012 Linaro Limited +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +This directory contains the tests that only need to run the "am instrument -w" +command on android. Please see the example.py for a reference. +Please note this is not a test that can be run. + +**URL:** None + +**Default options:** None +""" diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/instruments/example.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/instruments/example.py new file mode 100644 index 0000000..b5c73d0 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/instruments/example.py @@ -0,0 +1,32 @@ +# copyright (C) 2012 Linaro Limited +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Example for how to add instrument tests into lava-android-test. +You can try this test with the android emulator which has this test integrated. + +**URL:** http://android.git.linaro.org/gitweb?p=platform/development.git;a=blob;f=tools/emulator/test-apps/ConnectivityTest/src/com/android/emulator/connectivity/test/ConnectivityTest.java + +**Default options:** None +""" + +cmd = ("am instrument -r -w " + "com.android.emulator.connectivity.test/" + "android.test.InstrumentationTestRunner") +RUN_ADB_SHELL_STEPS = [cmd] diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/iozone.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/iozone.py new file mode 100644 index 0000000..ab9a0b2 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/iozone.py @@ -0,0 +1,118 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Perform the iozone test on the target device + +**URL:** http://android.git.linaro.org/gitweb?p=platform/external/iozone.git;a=summary + +**Default options:** None +""" +from lava_android_test.config import get_config +import lava_android_test.testdef +import os +import re + + +class IozoneParser(lava_android_test.testdef.AndroidTestParser): + '''Custom parser for Iozone. -b with a results file must be specified. + The results file is not parsed. However the addition of this parameter + causes an organized results report to be printed at the bottom + ''' + #used to find each report + PATTERN_REPORT = '(?P<report_name>.*?)report' + #used to determined output units + PATTERN_UNITS = 'Output is in (?P<units>\S*)' + + def real_parse(self, result_filename='stdout.log', + output_filename='stdout.log', + test_name=''): + '''Parse the results of stdout. + This requires the -b option be specified to IOZONE. + ''' + #filename = artifacts.stdout_pathname + pat_report = re.compile(self.PATTERN_REPORT) + pat_units = re.compile(self.PATTERN_UNITS) + units = '' + with open(output_filename, 'r') as fd: + lines = fd.readlines() + for i in range(0, len(lines)): + line = lines[i] + match_report = pat_report.search(line) + match_units = pat_units.search(line) + #found report. + if match_report: + ''' The results are the following format + <report name> report + reclen 1 + block_size results 1 + ''' + report_name = match_report.groupdict()['report_name' + ].replace("\"", "") + i += 1 + rclen_line = lines[i].replace("\"", "") + i += 1 + results_line = lines[i].replace("\"", "") + reclen_split = rclen_line.split() + results_split = results_line.split() + #first value is the block size + size = results_split[0] + for n in range(0, len(reclen_split)): + results = {'test_case_id': + "iozone_%sKB_%s_rclen_%s" % (report_name, + str(size), + str(reclen_split[n])), + 'result': 'pass', + 'measurement': int(results_split[n + 1]), + 'units': units} + self.results['test_results'].append(results) + elif match_units: + units = match_units.groupdict()['units'] + + +test_name = 'iozone' + +config = get_config() +curdir = os.path.realpath(os.path.dirname(__file__)) +iozone_sh_name = 'iozone.sh' +iozone_dir_path = os.path.join(curdir, 'iozone') +#copy the whole directory over +#this will alow users to place the crosscompiled izone binary +#in the folder and modify iozone.sh to remount the root fs. +iozone_dir_android_path = os.path.join(config.installdir_android, + test_name) +iozone_sh_android_path = os.path.join(iozone_dir_android_path, + iozone_sh_name) + +INSTALL_STEPS_ADB_PRE = ['push %s %s ' % (iozone_dir_path, + iozone_dir_android_path), + 'shell chmod -R 777 %s' % iozone_dir_android_path] + +ADB_SHELL_STEPS = ["%s %s" % (iozone_sh_android_path, iozone_dir_android_path)] + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = IozoneParser() +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/memtester.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/memtester.py new file mode 100644 index 0000000..2ddad92 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/memtester.py @@ -0,0 +1,45 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Perform the memtester test on the target device. +memtester is a utility for testing the memory subsystem in a computer to determine if it is faulty. + +**URL:** http://android.git.linaro.org/gitweb?p=platform/external/memtester.git;a=summary + +**Default options:** None +""" +import lava_android_test.testdef + +test_name = 'memtester' + +INSTALL_STEPS_ADB_PRE = [] +ADB_SHELL_STEPS = ['memtester 1M 1'] +PATTERN = "^\s*(?P<test_case_id>.*?)\s*:\s*(?P<result>\w+)\s*$" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/methanol.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/methanol.py new file mode 100644 index 0000000..5785317 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/methanol.py @@ -0,0 +1,65 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +The Methanol is a page load benchmarking engine. +The benchmark engine measures the overall page layouting and rendering time of the browser. +The methanol now includs test for css/canvas/smp/svg test + +**URL:** https://github.com/szeged/methanol.git + +**Default options:** None +""" + +import os +import json + +import lava_android_test.testdef + +from lava_android_test.config import get_config + +curdir = os.path.realpath(os.path.dirname(__file__)) +config = get_config() + +result_dir = config.resultsdir_android +RUN_STEPS_HOST_PRE = ["bash %s/methanol/methanol.sh $(SERIAL) $(OPTIONS)" % curdir] + +class MethanolTestParser(lava_android_test.testdef.AndroidTestParser): + + def real_parse(self, result_filename=None, output_filename='methanol_result.json', + test_name=''): + """Parse test output to gather results + Use the pattern specified when the class was instantiated to look + through the results line-by-line and find lines that match it. + Results are then stored in self.results. If a fixupdict was supplied + it is used to convert test result strings to a standard format. + """ + with open(output_filename) as stream: + test_results_data = stream.read() + test_results_json = json.loads(test_results_data) + self.results['test_results'] = test_results_json + + +inst = lava_android_test.testdef.AndroidTestInstaller() +run = lava_android_test.testdef.AndroidTestRunner(steps_host_pre=RUN_STEPS_HOST_PRE) +parser = MethanolTestParser() +testobj = lava_android_test.testdef.AndroidTest(testname="methanol", + installer=inst, runner=run, parser=parser, + org_ouput_file='/data/local/tmp/methanol/methanol_result.json') diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/methanol/methanol.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/methanol/methanol.sh new file mode 100755 index 0000000..81e2598 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/methanol/methanol.sh @@ -0,0 +1,327 @@ +#!/bin/bash +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +#the default ip or domain used by the client to access the server +DEFAULT_DOMAIN_IP=`ifconfig | awk -F':' '/inet addr/&&!/127.0.0.1/{split($2,_," ");print _[1]}'` +DEFAULT_BROWSER='DEFAULT' + +######################################################## +###### NOT MODIFY SOURCE OF BELOW ##### +######################################################## +THIS_FILE="$0" +methanol_git="git://github.com/szeged/methanol.git" +chrome_apk_url="http://testdata.validation.linaro.org/chrome/Chrome-latest.apk" +server_settings_file="/etc/lava/web_server/settings.conf" +result_dir_android="/data/local/tmp/methanol" +declare -a RESULTS=(); +methanol_url="/" +report_url="/cgi/save_methanol_data.py" +report_res_dir="/tmp/methanol" +target_dir="" +server_pid="" + +ADB_OPTION="" +domain_ip="${DEFAULT_DOMAIN_IP}" +browser="${DEFAULT_BROWSER}" +test_target="" + +function parse_arg(){ + serial="" + while test -n "$1"; do + case "$1" in + --browser|-b) + if [ "x$2" = "x" ]; then + echo "Error: $1 requires an argument which should be DEFAULT or CHROME" + exit 1 + fi + browser="$2" + if [ "X${browser}" != "XDEFAULT" ] && [ "X${browser}" != "XCHROME" ]; then + echo "Error: $1 requires an argument which should be DEFAULT or CHROME" + exit 1 + fi + shift 2 + ;; + --domain|-d) + if [ "x$2" = "x" ]; then + echo "Error: $1 requires an argument" + exit 1 + fi + domain_ip="$2" + shift 2 + ;; + --target|-t) + if [ "x$2" = "x" ]; then + echo "Error: $1 requires an argument" + exit 1 + fi + test_target="$2" + shift 2 + ;; + --help|-h) + show_usage + exit 0 + ;; + *) + if [ -n "${serial}" ]; then + show_usage + echo "Too many arguments, see --help for details" + exit 1 + else + serial="$1" + shift + fi + ;; + esac + done + + if [ -n "${serial}" ]; then + ADB_OPTION="-s ${serial}" + fi +} + +function show_usage(){ + echo "`basename ${THIS_FILE}` [serial_no] [-b DEFAULT|CHROME] [-d domain_ip]" +} + +function patch_sources(){ + src_root_dir=${1} + if [ -z ${src_root_dir} ]; then + return + fi + + if [ \! -d ${src_root_dir} ]; then + return + fi + + ## The following test case cannot be on android browser, so comment them out + ## Patch the engine.js + sed -i "s% + results;% + results.replace\(new RegExp('/','gm'), '_'\);%" ${src_root_dir}/engine.js + + ##Patch svg.js + sed -i s%\"svg/anim/earth.svg\",%\"svg/anim/earth.svg\"/*,% ${src_root_dir}/svg.js + sed -i s%\"svg/anim/svg.svg\"%\"svg/anim/svg.svg\"*/% ${src_root_dir}/svg.js + + ##Patch smp.js + sed -i s%\"smp/3d-terrain-demo/single/index.html\",%//\"smp/3d-terrain-demo/single/index.html\",% ${src_root_dir}/smp.js + sed -i s%\"smp/3d-terrain-demo/worker/index.html\",%//\"smp/3d-terrain-demo/worker/index.html\",% ${src_root_dir}/smp.js + sed -i s%\"smp/fire-on-water/worker/index.html\",%//\"smp/fire-on-water/worker/index.html\",% ${src_root_dir}/smp.js +} + +function deploy(){ + + if [ "${browser}" = "CHROME" ]; then + echo "wget --progress=dot -e dotbytes=1M -np -l 10 --no-check-certificate ${chrome_apk_url} -O ./Chrome-latest.apk" + wget --progress=dot -e dotbytes=1M -np -l 10 --no-check-certificate ${chrome_apk_url} -O ./Chrome-latest.apk + if [ $? -ne 0 ]; then + echo "Failed to download the chrome apk file from ${chrome_apk_url}." + cleanup + exit 1 + fi + + adb ${ADB_OPTION} uninstall com.android.chrome + + echo "adb ${ADB_OPTION} install ./Chrome-latest.apk" + adb ${ADB_OPTION} install ./Chrome-latest.apk + if [ $? -ne 0 ]; then + echo "Failed to install the Chrome browser application." + cleanup + rm -f ./Chrome-latest.apk + exit 1 + fi + rm -f ./Chrome-latest.apk + adb ${ADB_OPTION} shell am start com.android.chrome/com.google.android.apps.chrome.Main + sleep 10 + f_preferences='/data/data/com.android.chrome/shared_prefs/com.android.chrome_preferences.xml' + f_preferences_base=`basename ${f_preferences}` + owner_grp=`adb ${ADB_OPTION} shell ls -l ${f_preferences}|cut -d \ -f2` + if [ -z "${owner_grp}" ]; then + echo "Failed to get the user/group infromation of chrome preferences file." + cleanup + rm -f ./Chrome-latest.apk + exit 1 + fi + adb ${ADB_OPTION} pull ${f_preferences} ./${f_preferences_base} + sed -i '/<map>/ a\<boolean name="first_run_flow" value="true" />' ./${f_preferences_base} + adb ${ADB_OPTION} push ./${f_preferences_base} ${f_preferences} + adb ${ADB_OPTION} shell chown ${owner_grp}:${owner_grp} ${f_preferences} + chrome_pid=`adb ${ADB_OPTION} shell ps |grep -P 'chrome\s*$'|tr -s ' '|cut -d \ -f2` + if [ -n "${chrome_pid}" ]; then + adb ${ADB_OPTION} shell kill ${chrome_pid} + fi + rm -f ./${f_preferences_base} + fi + + cur_path=`pwd` + target_dir=`mktemp -u --tmpdir=${cur_path} methanol-XXX` + git clone "${methanol_git}" "${target_dir}" + if [ $? -ne 0 ];then + echo "Failed to clone the methanol source from ${methanol_git}" + cleanup + exit 1 + fi + + #patch just because some test can not be run on android + patch_sources "${target_dir}" + + url_file=`mktemp -u --tmpdir=${cur_path} url-XXX` + nohup python `dirname $0`/start_server.py "${domain_ip}" "${target_dir}" "${url_file}" &>server.log & + server_pid=$! + sleep 5 + domain_protocol=`cat ${url_file}` + if [ -z "${domain_protocol}" ]; then + echo "Cannot get the url of the temporary created server." + echo "Failed to deploy the temporary server" + cleanup + exit 1 + fi +} + +function check_url(){ + if [ -n "${report_url}" ]; then + wget -q "${domain_protocol}/${report_url}" -O /dev/null + if [ $? -ne 0 ]; then + echo "The report url(${domain_protocol}/${report_url}) cannot be accessed" + echo "Please put the save_methanol_data.py to the cgi-bin directory" + echo "of your web server, and make sure it is accessible." + cleanup + exit 1 + fi + fi + + if [ -n "${methanol_url}" ]; then + wget -q "${domain_protocol}/${methanol_url}" -O /dev/null + if [ $? -ne 0 ]; then + echo "The url(${domain_protocol}/${methanol_url}) cannot be accessed" + echo "Please clone the methanol directory to local via following command" + echo " git clone ${methanol_git}" + echo "and copy the entire directory to some place of your web server" + echo "and make sure it is accessible." + cleanup + exit 1 + fi + else + echo "Please speecify the methanol url that will be used for test." + cleanup + exit 1 + fi +} + +function wait_result(){ + if [ -n "$1" ]; then + file_path="$1" + else + return 0 + fi + + for (( i=1; ; i++ )); do + sleep 300 + if [ -f "${file_path}" ]; then + return 0 + fi + done + return 1 +} + +function test_methanol(){ + if [ -n "$1" ]; then + test_type="-${1}" + else + test_type="" + fi + + result_file=`mktemp -u --tmpdir=${report_res_dir} fire${test_type}-XXX.json` + res_basename=`basename ${result_file}` + test_url="${domain_protocol}/${methanol_url}/fire${test_type}.html" + if [ -n "${report_url}" ]; then + test_url="${test_url}?reportToUrl=${report_url}%3Fsave2file=${res_basename}" + fi + + component_default="com.android.browser/com.android.browser.BrowserActivity" + component_chrome=" com.android.chrome/com.google.android.apps.chrome.Main" + if [ "${browser}" = "CHROME" ]; then + component=${component_chrome} + else + component=${component_default} + fi + echo "adb ${ADB_OPTION} shell am start -a android.intent.action.VIEW -d ${test_url} -n ${component}" + adb ${ADB_OPTION} shell "am start -a android.intent.action.VIEW -d ${test_url} -n ${component}" + wait_result "${result_file}" + if [ $? -eq 0 ]; then + cur_path=`pwd` + cp -uvf ${result_file} ${cur_path}/${res_basename} + echo "result_file=${cur_path}/${res_basename}" + RESULTS[${#RESULTS[@]}]="${cur_path}/${res_basename}" + + rm -f ${result_file} + else + echo "Failed to get the test result of fire${test_type}.html" + #cleanup + #exit 1 + fi +} + +function cleanup(){ + echo "DO CLEAN UP" + rm -fr methanol_result.json "${RESULTS[@]}" + if [ -n "${server_pid}" ]; then + kill -9 ${server_pid} + fi + if [ -n "${target_dir}" ]; then + rm -fr "${target_dir}" + fi + if [ "${browser}" = "CHROME" ]; then + adb ${ADB_OPTION} uninstall com.android.chrome + fi +} + +function main(){ + parse_arg "$@" + + ## delete the test result for last time + adb ${ADB_OPTION} shell rm "${result_dir_android}/methanol_result.json" + + trap cleanup EXIT + + deploy + + check_url + + page_suffix='${test_target}' + if [ -n "${page_suffix}" ]; then + page_suffix="-${test_target}" + fi + echo `date`: starts to test fire${page_suffix}.html + test_methanol "${test_target}" + echo `date`: all tests completed + + echo "Merge results of file: ${RESULTS[@]}" + `dirname $0`/methanol_merge_results.py methanol_result.json "${RESULTS[@]}" + if [ $? -eq 0 ]; then + adb ${ADB_OPTION} shell mkdir ${result_dir_android} + adb ${ADB_OPTION} push methanol_result.json "${result_dir_android}/methanol_result.json" + for f in "${RESULTS[@]}"; do + adb ${ADB_OPTION} push "${f}" "${result_dir_android}" + done + echo "The result is also push to android: ${result_dir_android}/${res_basename}" + else + echo "Failed to merge the results" + fi +} +main "$@" diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/methanol/methanol_merge_results.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/methanol/methanol_merge_results.py new file mode 100755 index 0000000..a57c602 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/methanol/methanol_merge_results.py @@ -0,0 +1,86 @@ +#!/usr/bin/python +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import re +import string +import sys + +import simplejson as json + +if len(sys.argv) < 3: + basename = os.path.basename(sys.argv[0]) + print 'Please specified the merge target file and source files like:' + print '\t %s target-result-file source-file1 source-file2 ...' + sys.exit(1) + +target_file = sys.argv[1] +test_results = [] +for f in sys.argv[2:]: + if not os.path.exists(f): + print "The file(%s) does not exist" % f + continue + + with open(f) as stream: + f_basename = os.path.basename(f) + last_hyphen_index = string.rfind(f_basename, '-') + if last_hyphen_index != -1: + file_id = f_basename[:last_hyphen_index] + else: + file_id = '' + + jobdata = stream.read() + results_data = json.loads(jobdata) + for res in results_data: + test_case_id = res.get('test_case_id') + average = res.get('average') + avg_dev = res.get('average_deviate') + units = res.get('units') + if file_id and test_case_id == 'summary': + test_case_id = '%s-summary' % file_id + test_case_id = test_case_id.replace('/', '_') + badchars = "[^a-zA-Z0-9\._-]" + test_case_id = re.sub(badchars, "", test_case_id.replace(" ", "_")) + if not units: + units = 'ms' + test_results.append({'test_case_id': '%s_avg' % test_case_id, + 'result': 'pass', + 'measurement': average, + 'units': units}) + if avg_dev: + test_results.append({ + 'test_case_id': '%s_avg_dev' % test_case_id, + 'result': 'pass', + 'measurement': avg_dev, + 'units': '%'}) + + +with open(target_file, 'w') as fd: + indent = ' ' * 2 + separators = (', ', ': ') + json.dump(test_results, fd, + use_decimal=True, + indent=indent, + separators=separators, + sort_keys=False) + +print "The result has been merged in file: %s" % target_file +sys.exit(0) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/methanol/start_server.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/methanol/start_server.py new file mode 100755 index 0000000..6ca96b5 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/methanol/start_server.py @@ -0,0 +1,62 @@ +#/usr/bin/python +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import sys +import CGIHTTPServer +import BaseHTTPServer + +### check parameter +if len(sys.argv) < 3: + print 'Please spsecify the ip and directory like this:' + print ' %s domain-or-ip directory-path url-file' % ( + os.path.basename(__file__)) + sys.exit(1) + +domain = sys.argv[1] +directory = sys.argv[2] +if len(sys.argv) == 4: + url_file = sys.argv[3] +else: + url_file = '' + +## change to that directory +old_dir = os.getcwd() +os.chdir(directory) + +## set the server configuration before start +cgi_handler = CGIHTTPServer.CGIHTTPRequestHandler +cgi_handler.cgi_directories.append('/cgi') +httpd = BaseHTTPServer.HTTPServer((domain, 0), cgi_handler) +url = '%s://%s:%s/' % ('http', httpd.socket.getsockname()[0], + httpd.socket.getsockname()[1]) + +## out put the url information to console and file for other script reference +print "serving at url=", url +if url_file: + with open(url_file, 'w') as stream: + stream.write(url) + print 'The information of url also have been wirtten into file(%s)' % ( + url_file) + +try: + httpd.serve_forever() +finally: + os.chdir(old_dir) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/mmtest.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/mmtest.py new file mode 100644 index 0000000..985a650 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/mmtest.py @@ -0,0 +1,63 @@ +# Copyright (C) 2011-2012 Linaro Limited +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Performs a test of multimedia functionality in Android by playing a variety +of different multimedia formats on Android. + +**URL:** http://android.git.linaro.org/gitweb?p=platform/frameworks/base.git;a=tree;f=media/tests/MediaFrameworkTest + +**Default options:** None +""" + +import os +import lava_android_test.testdef +from lava_android_test.utils import get_local_name +from lava_android_test.config import get_config + +test_name = 'mmtest' +config = get_config() + +site = 'http://samplemedia.linaro.org/' +local_name = get_local_name(site) +RUN_STEPS_HOST_PRE = [ + 'wget --progress=dot -e dotbytes=1M -r -np -l 10 -R csv,txt,css,html,gif,pdf %s -P %s' % (site, + local_name), + r'find %s -type f -name "index*" -exec rm -f \{\} \;' % local_name, + r'find %s -type f -name "README" -exec rm -f \{\} \;' % local_name] + +test_files_target_path = os.path.join(config.installdir_android, + test_name, local_name) +RUN_STEPS_ADB_PRE = ['push %s %s' % (local_name, test_files_target_path)] +RUN_ADB_SHELL_STEPS = ['am instrument -r -e targetDir %s \ + -w com.android.mediaframeworktest/.MediaFrameworkTestRunner' + % test_files_target_path, + 'rm -r %s' % (test_files_target_path)] + +inst = lava_android_test.testdef.AndroidTestInstaller() +run = lava_android_test.testdef.AndroidTestRunner( + steps_host_pre=RUN_STEPS_HOST_PRE, + steps_adb_pre=RUN_STEPS_ADB_PRE, + adbshell_steps=RUN_ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidInstrumentTestParser() +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/monkey.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/monkey.py new file mode 100644 index 0000000..944d8ae --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/monkey.py @@ -0,0 +1,57 @@ +# Copyright (c) 2011 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +Performs a test of monkey functionality in Android with the monkey command + +**URL:** http://android.git.linaro.org/gitweb?p=platform/development.git;a=blob;f=cmds/monkey/monkey + +**Default options:** None +""" +import os +import lava_android_test.testdef +from lava_android_test.config import get_config + +test_name = 'monkey' +config = get_config() +curdir = os.path.realpath(os.path.dirname(__file__)) +monkey_sh_name = 'monkey.sh' +monkey_sh_path = os.path.join(curdir, 'monkey', monkey_sh_name) +monkey_sh_android_path = os.path.join(config.installdir_android, + test_name, monkey_sh_name) + +INSTALL_STEPS_ADB_PRE = ['push %s %s ' % (monkey_sh_path, + monkey_sh_android_path), + 'shell chmod 777 %s' % monkey_sh_android_path] + +ADB_SHELL_STEPS = [monkey_sh_android_path] +#PATTERN = "^(?P<test_case_id>\w+):\W+(?P<measurement>\d+\.\d+)" +PATTERN = "## Network stats: elapsed time=(?P<measurement>\d+)ms" +FAILURE_PATTERNS = [] +#FAILURE_PATTERNS = ['\*\* Monkey aborted due to error.', +# '\*\* System appears to have crashed'] + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN, + appendall={'units': 'ms'}, failure_patterns=FAILURE_PATTERNS) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, runner=run, parser=parser) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/monkey/monkey.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/monkey/monkey.sh new file mode 100755 index 0000000..c774680 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/monkey/monkey.sh @@ -0,0 +1,6 @@ +#!/system/bin/sh +#monkey_cmd="monkey -s 1 --pct-touch 10 --pct-motion 20 --pct-nav 20 --pct-majornav 30 --pct-appswitch 20 --throttle 500 2147483647" +monkey_cmd="monkey -s 1 --pct-touch 10 --pct-motion 20 --pct-nav 20 --pct-majornav 30 --pct-appswitch 20 --throttle 500 500" +echo execute command=${monkey_cmd} +${monkey_cmd} +echo MONKEY_RET_CODE=$? diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/monkey_long_run.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/monkey_long_run.py new file mode 100644 index 0000000..d3d448d --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/monkey_long_run.py @@ -0,0 +1,78 @@ +# Copyright (c) 2011 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +Performs a test of monkey functionality in Android with some +black list packages provided. + +**URL:** http://android.git.linaro.org/gitweb?p=platform/development.git;a=blob;f=cmds/monkey/monkey + +**Default options:** "generic_target" +""" +import os +import lava_android_test.testdef +from lava_android_test.config import get_config + +test_name = 'monkey_long_run' +config = get_config() +curdir = os.path.realpath(os.path.dirname(__file__)) +monkey_sh_name = 'monkey_long_run.sh' +monkey_sh_path = os.path.join(curdir, test_name, monkey_sh_name) +monkey_sh_android_path = os.path.join(config.installdir_android, + test_name, monkey_sh_name) +monkey_blacklist_name = 'package_black_list' +monkey_blacklist_path = os.path.join(curdir, test_name, monkey_blacklist_name) +monkey_blacklist_android_path = os.path.join(config.installdir_android, + test_name, monkey_blacklist_name) +juice_monkey_blacklist_name = 'juice_package_black_list' +juice_monkey_blacklist_path = os.path.join(curdir, test_name, + juice_monkey_blacklist_name) +juice_monkey_blacklist_android_path = os.path.join(config.installdir_android, + test_name, + juice_monkey_blacklist_name) + +DEFAULT_OPTIONS = 'generic_target' +INSTALL_STEPS_ADB_PRE = ['push %s %s ' % (monkey_sh_path, + monkey_sh_android_path), + 'push %s %s ' % (monkey_blacklist_path, + monkey_blacklist_android_path), + 'push %s %s ' % (juice_monkey_blacklist_path, + juice_monkey_blacklist_android_path), + 'shell chmod 777 %s' % monkey_sh_android_path] + +ADB_SHELL_STEPS = ['%s $(OPTIONS) %s %s' % (monkey_sh_android_path, + juice_monkey_blacklist_android_path, + monkey_blacklist_android_path)] +#PATTERN = "^(?P<test_case_id>\w+):\W+(?P<measurement>\d+\.\d+)" +PATTERN = "## Network stats: elapsed time=(?P<measurement>\d+)ms" +FAILURE_PATTERNS = ['\*\* Monkey aborted due to error.', + '\*\* System appears to have crashed'] + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN, + appendall={'units': 'ms'}, failure_patterns=FAILURE_PATTERNS) +testobj = lava_android_test.testdef.AndroidTest( + testname=test_name, + installer=inst, + runner=run, + parser=parser, + default_options=DEFAULT_OPTIONS) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/monkey_long_run/juice_package_black_list b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/monkey_long_run/juice_package_black_list new file mode 100644 index 0000000..56d6045 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/monkey_long_run/juice_package_black_list @@ -0,0 +1,6 @@ +com.android.browser +com.android.development +com.android.quicksearchbox +com.android.speechrecorder +com.android.connectivitymanagertest +org.linaro.glmark2 diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/monkey_long_run/monkey_long_run.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/monkey_long_run/monkey_long_run.sh new file mode 100755 index 0000000..afdc249 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/monkey_long_run/monkey_long_run.sh @@ -0,0 +1,13 @@ +#!/system/bin/sh +#monkey_cmd="monkey -s 1 --pct-touch 10 --pct-motion 20 --pct-nav 20 --pct-majornav 30 --pct-appswitch 20 --throttle 500 2147483647" +if [ $1 == 'juice' ]; then +monkey_cmd="monkey -s 1 --pct-touch 10 --pct-motion 20 --pct-nav 20 --pct-majornav 30 --pct-appswitch 20 --throttle 500 --pkg-blacklist-file $2 30000" +elif [ $1 == 'juno' ]; then +monkey_cmd="monkey -s 1 --pct-touch 10 --pct-motion 20 --pct-nav 20 --pct-majornav 30 --pct-appswitch 20 --throttle 500 --pkg-blacklist-file /data/juno_monkey_blacklist 30000" +else +monkey_cmd="monkey -s 1 --pct-touch 10 --pct-motion 20 --pct-nav 20 --pct-majornav 30 --pct-appswitch 20 --throttle 500 --pkg-blacklist-file $3 25000" +fi + +echo execute command=${monkey_cmd} +${monkey_cmd} +echo MONKEY_RET_CODE=$? diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/monkey_long_run/package_black_list b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/monkey_long_run/package_black_list new file mode 100644 index 0000000..0fc6125 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/monkey_long_run/package_black_list @@ -0,0 +1,2 @@ +com.android.camera +com.android.connectivitymanagertest diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/pm_qa.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/pm_qa.py new file mode 100644 index 0000000..bf2cff8 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/pm_qa.py @@ -0,0 +1,58 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Linaro PM-QA tests for platforms + +**URL:** https://git.linaro.org/gitweb?p=tools/pm-qa.git;a=summary + +**Default options:** /data/benchmark/pm-qa +""" + +import os +import lava_android_test.testdef +from lava_android_test.config import get_config + +DEFAULT_OPTIONS = '/data/benchmark/pm-qa' +test_name = 'pm_qa' +config = get_config() +curdir = os.path.realpath(os.path.dirname(__file__)) +test_sh_name = 'pm-qa.sh' +test_sh_path = os.path.join(curdir, test_name, test_sh_name) +test_sh_android_path = os.path.join(config.installdir_android, + test_name, test_sh_name) + +INSTALL_STEPS_ADB_PRE = ['push %s %s ' % (test_sh_path, + test_sh_android_path), + 'shell chmod 777 %s' % test_sh_android_path] + +ADB_SHELL_STEPS = ["%s $(OPTIONS)" % test_sh_android_path] +PATTERN = "^\s*(?P<test_case_id>\w+)=(?P<result>\w+)\s*$" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser, + default_options=DEFAULT_OPTIONS) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/pm_qa/pm-qa.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/pm_qa/pm-qa.sh new file mode 100755 index 0000000..a570d8e --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/pm_qa/pm-qa.sh @@ -0,0 +1,63 @@ +#!/system/bin/sh + +scripts_dir=$1 && shift +if [ -z "${scripts_dir}" ];then + scripts_dir="/data/benchmark/pm-qa" +fi +test_func(){ + if [ ! -d "${scripts_dir}" ]; then + echo "pm_qa=fail" + exit + fi + + mkdir /data/bin/ + cd /data/bin + + busybox ln -s -f /system/bin/busybox awk + busybox ln -s -f /system/bin/busybox basename + busybox ln -s -f /system/bin/busybox chmod + busybox ln -s -f /system/bin/busybox chown + busybox ln -s -f /system/bin/busybox cp + busybox ln -s -f /system/bin/busybox diff + busybox ln -s -f /system/bin/busybox find + busybox ln -s -f /system/bin/busybox grep + busybox ln -s -f /system/bin/busybox rm + busybox ln -s -f /system/bin/busybox seq + busybox ln -s -f /system/bin/busybox taskset + busybox ln -s -f /system/bin/busybox tee + busybox ln -s -f /system/bin/busybox printf + busybox ln -s -f /system/bin/busybox wc + + busybox ln -s -f /system/bin/fake_command command + busybox ln -s -f /system/bin/fake_sudo sudo + busybox ln -s -f /system/bin/fake_udevadm udevadm + + export PATH=/data/bin:$PATH + + cd "${scripts_dir}" + + pwd_dir=$PWD + echo $pwd + tests_dirs="cpuidle cpufreq cpuhotplug sched_mc suspend thermal utils" + + for dir in $tests_dirs; do + subDir=${pwd_dir}/$dir + if [ -d $subDir ]; then + cd $subDir + else + continue + fi + + echo `pwd` + for file in `find . -name "*.sh"`; do + path=$file + echo $path + /system/bin/sh $path + done + cd .. + done + + echo "pm_qa=pass" +} + +test_func diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/sched_tests.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/sched_tests.py new file mode 100644 index 0000000..df91439 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/sched_tests.py @@ -0,0 +1,49 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Drives scheduler test scripts that are pre-intalled on Linaro Android +builds of big.LITTLE + +**URL:** https://linaro-private.git.linaro.org/gitweb?p=bL_tests/sched_tests.git + +**Default options:** None +""" + +import lava_android_test.testdef + +test_name = 'sched_tests' + +DEFAULT_OPTIONS='output all' + +INSTALL_STEPS_ADB_PRE = [] +ADB_SHELL_STEPS = ['run_sched_test $(OPTIONS)'] +PATTERN = "(?P<test_case_id>.*-*)\s+:\s+(?P<result>(SUCCESS|FAILED))" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser, + default_options=DEFAULT_OPTIONS) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/shells/__init__.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/shells/__init__.py new file mode 100644 index 0000000..7c13426 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/shells/__init__.py @@ -0,0 +1,33 @@ +# copyright (C) 2012 Linaro Limited +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +This directory contains the tests that only need to run the android shell +scripts that stored under this directory. +Please see the example.sh for a reference. +Please note this is not a test that can be run. + +**URL:** None + +**Default options:** None +""" + + +import os +curdir = os.path.dirname(os.path.realpath(__file__)) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/shells/binder.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/shells/binder.sh new file mode 100755 index 0000000..d3fb43d --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/shells/binder.sh @@ -0,0 +1,13 @@ +#!/system/bin/sh + +chmod 777 /data/nativebenchmark/binderAddInts +if [ -z "$1" ]; then + /data/nativebenchmark/binderAddInts -n 10 +else + /data/nativebenchmark/binderAddInts -n $1 +fi +if [ $? -eq 0 ]; then + echo "binder=pass"; +else + echo "binder=fail"; +fi diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/shells/custom.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/shells/custom.sh new file mode 100755 index 0000000..4b78632 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/shells/custom.sh @@ -0,0 +1,14 @@ +#!/system/bin/sh + +echo "The custom shell will be run is:" +echo " $@" +echo "Shell starts:" +$@ +echo "Shell ends:" +RET=$? +echo "The exit status is: $RET" +if [ $? -ne 0 ]; then + echo "custom=fail" +else + echo "custom=pass" +fi diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/shells/dalvik-vm-unit-tests.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/shells/dalvik-vm-unit-tests.sh new file mode 100755 index 0000000..65ca818 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/shells/dalvik-vm-unit-tests.sh @@ -0,0 +1,12 @@ +#!/system/bin/sh +# +# Dalvik-VM unit tests. +# + +chmod 777 /data/nativetest/dalvik-vm-unit-tests/dalvik-vm-unit-tests +/data/nativetest/dalvik-vm-unit-tests/dalvik-vm-unit-tests +if [ $? -eq 0 ]; then + echo "dalvik-vm-unit-tests=pass" +else + echo "dalvik-vm-unit-tests=fail" +fi diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/shells/example.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/shells/example.sh new file mode 100755 index 0000000..7e7e858 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/shells/example.sh @@ -0,0 +1,4 @@ +#!/system/bin/sh + +echo "test_case_fail=fail" +echo "test_case_pass=pass"
\ No newline at end of file diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/skia.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/skia.py new file mode 100644 index 0000000..8edbaee --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/skia.py @@ -0,0 +1,89 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Runs the skia benchmark to test 2D graphics performance. + +**URL:** https://sites.google.com/site/skiadocs/ + +**Default options:** None +""" + +import re +import lava_android_test.testdef + +test_name = 'skia' + +DEFAULT_OPTIONS = '1000' + +INSTALL_STEPS_ADB_PRE = [] +# Skia can do many more benchmarks, but it becomes almost too much data +# to make a nice chart for. The -match limits the ones we run +ADB_SHELL_STEPS = ['logcat -c', + 'skia_bench -repeat $(OPTIONS) -timers w -config 565 -match bitmap', + 'skia_bench -repeat $(OPTIONS) -timers w -config 565 -match rects', + 'skia_bench -repeat $(OPTIONS) -timers w -config 565 -match repeat', + 'logcat -d -s "skia:*"'] + + +class SkiaTestParser(lava_android_test.testdef.AndroidTestParser): + + def parse(self, result_filename=None, output_filename=None, + test_name=test_name): + pat_test = re.compile(r'running bench \[.*?\]\W+(?P<test>\w+)\W+$') + pat_type = re.compile( + r'\d+\):\W+(?P<type>\w+):\W+msecs =\W+(?P<time>\d+.\d+)') + + test = None + with open(output_filename, 'r') as stream: + for lineno, line in enumerate(stream, 1): + match = pat_test.search(line) + if match: + test = match.group('test') + else: + match = pat_type.search(line) + if match: + data = {} + data['test_case_id'] = "%s_%s" % (test, + match.group('type')) + data['measurement'] = match.group('time') + data['result'] = 'pass' + data['units'] = 'ms' + data['log_filename'] = result_filename + data['log_lineno'] = lineno + self.results['test_results'].append(data) + + if self.fixupdict: + self.fixresults(self.fixupdict) + if self.appendall: + self.appendtoall(self.appendall) + self.fixmeasurements() + self.fixids() + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = SkiaTestParser() +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser, + default_options=DEFAULT_OPTIONS) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/sleep.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/sleep.py new file mode 100644 index 0000000..faf39ad --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/sleep.py @@ -0,0 +1,48 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Action for sleeping some time between test actions + +**URL:** None + +**Default options:** None +""" +import lava_android_test.config +import lava_android_test.testdef + +test_name = 'sleep' + +DEFAULT_OPTIONS = '10' + +INSTALL_STEPS_ADB_PRE = [] +ADB_SHELL_STEPS = ['sleep $(OPTIONS); echo sleep_$(OPTIONS): PASS'] +PATTERN = "^\s*(?P<test_case_id>[^:]+?):\s+(?P<result>(PASS|FAIL)?)\s*$" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser, + default_options=DEFAULT_OPTIONS) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/task_placement.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/task_placement.py new file mode 100644 index 0000000..04fe252 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/task_placement.py @@ -0,0 +1,49 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Drives task placement scripts that are pre-intalled on Linaro Android +builds of big.LITTLE + +**URL:** https://linaro-private.git.linaro.org/gitweb?p=bL_tests/task-placement-tests.git + +**Default options:** None +""" + +import lava_android_test.testdef + +test_name = 'task_placement' + +DEFAULT_OPTIONS='' + +INSTALL_STEPS_ADB_PRE = [] +ADB_SHELL_STEPS = ['run_all_task_placement_tests.sh $(OPTIONS)'] +PATTERN = "(?P<test_case_id>.*-*)\s+:\s+(?P<result>(PASS|FAIL))" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser, + default_options=DEFAULT_OPTIONS) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/tjbench.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/tjbench.py new file mode 100644 index 0000000..f86f3d6 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/tjbench.py @@ -0,0 +1,140 @@ +# Copyright (c) 2011-2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Tests the performance of libjpegturbo + +**URL:** http://sourceforge.net/projects/libjpeg-turbo/ + +**Default options:** None +""" + +import os +import re +import lava_android_test.testdef +from lava_android_test.config import get_config + +test_name = 'tjbench' +config = get_config() +curdir = os.path.realpath(os.path.dirname(__file__)) +ppm_file_name = 'nightshot_iso_100.ppm' +ppm_url = ("http://testdata.validation.linaro.org/tjbench/" + "nightshot_iso_100.ppm") +ppm_temp_path = os.path.join(config.tempdir_host, ppm_file_name) +ppm_android_path = os.path.join(config.tempdir_android, test_name, + ppm_file_name) +ppm_tmpfs_path = os.path.join('/data/local/tmp/mytmpfs', ppm_file_name) +INSTALL_STEPS_HOST_PRE = ['wget --no-check-certificate -q "%s" -O ./%s' % ( + ppm_url, ppm_file_name)] +INSTALL_STEPS_ADB_PRE = ['push %s %s' % (ppm_temp_path, ppm_android_path)] + +RUN_STEPS_ADB_SHELL = ['mkdir /data/local/tmp/mytmpfs', + 'mount -t tmpfs -o mode=777 tmpfs /data/local/tmp/mytmpfs', + 'dd if=%s of=%s' % (ppm_android_path, ppm_tmpfs_path), + 'tjbench %s 95 -rgb -quiet scale 1/2' % ppm_tmpfs_path, + 'tjbench %s 95 -rgb -quiet' % ppm_tmpfs_path, + 'umount /data/local/tmp/mytmpfs', + 'rmdir /data/local/tmp/mytmpfs'] + + +class TjbenchTestParser(lava_android_test.testdef.AndroidTestParser): + + def parse(self, result_filename='stdout.log', output_filename='stdout.log', + test_name=''): + """Parse test output to gather results + Use the pattern specified when the class was instantiated to look + through the results line-by-line and find lines that match it. + Results are then stored in self.results. If a fixupdict was supplied + it is used to convert test result strings to a standard format. + """ + try: + unit_pat = re.compile( + r'^\s*All performance values in (?P<units>\S+)\s*$') + measure_pat = re.compile( + ('^\s*(?P<format>\S+)\s+\S+\s+(?P<subsamp>\S+)\s+' + '(?P<qual>\d+)\s+\d+\s+\d+\s+(?P<comp_perf>[\d\.]+)\s+' + '(?P<comp_ratio>[\d\.]+)\s+(?P<dcomp_perf>[\d\.]+)\s*$') + ) + except Exception as strerror: + raise RuntimeError( + "AndroidTestParser - Invalid regular expression '%s' - %s" % ( + self.pattern, strerror)) + units = None + prefix_hash = {} + with open(output_filename, 'r') as stream: + for lineno, line in enumerate(stream, 1): + if units is None: + match = unit_pat.search(line) + if not match: + continue + else: + units = match.group('units') + + match = measure_pat.search(line) + if match: + tmpdata = match.groupdict() + test_case_prefix = '%s_%s_%s' % (tmpdata['format'], + tmpdata['subsamp'], + tmpdata['qual']) + if not prefix_hash.get(test_case_prefix): + prefix_hash[test_case_prefix] = True + test_case_prefix = '%s_%s' % (test_case_prefix, + 'scale_half') + common_data = {'log_filename': result_filename, + 'log_lineno': lineno, + 'result': 'pass' + } + comp_perf = {'test_case_id': '%s_%s' % (test_case_prefix, + 'comp_perf'), + 'units': units, + 'measurement': tmpdata['comp_perf'] + } + comp_perf.update(common_data) + comp_ratio = {'test_case_id': '%s_%s' % (test_case_prefix, + 'comp_ratio'), + 'units': '%', + 'measurement': tmpdata['comp_ratio'] + } + comp_ratio.update(common_data) + dcomp_perf = {'test_case_id': '%s_%s' % (test_case_prefix, + 'dcomp_perf'), + 'units': units, + 'measurement': tmpdata['dcomp_perf'] + } + dcomp_perf.update(common_data) + self.results['test_results'].extend([comp_perf, comp_ratio, + dcomp_perf]) + if self.fixupdict: + self.fixresults(self.fixupdict) + if self.appendall: + self.appendtoall(self.appendall) + self.fixmeasurements() + self.fixids(test_name=test_name) + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_host_pre=INSTALL_STEPS_HOST_PRE, + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=RUN_STEPS_ADB_SHELL) +parser = TjbenchTestParser() +testobj = lava_android_test.testdef.AndroidTest(testname="tjbench", + installer=inst, + runner=run, + parser=parser) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/usbhardware.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/usbhardware.py new file mode 100644 index 0000000..8a2a796 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/usbhardware.py @@ -0,0 +1,56 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Ensures USB is enabled on the device by checking /sys entries + +**URL:** None + +**Default options:** None +""" + +import os +import lava_android_test.testdef +from lava_android_test.config import get_config + +test_name = 'usbhardware' +config = get_config() +curdir = os.path.realpath(os.path.dirname(__file__)) +test_sh_name = 'usbhardware.sh' +test_sh_path = os.path.join(curdir, test_name, test_sh_name) +test_sh_android_path = os.path.join(config.installdir_android, + test_name, test_sh_name) + +INSTALL_STEPS_ADB_PRE = ['push %s %s ' % (test_sh_path, + test_sh_android_path), + 'shell chmod 777 %s' % test_sh_android_path] + +ADB_SHELL_STEPS = [test_sh_android_path] +PATTERN = "^\s*(?P<test_case_id>\w+)=(?P<result>\w+)\s*$" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/usbhardware/usbhardware.sh b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/usbhardware/usbhardware.sh new file mode 100755 index 0000000..d7e8f7d --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/usbhardware/usbhardware.sh @@ -0,0 +1,13 @@ +#!/system/bin/sh + +test_func(){ + if [ ! -f /sys/class/android_usb/android0/state ]; then + echo "usbhardware=fail" + exit + fi + + cat /sys/class/android_usb/android0/state + echo "usbhardware=pass" +} + +test_func diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/v8.py b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/v8.py new file mode 100644 index 0000000..e017f00 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/test_definitions/v8.py @@ -0,0 +1,53 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Performs the v8 benchmark on Android and returns the metrics + +**URL:** http://v8.googlecode.com/svn/data/benchmarks/v5/run.html + +**Default options:** None +""" + + +import lava_android_test.config +import lava_android_test.testdef + +test_name = 'v8' + +INSTALL_STEPS_ADB_PRE = [] +adb_shell = ('"' + 'cd /data/benchmark/v8;' + 'if which v8shell 2>/dev/null 1>/dev/null;' + 'then v8shell run.js; ' + 'else d8 run.js; fi' + '"') +ADB_SHELL_STEPS = [adb_shell] +PATTERN = "^(?P<test_case_id>.*?):\s+(?P<measurement>[\d.]+)\s*$" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/testdef.py b/build/lib.linux-x86_64-2.7/lava_android_test/testdef.py new file mode 100644 index 0000000..0cb97aa --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/testdef.py @@ -0,0 +1,771 @@ +# Copyright (C) 2010-2012 Linaro Limited +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import base64 +import hashlib +import logging +import os +import re +import string +import time +import tempfile +import decimal +import zipfile + +from datetime import datetime +from uuid import uuid4 + +from lava_android_test.adb import ADB +from lava_android_test.api import ITest +from lava_android_test.config import get_config +from lava_android_test.utils import write_file, geturl +from lava_android_test import hwprofile, swprofile +from linaro_dashboard_bundle.io import DocumentIO + + +class Attachment(object): + + def __init__(self, pathname=None, mime_type=None): + self.pathname = pathname + self.mime_type = mime_type + + def copy_to_result_dir(self, adb=None, resultsdir=None): + """ + Copy the file specified by the pathname to result + directory of this time test, beacuse some test will + generate the result to the same path file. + And Please Note that pathname must be the absolute + path in the device. + """ + if (not self.pathname) or (not self.pathname.startswith('/')): + return + if not resultsdir: + return + if not adb: + adb = ADB() + if not adb.exists(resultsdir): + adb.makedirs(resultsdir) + ret_code = adb.copy(self.pathname, os.path.join(resultsdir, + os.path.basename(self.pathname))) + if ret_code != 0: + raise RuntimeError( + "Failed to copy file '%s' to '%s' on device(%s)" % + (self.pathname, resultsdir, adb.get_serial())) + + def generate_bundle(self, adb=None, resultsdir=None): + data_bundle = {} + if not self.pathname: + return data_bundle + if not adb: + adb = ADB() + config = get_config() + basename = os.path.basename(self.pathname) + android_path = os.path.join(resultsdir, basename) + if adb.exists(android_path): + tmp_path = os.path.join(config.tempdir_host, basename) + adb.pull(android_path, tmp_path) + with open(tmp_path, 'rb') as stream: + data = stream.read() + if data: + data_bundle = {"pathname": basename, + "mime_type": self.mime_type, + "content": base64.standard_b64encode(data)} + os.unlink(tmp_path) + return data_bundle + + +class AndroidTest(ITest): + """Base class for defining tests. + + This can be used by test definition files to create an object that + contains the building blocks for installing tests, running them, + and parsing the results. + + testname - name of the test or test suite + version - version of the test or test suite + installer - AbrekInstaller instance to use + runner - AbrekRunner instance to use + parser - AbrekParser instance to use + """ + adb = ADB() + default_attachments = [ + Attachment(pathname="stderr.log", mime_type="text/plain"), + Attachment(pathname="stdout.log", mime_type="text/plain"), + Attachment(pathname="screencap.png", mime_type="image/png"), + Attachment(pathname="tombstones.zip", mime_type="application/zip") + ] + + def setadb(self, adb=None): + self.adb = adb + + def getadb(self): + return self.adb + + def __init__(self, testname, version="", installer=None, runner=None, + parser=None, default_options=None, + org_ouput_file='stdout.log', + attachments=[]): + self.testname = testname + self.version = version + self.installer = installer + self.runner = runner + self.parser = parser + self.default_options = default_options + self.org_ouput_file = org_ouput_file + self.origdir = os.path.abspath(os.curdir) + self.attachments = self.default_attachments + if self.org_ouput_file and (self.org_ouput_file != "stdout.log"): + self.attachments.append( + Attachment(pathname=self.org_ouput_file, + mime_type="text/plain")) + if attachments: + self.attachments.extend(attachments) + + def set_runner(self, runner=None): + self.runner = runner + + def set_parser(self, parser=None): + self.parser = parser + + def install(self, install_options=None): + """Install the test suite. + + This creates an install directory under the user's XDG_DATA_HOME + directory to mark that the test is installed. The installer's + install() method is then called from this directory to complete any + test specific install that may be needed. + """ + if not self.installer: + raise RuntimeError("no installer defined for '%s'" % + self.testname) + self.installer.setadb(self.adb) + config = get_config() + if not os.path.exists(config.tempdir_host): + os.makedirs(config.tempdir_host) + os.chdir(config.tempdir_host) + installdir = os.path.join(config.installdir_android, self.testname) + if self.adb.exists(installdir): + raise RuntimeError("%s is already installed" % self.testname) + ret_code = self.adb.makedirs(installdir) + if ret_code != 0: + raise RuntimeError( + "Failed to create directory(%s) for test(%s)" % + (installdir, self.testname)) + + if install_options is not None: + self.adb.shell('echo "%s" > %s/install_options' % + (install_options, installdir)) + try: + self.installer.install(install_options) + except Exception as e: + self.uninstall() + raise RuntimeError( + "Failed to install test(%s):%s" % (self.testname, e)) + finally: + os.chdir(self.origdir) + + def uninstall(self): + """Uninstall the test suite. + + Uninstalling just recursively removes the test specific directory + under the user's XDG_DATA_HOME directory. This will both mark + the test as removed, and clean up any files that were downloaded + or installed under that directory. Dependencies are intentionally + not removed by this. And others installed files won't be removed too. + """ + config = get_config() + path = os.path.join(config.installdir_android, self.testname) + if self.adb.exists(path): + self.adb.rmtree(path) + + def _add_install_options(self, bundle, config): + optionfile = "%s/%s/install_options" % (config.installdir_android, + self.testname) + if self.adb.exists(optionfile): + output = self.adb.run_adb_cmd('shell cat %s' % optionfile)[1] + bundle['test_runs'][0]['attributes']['install_options'] = output[0] + + def _savetestdata(self, analyzer_assigned_uuid, run_options=""): + config = get_config() + TIMEFORMAT = '%Y-%m-%dT%H:%M:%SZ' + bundle = { + 'format': config.bundle_format, + 'test_runs': [ + { + 'analyzer_assigned_uuid': analyzer_assigned_uuid, + 'analyzer_assigned_date': + self.runner.starttime.strftime(TIMEFORMAT), + 'time_check_performed': False, + 'attributes':{}, + 'test_id': self.testname, + 'test_results':[], + 'attachments':[], + 'hardware_context': hwprofile.get_hardware_context(self.adb), + 'software_context': swprofile.get_software_context(self.adb) + } + ] + } + if run_options: + bundle['test_runs'][0]['attributes']['run_options'] = run_options + self._add_install_options(bundle, config) + filename_host = os.path.join(config.tempdir_host, 'testdata.json') + write_file(DocumentIO.dumps(bundle), filename_host) + filename_target = os.path.join(self.resultsdir, 'testdata.json') + self.adb.push(filename_host, filename_target) + + def run(self, quiet=False, run_options=None): + if not self.runner: + raise RuntimeError("no test runner defined for '%s'" % + self.testname) + if not run_options: + run_options = self.default_options + + self.runner.setadb(self.adb) + config = get_config() + if not os.path.exists(config.tempdir_host): + os.mkdir(config.tempdir_host) + os.chdir(config.tempdir_host) + resultname = (self.testname + + str(time.mktime(datetime.utcnow().timetuple()))) + self.resultsdir = os.path.join(config.resultsdir_android, resultname) + self.adb.makedirs(self.resultsdir) + self.runner.run(self.resultsdir, run_options=run_options) + self._gather_tombstones(self.resultsdir) + self._copyattachments(self.resultsdir) + self._screencap(self.resultsdir) + self._savetestdata(str(uuid4()), run_options=run_options) + result_id = os.path.basename(self.resultsdir) + print("ANDROID TEST RUN COMPLETE: Result id is '%s'" % result_id) + os.chdir(self.origdir) + return result_id + + def _screencap(self, resultsdir): + target_path = '/system/bin/screenshot' + self.adb.shell('%s %s' % (target_path, os.path.join(resultsdir, + 'screencap.png'))) + + def _gather_tombstones(self, resultsdir): + """ + Extension of the generate bundle function. + Grabs the tombstones and appends them to the bundle. + """ + config = get_config() + tombstone_path = '/data/tombstones' + tombstone_zip = os.path.join(config.tempdir_host, 'tombstones.zip') + if self.adb.exists(tombstone_path): + tmp_path = os.path.join(config.tempdir_host, 'tombstones') + self.adb.pull(tombstone_path, tmp_path) + self.adb.shell("rm -R " + tombstone_path) + zipf = zipfile.ZipFile(tombstone_zip, mode='w') + for rootdir, dirs, files in os.walk(tmp_path): + for f in files: + zipf.write(os.path.join(rootdir, f), arcname=f) + zipf.close() + self.adb.push(tombstone_zip, os.path.join(resultsdir, + 'tombstones.zip')) + os.unlink(tombstone_zip) + + def _copyattachments(self, resultsdir): + for attachment in self.attachments: + attachment.copy_to_result_dir(adb=self.adb, resultsdir=resultsdir) + + def parse(self, resultname): + if not self.parser: + raise RuntimeError("no test parser defined for '%s'" % + self.testname) + output_filename = os.path.basename(self.org_ouput_file) + config = get_config() + os.chdir(config.tempdir_host) + resultsdir_android = os.path.join(config.resultsdir_android, + resultname) + result_filename_android = os.path.join(resultsdir_android, + output_filename) + result_filename_host_temp = tempfile.mkstemp(prefix=output_filename, + dir=config.tempdir_host)[1] + self.adb.pull(result_filename_android, result_filename_host_temp) + self.parser.parse(output_filename, + output_filename=result_filename_host_temp, + test_name=self.testname) + os.remove(result_filename_host_temp) + os.chdir(self.origdir) + + +class AndroidTestInstaller(object): + + adb = ADB() + + """Base class for defining an installer object. + + This class can be used as-is for simple installers, or extended for more + advanced funcionality. + + steps_host - list of steps to be executed on host + steps_android - list of steps to be executed on android + url - location from which the test suite should be downloaded + md5 - md5sum to check the integrety of the download + """ + def __init__(self, steps_host_pre=[], steps_adb_pre=[], apks=[], + steps_adb_post=[], steps_host_post=[], + url=None, md5=None, **kwargs): + self.steps_host_pre = steps_host_pre + self.steps_adb_pre = steps_adb_pre + self.apks = apks + self.steps_adb_post = steps_adb_post + self.steps_host_post = steps_host_post + self.url = url + self.md5 = md5 + + def _download(self): + """Download the file specified by the url and check the md5. + Returns the path and filename if successful, otherwise return None + """ + if not self.url: + return 0 + config = get_config() + filename = geturl(self.url, config.tempdir_host) + #If the file does not exist, then the download was not successful + if not os.path.exists(filename): + return None + if self.md5: + checkmd5 = hashlib.md5() + with open(filename, 'rb') as fd: + data = fd.read(0x10000) + while data: + checkmd5.update(data) + data = fd.read(0x10000) + if checkmd5.hexdigest() != self.md5: + raise RuntimeError("Unexpected md5sum downloading %s" % + filename) + return None + return filename + + def _installapk(self): + for apk in self.apks: + rc = self.adb.installapk(apk) + if rc: + raise RuntimeError( + "Failed to install apk '%s' failed. %d" % (apk, rc)) + + def install(self, install_options=None): + self._download() + _run_steps_host(self.steps_host_pre, self.adb.serial, install_options) + _run_steps_adb(self.steps_adb_pre, self.adb.serial, install_options) + self._installapk() + _run_steps_adb(self.steps_adb_post, self.adb.serial, install_options) + _run_steps_host(self.steps_host_post, self.adb.serial, install_options) + + def setadb(self, adb=None): + self.adb = adb + + +class AndroidTestRunner(object): + + adb = ADB() + """Base class for defining an test runner object. + + This class can be used as-is for simple execution with the expectation + that the run() method will be called from the directory where the test + was installed. Steps, if used, should handle changing directories from + there to the directory where the test was extracted if necessary. + This class can also be extended for more advanced funcionality. + + steps - list of steps to be executed in a shell + """ + def __init__(self, steps_host_pre=[], steps_adb_pre=[], + adbshell_steps=[], steps_adb_post=[], steps_host_post=[]): + self.steps_host_pre = steps_host_pre + self.steps_adb_pre = steps_adb_pre + self.adbshell_steps = adbshell_steps + self.steps_adb_post = steps_adb_post + self.steps_host_post = steps_host_post + self.testoutput = [] + + def _run_steps_adbshell(self, resultsdir, option=None): + stdoutlog = os.path.join(resultsdir, 'stdout.log') + stderrlog = os.path.join(resultsdir, 'stderr.log') + try: + for cmd in self.adbshell_steps: + if option is not None: + cmd = cmd.replace('$(OPTIONS)', option) + else: + cmd = cmd.replace('$(OPTIONS)', '') + if resultsdir is not None: + cmd = cmd.replace('$(RESULTDIR)', resultsdir) + else: + cmd = cmd.replace('$(RESULTDIR)', '') + cmd = cmd.strip() + ret_code = self.adb.run_adb_shell_for_test(cmd, + stdoutlog, + stderrlog) + if ret_code != 0: + raise Exception( + "Failed to execute command(%s):ret_code=%d" % (cmd, + ret_code)) + except: + raise + finally: + self.adb.shell('getprop', + os.path.join(resultsdir, 'propoutput.log')) + self.adb.shell('cat /proc/cpuinfo', + os.path.join(resultsdir, 'cpuinfo.log')) + self.adb.shell('cat /proc/meminfo', + os.path.join(resultsdir, 'meminfo.log')) + + def run(self, resultsdir, run_options=None): + self.starttime = datetime.utcnow() + _run_steps_host(self.steps_host_pre, self.adb.serial, + option=run_options, resultsdir=resultsdir) + _run_steps_adb(self.steps_adb_pre, self.adb.serial, + option=run_options, resultsdir=resultsdir) + self._run_steps_adbshell(resultsdir, option=run_options) + _run_steps_adb(self.steps_adb_post, self.adb.serial, + option=run_options, resultsdir=resultsdir) + _run_steps_host(self.steps_host_post, self.adb.serial, + option=run_options, resultsdir=resultsdir) + self.endtime = datetime.utcnow() + + def setadb(self, adb=None): + self.adb = adb + + +class AndroidTestParser(object): + adb = ADB() + PASS_PATS = ['PASS', 'OK', 'TRUE', 'DONE'] + FAIL_PATS = ['FAIL', 'NG', 'FALSE'] + SKIP_PATS = ['SKIP'] + + """Base class for defining a test parser + + This class can be used as-is for simple results parsers, but will + likely need to be extended slightly for many. If used as it is, + the parse() method should be called while already in the results + directory and assumes that a file for test output will exist called + testoutput.log. + + pattern - regexp pattern to identify important elements of test output + For example: If your testoutput had lines that look like: + "test01: PASS", then you could use a pattern like this: + "^(?P<testid>\w+):\W+(?P<result>\w+)" + This would result in identifying "test01" as testid and + "PASS" as result. Once parse() has been called, + self.results.test_results[] contains a list of dicts of all the + key,value pairs found for each test result + fixupdict - dict of strings to convert test results to standard strings + For example: if you want to standardize on having pass/fail results + in lower case, but your test outputs them in upper case, you could + use a fixupdict of something like: {'PASS':'pass','FAIL':'fail'} + appendall - Append a dict to the test_results entry for each result. + For example: if you would like to add units="MB/s" to each result: + appendall={'units':'MB/s'} + failure_patterns - regexp pattern to identify whether the test is failed + or success + If there is a string match one pattern in failure_patterns, + then this test will be deal as failed. + """ + def __init__(self, pattern=None, fixupdict=None, appendall={}, + failure_patterns=[]): + self.pattern = pattern + self.fixupdict = fixupdict + self.results = {'test_results': []} + self.appendall = appendall + self.failure_patterns = failure_patterns + + def _find_testid(self, test_id): + for x in self.results['test_results']: + if x['testid'] == test_id: + return self.results['test_results'].index(x) + + def parse(self, result_filename='stdout.log', + output_filename='stdout.log', test_name=''): + """Parse test output to gather results + + Use the pattern specified when the class was instantiated to look + through the results line-by-line and find lines that match it. + Results are then stored in self.results. If a fixupdict was supplied + it is used to convert test result strings to a standard format. + """ + + self.real_parse(result_filename=result_filename, + output_filename=output_filename, test_name=test_name) + + self.fixresults(self.fixupdict) + if self.appendall: + self.appendtoall(self.appendall) + self.fixmeasurements() + self.fixids(test_name=test_name) + + def real_parse(self, result_filename='stdout.log', + output_filename='stdout.log', test_name=''): + """Using the pattern to do the real parse operation + + generate the test_results elements from the result file by parsing + with the pattern specified. + """ + if not self.pattern: + return + + try: + pat = re.compile(self.pattern) + except Exception as strerror: + raise RuntimeError( + "AndroidTestParser - Invalid regular expression '%s' - %s" % ( + self.pattern, strerror)) + + failure_pats = [] + for failure_pattern in self.failure_patterns: + try: + failure_pat = re.compile(failure_pattern) + except Exception as strerror: + raise RuntimeError( + "AndroidTestParser - Invalid regular expression '%s' - %s" % ( + failure_pattern, strerror)) + failure_pats.append(failure_pat) + test_ok = True + + with open(output_filename, 'r') as stream: + for lineno, line in enumerate(stream, 1): + if test_ok == True: + for failure_pat in failure_pats: + failure_match = failure_pat.search(line) + if failure_match: + test_ok = False + + match = pat.search(line) + if not match: + continue + data = match.groupdict() + data["log_filename"] = result_filename + data["log_lineno"] = lineno + if data.get('result') is None: + data['result'] = test_ok and 'pass' or 'fail' + self.results['test_results'].append(data) + + def append(self, testid, entry): + """Appends a dict to the test_results entry for a specified testid + + This lets you add a dict to the entry for a specific testid + entry should be a dict, updates it in place + """ + index = self._find_testid(testid) + self.results['test_results'][index].update(entry) + + def appendtoall(self, entry): + """Append entry to each item in the test_results. + + entry - dict of key,value pairs to add to each item in the + test_results + """ + for t in self.results['test_results']: + t.update(entry) + + def fixresults(self, fixupdict): + """Convert results to a known, standard format + + pass it a dict of keys/values to replace + For instance: + {"TPASS":"pass", "TFAIL":"fail"} + This is really only used for qualitative tests + """ + for t in self.results['test_results']: + if "result" in t: + if not fixupdict: + if self.is_result_match(t['result'], self.PASS_PATS): + t['result'] = 'pass' + elif self.is_result_match(t['result'], self.FAIL_PATS): + t['result'] = 'fail' + elif self.is_result_match(t['result'], self.SKIP_PATS): + t['result'] = 'skip' + else: + t['result'] = 'unknown' + elif t['result'] in fixupdict: + t['result'] = fixupdict[t['result']] + else: + t['result'] = 'unknown' + + def is_result_match(self, result, patterns=[]): + cap_result = string.upper(result) + for pattern in patterns: + cap_pattern = string.upper(pattern) + pat_index = string.find(cap_result, cap_pattern) + if pat_index > -1: + return True + + return False + + def fixmeasurements(self): + """Measurements are often read as strings, but need to be + decimal.Decimal as per dashboard bundle format JSON schema. + """ + for test_case in self.results['test_results']: + if 'measurement' in test_case: + try: + test_case['measurement'] = decimal.Decimal( + test_case['measurement']) + except decimal.InvalidOperation: + logging.warning("Invalid measurement %s" % ( + test_case['measurement'])) + del test_case['measurement'] + + def fixids(self, test_name=''): + """ + Convert spaces to _ in test_case_id and remove illegal characters + """ + badchars = "[^a-zA-Z0-9\._-]" + for test_case in self.results['test_results']: + if 'test_case_id' in test_case: + test_case['test_case_id'] = test_case[ + 'test_case_id'].replace(" ", "_") + test_case['test_case_id'] = re.sub(badchars, "", + test_case['test_case_id']) + else: + test_case['test_case_id'] = test_name + + def setadb(self, adb=None): + self.adb = adb + + def set_result_patterns(self, pass_pat=[], fail_pat=[], skip_pat=[]): + if pass_pat: + self.PASS_PATS = pass_pat + if fail_pat: + self.FAIL_PATS = fail_pat + if skip_pat: + self.SKIP_PATS = skip_pat + + +class AndroidInstrumentTestParser(AndroidTestParser): + + def parse(self, result_filename='stdout.log', output_filename='stdout.log', + test_name=''): + """Parser for Instrument test that run with the -r option + """ + pat_test = re.compile( + r'^\s*INSTRUMENTATION_STATUS:\s*test=(?P<test_case_id>.+)\s*$') + pat_status_code = re.compile( + r'^\s*INSTRUMENTATION_STATUS_CODE:\s*(?P<status_code>[\d-]+)\s*$') + data = {} + with open(output_filename, 'r') as stream: + for lineno, line in enumerate(stream, 1): + match = pat_test.search(line) + if match: + data['test_case_id'] = match.group('test_case_id') + continue + + match = pat_status_code.search(line) + if match: + status_code = match.group('status_code') + if status_code == '1': + # test case started + data = {} + elif data['test_case_id']: + if status_code == '0': + data['result'] = 'pass' + else: + data['result'] = 'fail' + data["log_filename"] = result_filename + data["log_lineno"] = lineno + self.results['test_results'].append(data) + data = {} + continue + + if self.fixupdict: + self.fixresults(self.fixupdict) + if self.appendall: + self.appendtoall(self.appendall) + self.fixmeasurements() + self.fixids() + + +class AndroidSimpleTestParser(AndroidTestParser): + + def real_parse(self, result_filename='stdout.log', + output_filename='stdout.log', test_name=''): + self.res_pattern = ("^\s*(?P<test_case_id>.+?)\s*=" + "\s*(?P<result>(pass|fail|ok|ng|true|false|skip|done))\s*$") + self.measurement_pattern = ("^\s*(?P<test_case_id>.+?)\s*=" + "\s*(?P<measurement>[\.\d]+)\s*$") + self.measurement_units_pattern = ("^\s*(?P<test_case_id>.+?)\s*=" + "\s*(?P<measurement>[\.\d]+)\s+(?P<units>\S+)\s*$") + + res_pat = re.compile(self.res_pattern) + measurement_pat = re.compile(self.measurement_pattern) + measurement_units_pat = re.compile(self.measurement_units_pattern) + + with open(output_filename, 'r') as stream: + for lineno, line in enumerate(stream, 1): + match = res_pat.search(line) + if not match: + match = measurement_pat.search(line) + if not match: + match = measurement_units_pat.search(line) + if not match: + continue + data = match.groupdict() + data["log_filename"] = result_filename + data["log_lineno"] = lineno + if data.get('result') is None: + data['result'] = 'pass' + + self.results['test_results'].append(data) + + +def _run_steps_host(steps=[], serial=None, option=None, resultsdir=None): + adb = ADB(serial) + for cmd in steps: + if serial is not None: + cmd = cmd.replace('$(SERIAL)', serial) + else: + cmd = cmd.replace('$(SERIAL)', '') + if option is not None: + cmd = cmd.replace('$(OPTIONS)', option) + else: + cmd = cmd.replace('$(OPTIONS)', '') + if resultsdir is not None: + cmd = cmd.replace('$(RESULTDIR)', resultsdir) + else: + cmd = cmd.replace('$(RESULTDIR)', '') + + cmd = cmd.strip() + rc, output = adb.run_cmd_host(cmd, quiet=False) + if rc: + raise RuntimeError( + "Run step '%s' failed. %d : %s" % (cmd, rc, output)) + if resultsdir is not None: + stdoutlog = os.path.join(resultsdir, 'stdout.log') + adb.push_stream_to_device(output, stdoutlog) + + +def _run_steps_adb(steps=[], serial=None, option=None, resultsdir=None): + adb = ADB(serial) + for cmd in steps: + if option is not None: + cmd = cmd.replace('$(OPTIONS)', option) + else: + cmd = cmd.replace('$(OPTIONS)', '') + if resultsdir is not None: + cmd = cmd.replace('$(RESULTDIR)', resultsdir) + else: + cmd = cmd.replace('$(RESULTDIR)', '') + cmd = cmd.strip() + rc, output = adb.run_adb_cmd(cmd, quiet=False) + if rc: + raise RuntimeError( + "Run step '%s' failed. %d : %s" % (cmd, rc, output)) + if resultsdir is not None: + stdoutlog = os.path.join(resultsdir, 'stdout.log') + adb.push_stream_to_device(output, stdoutlog) diff --git a/build/lib.linux-x86_64-2.7/lava_android_test/utils.py b/build/lib.linux-x86_64-2.7/lava_android_test/utils.py new file mode 100644 index 0000000..75290d2 --- /dev/null +++ b/build/lib.linux-x86_64-2.7/lava_android_test/utils.py @@ -0,0 +1,202 @@ +# Copyright (c) 2010-2012 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +import re +import os +import pexpect +import shutil +import subprocess +import sys +import time +import urllib2 +import urlparse + +_fake_files = None +_fake_paths = None +_fake_machine = None + + +class Tee(file): + """ A file-like object that optionally mimics tee functionality. + + By default, output will go to both stdout and the file specified. + Optionally, quiet=True can be used to mute the output to stdout. + """ + def __init__(self, *args, **kwargs): + try: + self.quiet = kwargs.pop('quiet') + except KeyError: + self.quiet = False + super(Tee, self).__init__(*args, **kwargs) + + def write(self, data): + super(Tee, self).write(data) + if self.quiet is False: + sys.stdout.write(data) + + +def geturl(url, path=""): + urlpath = urlparse.urlsplit(url).path + filename = os.path.basename(urlpath) + if path: + filename = os.path.join(path, filename) + fd = open(filename, "w") + try: + response = urllib2.urlopen(urllib2.quote(url, safe=":/")) + fd = open(filename, 'wb') + shutil.copyfileobj(response, fd, 0x10000) + fd.close() + response.close() + except: + raise RuntimeError("Could not retrieve %s" % url) + return filename + + +def write_file(data, path): + with open(path, "w") as fd: + fd.write(data) + + +def read_file(path): + global _fake_files + global _fake_paths + if _fake_files is not None: + if path in _fake_files: + return _fake_files[path] + if _fake_paths is not None: + if path in _fake_paths: + path = _fake_paths[path] + with open(path) as fd: + data = fd.read() + return data + + +def fake_file(path, data=None, newpath=None): + """ + Set up a fake file to be read with read_file() in testing + If data is specified, the string passed as data will be returned instead + if newpath is specified, the file attempted to be read will be replaced + by newfile + """ + global _fake_files + global _fake_paths + if data is not None: + if _fake_files is None: + _fake_files = {} + _fake_files[path] = data + if newpath is not None: + if _fake_paths is None: + _fake_paths = {} + _fake_paths[path] = newpath + + +def fake_machine(type): + """ + Set up a fake machine type for testing + """ + global _fake_machine + _fake_machine = type + + +def clear_fakes(): + global _fake_files + global _fake_paths + _fake_files = {} + _fake_paths = {} + + +def clear_fake_machine(): + global _fake_machine + _fake_machine = None + + +def run_and_log(cmd, fd, quiet=False): + """ + Run a command and log the output to fd + """ + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, shell=True) + while proc.returncode == None: + proc.poll() + data = proc.stdout.readline() + fd.write(data) + if quiet is False: + sys.stdout.write(data) + return proc.returncode + + +def get_machine_type(): + """ + Return the machine type + """ + global _fake_machine + if _fake_machine is None: + return os.uname()[-1] + return _fake_machine + + +def get_local_name(url): + url = url.strip() + url = re.sub('[\/]+$', '', url) + rest = urllib2.splittype(url)[1] + host, rest = urllib2.splithost(rest) + if rest is None or rest == '': + return host + return os.path.basename(rest) + + +def check_command_exist(command): + rc = subprocess.call(["which", command], stdout=open('/dev/null', 'w')) + return rc == 0 + + +def find_files(target_dir, ext): + file_list = [] + for rootdir, dirs, files in os.walk(target_dir): + for f in files: + if f.upper().endswith(ext.upper()): + file_list.append(os.path.join(rootdir, f)) + + file_list.sort() + return file_list + + +def delete_files(flist=[]): + for f in flist: + if os.path.exists(f): + os.unlink(f) + + +def stop_at_pattern(command=None, pattern=None, timeout=-1): + if not command: + return + + if not pattern: + response = [pexpect.EOF] + else: + response = [pattern, pexpect.EOF] + + result = True + proc = pexpect.spawn(command, logfile=sys.stdout) + try: + match_id = proc.expect(response, timeout=timeout) + if match_id == 0: + time.sleep(5) + except pexpect.TIMEOUT: + result = False + finally: + proc.sendcontrol('C') + proc.sendline('') + + return result diff --git a/doc/changes.rst b/doc/changes.rst new file mode 100644 index 0000000..5476058 --- /dev/null +++ b/doc/changes.rst @@ -0,0 +1,212 @@ +Version History +*************** + +.. _version_0_16.2: + +Version 0.16.2 +============== + +* Fix NameError in ShellTestProvider. + +Version 0.16.1 +============== + +* Add some options to 0xbench, skia, v8 benchmarks to configure number of iterations + +.. _version_0_16: + +Version 0.16 +============ +* Added ashmem test +* Added binder test + +.. _version_0_15: + +Version 0.15 +============ +* Add support for canvas test in methanol +* fix hostshell-workload test for upstream builds + +.. _version_0_14: + +Version 0.14 +============ +* added private test support for bigLITTLE workload suite + +.. _version_0_13: + +Version 0.13 +============ +* update git URL for methanol +* delete the copy media files source because this is done with the android_install_cts_medias action + +.. _version_0_12: + +Version 0.12 +============ +* add sched_tests.py +* add task_placement test +* fixes to sdcard mount and vellamo tests + +.. _version_0_11: + +Version 0.11 +============ +* methanol test fix +* add support the android black box harness + +.. _version_0_10: + +Version 0.10 +============ +* update to methanol +* add MonkeyRunner Parser + +.. _version_0_9_1: + +Version 0.9.1 +============= +* Fix bug 1037936 caused by revno 189.3.18 + +.. _version_0_9: + +Version 0.9 +=========== +* Make mmtest logs less verbose. +* Wait longer for wifi to turn off. +* add extract-attachments sub command +* big_LITTLE: add support for selecting testsuite through $(OPTIONS) +* add methanol test + +.. _version_0_8: + +Version 0.8 +=========== +* added a test wrapper to make it easier to add shell script type tests +* updated CTS to use latest Google version +* added wifi connection test +* updates to pm-qa + +.. _version_0_7: + +Version 0.7 +=========== + +* add a test to disable android wallpaper +* input method service test +* monkey runner updates +* pm-qa test support +* big-LITTLE test support + +.. _version_0_6: + +Version 0.6 +=========== + +* added new sleep test +* added a hello world example test +* increase number of repeats for skia benchmark +* update URL's for test data in some tests + +.. _version_0_5: + +Version 0.5 +=========== + +* new tests: + * cache-coherency + * iozone + * memtester +* support running monkeyrunner tests + +.. _version_0_4: + +Version 0.4 +=========== +* new wifi test +* update bluetooth test +* update test bundle format to 1.3 + +.. _version_0_3: + +Version 0.3 +=========== +* new tjbench test +* new bluetooth test +* remove dependency on linaro_json + +.. _version_0_2: + +Version 0.2 +=========== +* new gator test +* update mmtest script +* Bug #962094: error occurred when no parser specified for run-custom command +* Bug #962096: the test_id generated is longer than 64 + +.. _version_0_0.10: + +Version 0.0.10 +============== +* new CTS test +* new v8 test +* new skia test +* new glmark2 test +* add support for install option +* add support for multiple ids for delete and parse commands +* remove external tools + +.. _version_0_0.9: + +Version 0.0.9 +============= +* add unit test +* fix LP: #902161 by removing dependency on pexpect. + +.. _version_0_0.8: + +Version 0.0.8 +============= +* fix the logical of makedirs Bug LP:#891326 +* modify mmtest to use the built-in MediaFramework + +.. _version_0_0.7: + +Version 0.0.7 +============= +* add new mmtest for Multimedia Test + +.. _version_0_0.6: + +Version 0.0.6 +============= +* fix install options to go through install method rather than test loader + +.. _version_0_0.5: + +Version 0.0.5 +============= +* add support for install option of install subcommand +* change monkey to always return 0 + +.. _version_0_0.4: + +Version 0.0.4 +============= +* update for 0xbench's package name modification + +.. _version_0_0.3: + +Version 0.0.3 +============= +* add function to collect package information and screen shot after test +* add support for two more instances to be executed simultaneously +* add check for the existence of adb conmmand +* modify MANIFEST.in to make files in test_definitions be installed successfully + +.. _version_0_0.1: + +Version 0.0.1 +============= + +* Initial release diff --git a/doc/conf.py b/doc/conf.py new file mode 100644 index 0000000..3900b83 --- /dev/null +++ b/doc/conf.py @@ -0,0 +1,212 @@ +# -*- coding: utf-8 -*- +# +# Linaro JSON documentation build configuration file, created by +# sphinx-quickstart on Mon Dec 27 16:39:47 2010. +# +# This file is execfile() with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.append(os.path.abspath('..')) + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.viewcode'] + +# Configuration for sphinx.ext.todo + +todo_include_todos = True + +# Add any paths that contain templates here, relative to this directory. +templates_path = [] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'LAVA Android Test' +copyright = u'2010-2012, Linaro Limited' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +import versiontools +import lava_android_test +version = "%d.%d" % lava_android_test.__version__[0:2] +# The full version, including alpha/beta/rc tags. +release = versiontools.format_version(lava_android_test.__version__) + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of documents that shouldn't be included in the build. +#unused_docs = [] + +# List of directories, relative to source directory, that shouldn't be +# searched for source files. +exclude_trees = [] + +# The rest default role (used for this markup: `text`) to use for +# all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. Major themes that +# come with Sphinx are currently 'default' and 'sphinxdoc'. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_use_modindex = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = '' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'LAVAAndroidTestDocumentation' + + +# -- Options for LaTeX output ------------------------------------------------ + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples (source +# start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'LAVA Android Test.tex', u'LAVA Android Test Documentation', + u'Yongqin Liu', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_use_modindex = True + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/doc/index.rst b/doc/index.rst new file mode 100644 index 0000000..d4ec0e1 --- /dev/null +++ b/doc/index.rst @@ -0,0 +1,81 @@ +=============================== +LAVA Android Test Documentation +=============================== + +LAVA Android Test is a wrapper framework exposing unified API and command line +interface for running arbitrary tests and storing the results in a structured +manner. + +LAVA Android Test is a part of the LAVA stack and can be used with other LAVA +components, most notably the dispatcher (for setting up the test environment +and controlling execution of multiple tests) and the dashboard (for storing) + +.. seealso:: To learn more about LAVA see https://launchpad.net/lava + +Indices and tables +================== + +.. toctree:: + :maxdepth: 2 + + installation.rst + usage.rst + tests.rst + reference.rst + changes.rst + todo.rst + +Features +======== + +* Ability to enumerate, install, run and remove tests on a Linux-based system. +* Support for benchmarks as well as pass/fail tests. +* Support for capturing android environment information such as installed packages and + hardware information and recording that in a machine-readable manner. +* Store results in raw form (log files) as well as Linaro Dashboard Bundle + format that can be uploaded to the LAVA Dashboard for archiving and analysis. +* Extensible API for adding new tests (:class:`~lava_android_test.api.ITest`) +* Ever-growing collection of freely available and generic tests and benchmarks + +Quickstart +========== + +This example will run on Ubuntu Lucid and beyond. we should better to install it +in an virtual environment, so that it will not mess up with the system environment:: + + $ virtualenv ${workspace} ### create the virtual environment + $ source ${workspace}/bin/activate ### enter the virtual environment + $ pip install --upgrade lava-android-test ### install the latest package to the the virtual environment + $ lava-android-test install monkey ### install the test named monkey + $ lava-android-test run monkey ### run the monkey test + $ virtualenv ${workspace} ### exit the virtual environment + +.. seealso:: For a more thorough description see :ref:`usage` +.. seealso:: For detailed installation istructions see :ref:`installation` + +Latest documentation +==================== + +This documentation may be out of date, see +http://validation.linaro.org/static/docs/lava-android-test/ or the +Documentation link on any LAVA instance to learn more. + + +Source code, bugs and patches +============================= + +The project is maintained on Launchpad at http://launchpad.net/lava-android-test/. + +You can get the source code with bazaar using ``bzr branch lp:lava-android-test``. +Patches can be submitted using Launchpad merge proposals (for introduction to +this and topic see https://help.launchpad.net/Code/Review). + +Please report all bugs at https://bugs.launchpad.net/lava-android-test/+filebug. + +Most of the team is usually available in ``#linaro`` on ``irc.freenode.net``. +Feel free to drop by to chat and ask questions. + + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/doc/installation.rst b/doc/installation.rst new file mode 100644 index 0000000..3b30cb4 --- /dev/null +++ b/doc/installation.rst @@ -0,0 +1,58 @@ + +.. _installation: + +Installation +============ + +Prerequisites +^^^^^^^^^^^^^ + +The following debian packages are needed to use LAVA Test: + +* python-setuptools +* python-apt +* usbutils +* python-testrepository - for running unit tests +* python-sphinx - for building documentation + +Installation Options +^^^^^^^^^^^^^^^^^^^^ + +There are several installation options available: + +Using Python Package Index +-------------------------- + +This package is being actively maintained and published in the `Python Package +Index <http://http://pypi.python.org>`_. You can install it if you have `pip +<http://pip.openplans.org/>`_ tool using just one line:: + + pip install lava-android-test + + +Using source tarball +-------------------- + +To install from source you must first obtain a source tarball from either pypi +or from `Launchpad <http://launchpad.net/>`_. To install the package unpack the +tarball and run:: + + python setup.py install + +You can pass ``--user`` if you prefer to do a local (non system-wide) +installation. Note that executable programs are placed in ``~/.local/bin/`` and +this directory is not on ``PATH`` by default. + +Installing for development +-------------------------- + +An easy way to set things up for local development is to create a python +virtualenv. You can create the virtualenv anyway in your filesystem. In +the example below, its simply put under the bzr repo where development +is being done from:: + + bzr branch lp:lava-android-test + cd lava-android-test + virtualenv .venv ; . ./venv/bin/activate + pip install keyring + ./setup.py develop diff --git a/doc/reference.rst b/doc/reference.rst new file mode 100644 index 0000000..aa0cbcb --- /dev/null +++ b/doc/reference.rst @@ -0,0 +1,76 @@ +.. _reference: + +========= +Reference +========= + +.. _command_reference: + +Command Reference +================= + +.. automodule:: lava_android_test.commands + :members: + +.. todo:: + + * Describe basic commands + * Describe arguments and options to each command in detail + +Pathnames and files +=================== + +LAVA Android Test uses the following files: + +* ``/tmp/lava-android-test/`` -- temporary directory to put temporary files of each lava-android-test instance. + +.. _code_reference: + +Code reference +============== + +.. todo:: + + * Describe general code layout + * Describe key API integration points (on a separate page if needed for clarity) + * Provide an example test and walk the reader through the meaning of each part + +Abstract Interfaces +^^^^^^^^^^^^^^^^^^^ + +.. automodule:: lava_android_test.api + :members: + +Test definitions and test providers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. automodule:: lava_android_test.test_definitions + :members: + +Test components (installers, runners and parsers) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. automodule:: lava_android_test.testdef + :members: + +Core Modules +^^^^^^^^^^^^ + +.. automodule:: lava_android_test.config + :members: + +Environment Scanners +^^^^^^^^^^^^^^^^^^^^ + +.. automodule:: lava_android_test.hwprofile + :members: + +.. automodule:: lava_android_test.swprofile + :members: + +Utilities +^^^^^^^^^ + +.. automodule:: lava_android_test.utils + :members: + diff --git a/doc/tests.rst b/doc/tests.rst new file mode 100644 index 0000000..71a11dd --- /dev/null +++ b/doc/tests.rst @@ -0,0 +1,275 @@ +.. _test: + +=============== +Supported Tests +=============== + +The following tests are currently supported in LAVA Android Test: + + * `0xbench`_ + * `bctest`_ + * `big_LITTLE`_ + * `blackbox`_ + * `bluetooth`_ + * `busybox`_ + * `cache_coherency`_ + * `commands`_ + * `command-example`_ + * `command-linaro_android_kernel_test`_ + * `command-tjunittest`_ + * `cts`_ + * `gatortest`_ + * `glmark2`_ + * `helloworld`_ + * `hostshells`_ + * `hostshell-connect-lab-wifi`_ + * `hostshell-example`_ + * `hostshell-sdcard-mounted`_ + * `hostshell-workload`_ + * `ime`_ + * `install_prep_4bench`_ + * `instruments`_ + * `instrument-example`_ + * `iozone`_ + * `memtester`_ + * `methanol`_ + * `mmtest`_ + * `monkey`_ + * `monkey_long_run`_ + * `pm_qa`_ + * `sched_tests`_ + * `shells`_ + * `shell-binder`_ + * `shell-dalvik-vm-unit-tests`_ + * `shell-example`_ + * `skia`_ + * `sleep`_ + * `task_placement`_ + * `tjbench`_ + * `usbhardware`_ + * `v8`_ + * `monkeyrunner(system)`_ + * `monkeyrunner(third-party-benchmarks)`_ + +0xbench ++++++++ +.. automodule:: lava_android_test.test_definitions.0xbench + +bctest +++++++ +.. automodule:: lava_android_test.test_definitions.bctest + +big_LITTLE +++++++++++ +.. automodule:: lava_android_test.test_definitions.big_LITTLE + +blackbox +++++++++ +.. automodule:: lava_android_test.test_definitions.blackbox + +bluetooth ++++++++++ +.. automodule:: lava_android_test.test_definitions.bluetooth + +busybox ++++++++ +.. automodule:: lava_android_test.test_definitions.busybox + +cache_coherency ++++++++++++++++ +.. automodule:: lava_android_test.test_definitions.cache_coherency + +commands +++++++++ +.. automodule:: lava_android_test.test_definitions.commands + +command-example ++++++++++++++++ +.. automodule:: lava_android_test.test_definitions.commands.example + +command-linaro_android_kernel_test +++++++++++++++++++++++++++++++++++ +.. automodule:: lava_android_test.test_definitions.commands.linaro_android_kernel_test + +command-tjunittest +++++++++++++++++++ +.. automodule:: lava_android_test.test_definitions.commands.tjunittest + +cts ++++ +.. automodule:: lava_android_test.test_definitions.cts + +gatortest ++++++++++ +.. automodule:: lava_android_test.test_definitions.gatortest + +glmark2 ++++++++ +.. automodule:: lava_android_test.test_definitions.glmark2 + +helloworld +++++++++++ +.. automodule:: lava_android_test.test_definitions.helloworld + +hostshells +++++++++++ +.. automodule:: lava_android_test.test_definitions.hostshells + +hostshell-connect-lab-wifi +++++++++++++++++++++++++++ +Try to connect the wifi in lava-lab for other tests, also can be used to test if the wifi works + +**URL:** None + +**Default options:** None + +hostshell-example ++++++++++++++++++ +Example for how to integrate test which is a host shell script into lava-android-test + +**URL:** None + +**Default options:** None + +hostshell-sdcard-mounted +++++++++++++++++++++++++ +Check if the sdcard is mounted when the android booted up by check the output of mount command + +**URL:** None + +**Default options:** None + +hostshell-workload +++++++++++++++++++ +Test of Automatic Workload Automation for big LITTLE Systems from ARM + +**URL:** https://linaro-private.git.linaro.org/gitweb?p=workload-automation.git;a=summary + +**Default options:** None + +ime ++++ +.. automodule:: lava_android_test.test_definitions.ime + +install_prep_4bench ++++++++++++++++++++ +.. automodule:: lava_android_test.test_definitions.install_prep_4bench + +instruments ++++++++++++ +.. automodule:: lava_android_test.test_definitions.instruments + +instrument-example +++++++++++++++++++ +.. automodule:: lava_android_test.test_definitions.instruments.example + +iozone +++++++ +.. automodule:: lava_android_test.test_definitions.iozone + +memtester ++++++++++ +.. automodule:: lava_android_test.test_definitions.memtester + +methanol +++++++++ +.. automodule:: lava_android_test.test_definitions.methanol + +mmtest +++++++ +.. automodule:: lava_android_test.test_definitions.mmtest + +monkey +++++++ +.. automodule:: lava_android_test.test_definitions.monkey + +monkey_long_run ++++++++++++++++ +.. automodule:: lava_android_test.test_definitions.monkey_long_run + +pm_qa ++++++ +.. automodule:: lava_android_test.test_definitions.pm_qa + +sched_tests ++++++++++++ +.. automodule:: lava_android_test.test_definitions.sched_tests + +shells +++++++ +.. automodule:: lava_android_test.test_definitions.shells + +shell-binder +++++++++++++ +Measures the rate at which a short binder IPC operation can be +performed. The operation consists of the client sending a parcel +that contains two integers. For each parcel that the server +receives, it adds the two integers and sends the sum back to +the client. + +**URL:** http://android.git.linaro.org/gitweb?p=platform/system/extras.git;a=blob;f=tests/binder/benchmarks/binderAddInts.cpp + +**Default options:** None + +shell-dalvik-vm-unit-tests +++++++++++++++++++++++++++ +Run the unit tests for dalvik vm. + +**URL:** http://android.git.linaro.org/gitweb?p=platform/dalvik.git;a=blob;f=unit-tests/dvmHumanReadableDescriptor_test.cpp + +**Default options:** None + +shell-example ++++++++++++++ +Example for how to integrate test which is a shell script into lava-android-test + +**URL:** None + +**Default options:** None + +skia +++++ +.. automodule:: lava_android_test.test_definitions.skia + +sleep ++++++ +.. automodule:: lava_android_test.test_definitions.sleep + +task_placement +++++++++++++++ +.. automodule:: lava_android_test.test_definitions.task_placement + +tjbench ++++++++ +.. automodule:: lava_android_test.test_definitions.tjbench + +usbhardware ++++++++++++ +.. automodule:: lava_android_test.test_definitions.usbhardware + +v8 +++ +.. automodule:: lava_android_test.test_definitions.v8 + +monkeyrunner(system) +++++++++++++++++++++ +Run some system tests with the monkeyrunner scripts. +but this part should be recreated with uiautomator scripts + +**URL:** http://android.git.linaro.org/gitweb?p=test/linaro/android/system.git;a=summary + +**Default options:** None + +monkeyrunner(third-party-benchmarks) +++++++++++++++++++++++++++++++++++++ +Support for run the third party benchmark applications automatically, +and collect the test result automatically. +The supported third party benchmark applications include: +andebench/antutu/caffeinemark/geekbench/glbenchmark/linpack/nbench/quadrant/vellamo + +**URL of apks:** https://linaro-private.git.linaro.org/gitweb?p=people/yongqinliu/benchmark-apks.git;a=summary + +**URL of scripts:** http://android.git.linaro.org/gitweb?p=platform/external/thirdparty-benchmarks.git;a=summary + +**Default options:** None + diff --git a/doc/todo.rst b/doc/todo.rst new file mode 100644 index 0000000..620f67e --- /dev/null +++ b/doc/todo.rst @@ -0,0 +1,6 @@ +List of items that need work +============================ + +.. todolist:: + +Add support for out-of-tree test. diff --git a/doc/usage.rst b/doc/usage.rst new file mode 100644 index 0000000..3f199ff --- /dev/null +++ b/doc/usage.rst @@ -0,0 +1,413 @@ +.. _usage: + +===== +Usage +===== + +Workflow Overview +================= + +LAVA Android Test can be used in several different ways. Most notably those are +standalone (without the LAVA dispatcher) and managed (when LAVA Android Test is +installed and controlled by the LAVA dispatcher). + +Standalone usage +^^^^^^^^^^^^^^^^ + +In standalone mode a human operator installs LAVA Android Test on some device +(laptop or computer or a virtual machine), installs the tests that are to be +executed and then executes them manually (by manually running LAVA Android test, +the actual tests are non-interactive). + +Using LAVA to develop and run new tests ++++++++++++++++++++++++++++++++++++++++ + +This mode is useful for test development (adding new tests, developing custom +tests especially tailored for LAVA, etc.). Here the typical cycle depends on +how the tests is wrapped for usage by LAVA and what the test developer is +focusing on. + +While developing the actual test the typical set of commands might look like +this:: + + $ lava-android-test install my-custom-test + $ lava-android-test run my-custom-test + $ lava-android-test uninstall my-custom-test + +Here the developer could observe changes to the test program (that is +presumably compiled and copied somewhere by the install stage). + +Using LAVA to analyze test results +++++++++++++++++++++++++++++++++++ + +Developing the test is only half of the story. The other half is developing +LAVA Android Test integration code, most importantly the artefact parser / analyzer. +This part has to be implemented in python (unlike the test program that can be +implemented in any language and technology). Here the developer is focusing on +refining the parser to see if the outcome is as indented. Assuming that earlier +the developer ran the test at least once and wrote down the result identifier. +The set of commands one might use is:: + + $ lava-android-test parse result-id + +The result id is used to locate leftovers from running that specific test +at some previous point in time. + +By default parse will print the bundle to standard output for inspection. +It should be redirected to a page for easier verification. + +.. note:: + + While the syntax of the bundle created with `lava-android-test parse` is always + correct (or, if the parser does something really, really strange, a + detailed error is reported), the actual contents may not be what you + intended it to be. Parsers are ultimately fragile as they mostly deal with + unstructured or semi-structured free-form text that most test programs seem + to produce. The ultimate goal of a developer should be to produce + unambiguous, machine readable format. This level of integration would allow + to wrap a whole class of tests in one go (such as all xUnit-XML speaking + test frameworks). + +Usage with the dispatcher +^^^^^^^^^^^^^^^^^^^^^^^^^ + +The dispatcher is useful for automating LAVA Android Test environment setup, describing +test scenarios (the list of tests to invoke) and finally storing the results in +the LAVA dashboard. + +Typically this mode is based on the following sequence of commands: + +#. Install lava-android-test along with the required dependencies. +#. Install the test or tests. +#. Run, parse and store in one. + +Here the whole setup is non-interactive and at the end the dispatcher can copy +the output bundle for additional processing. + +Automation considerations +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. _wrapping_existing_test_or_benchmark: + +Wrapping existing test or benchmark +=================================== + +LAVA Android Test can be extended in several different ways. There is no best method, +each has some pros and cons. In general we welcome any freely redistributable, +generic tests. Those enrich the LAVA ecosystem and by providing useful +out-of-the-box features to our users. + +Technically all tests are hidden behind a set of abstract interfaces that tell +LAVA Android Test what to do in response to operator or dispatcher actions. The primary +interface is :class:`~lava_android_test.api.ITest` and the three principal +methods: :meth:`~lava_android_test.api.ITest.install`, +:meth:`~lava_android_test.api.ITest.run`, +:meth:`~lava_android_test.api.ITest.parse`. + +In practice it is usually much easier to instantiate our pluggable delegate +test (:class:`lava_android_test.testdef.Test`) and define the three delegates that +know how to install, run and parse. Again for each step we have a base class +that can be easily customized or even used directly as is. Those classes are +:class:`~lava_android_test.testdef.TestInstaller`, +:class:`~lava_android_test.testdef.TestRunner` and +:class:`~lava_android_test.testdef.TestParser`. They all implement well-defined +interfaces so if you wish to customize them you should become familiar with +the API requirements first. + +Contributing new tests to LAVA +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The most direct way to add a new test is to contribute patches to LAVA Android Test +itself. This method will simply add a new test definition to the collection of +available tests. + +This method is recommended for generic tests that rarely change and are +suitable for wide variety of hardware and software for android. + +The advantage is that those tests can be invoked out of the box and will be +maintained by the LAVA team. The disadvantage is that all changes to those +tests need to follow Linaro development work flow, get reviewed and finally +merged. Depending on your situation this may be undesired. + +Steps to integrate an Android test to LAVA +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +1. Checkout the lava-android-test + +With the following command:: + + bzr branch lp:lava-android-test + +2. About wrapper script + +If the test tools are just command that can be run on android system, +and the output is well formatted, then congratulations, you can go +directly to step 6. You don't need to wrap script again. + +3. Four types simple test + + 1. Instrumentation test, run like "adb shell am instrument ..." + + create a file like lava_android_test/test_definitions/instruments/example.py, + and put it under lava_android_test/test_definitions/instruments:: + + cmd = ("am instrument -r -w " + "com.android.emulator.connectivity.test/" + "android.test.InstrumentationTestRunner") + RUN_ADB_SHELL_STEPS = [cmd] + + + 2. Android command test, run like "adb shell test-command" + + create a file like lava_android_test/test_definitions/commands/example.py + and put it under lava_android_test/test_definitions/commands:: + + RUN_ADB_SHELL_STEPS = ['tjunittest'] + PATTERN = ("^\s*(?P<test_case_id>.+)\s+\.\.\.\s+(?P<result>\w+)\." + "\s+(?P<measurement>[\d\.]+)\s+(?P<units>\w+)\s*$") + + + 3. Android shell test, need to write a shell and run like "adb shell script.sh" + + create a file like lava_android_test/test_definitions/shells/example.py + and put it under lava_android_test/test_definitions/shells:: + + #!/system/bin/sh + + echo "test_case_fail=fail" + echo "test_case_pass=pass" + + 4. Host shell test, need to write a shell and run like "bash script.sh" + + create a file like lava_android_test/test_definitions/hostshells/example.sh + and put it under lava_android_test/test_definitions/shells:: + + #!/bin/bash + echo "hostshells-example-fail=fail" + echo "hostshells-example-pass=pass" + + this shell script will be passed "-s $(SERIAL) $(OPTIONS)" as arguments + +4. About test scripts/tools + +Put the actual test tools in some place, normally they are +in a sub directory of test_definitions, like the busybox test, i.e. +the actual test tool is busybox_test.sh, and it is put in the +lava_android_test/test_definitions/busybox directory. + +.. note:: + In this case, we should modify the MANIFEST.in file in the root source directory. + Otherwise the contents in that directory won’t be installed into the system python library. + Like: + + include lava_android_test/test_definitions/busybox/ + +5. Add a test wrapper script for your test into the test_definitions directory. + +The content of the wrapper script should be something like below, +Normally, you just need to redefine the red and bold part in the above:: + + import os + import lava_android_test.testdef + + test_name = 'test_sample' + + #linux commands that will be run on the host before INSTALL_STEPS_ADB_PRE" + INSTALL_STEPS_HOST_PRE = [] + #adb commands that will be run before install apk file into android + INSTALL_STEPS_ADB_PRE = [] + #APK file path list that will be intalled into android + APKS= [] + #adb commands that will be run before install apk file into android + INSTALL_STEPS_ADB_POST = [] + #linux commands that will be run on the host after INSTALL_STEPS_ADB_POST + INSTALL_STEPS_HOST_POST = [] + + #linux commands that will be run on the host before RUN_STEPS_ADB_PRE + RUN_STEPS_HOST_PRE = [] + #adb commands that will be run before install apk file into android + RUN_STEPS_ADB_PRE = [] + #commands that will be run on android + ADB_SHELL_STEPS = [] + #adb commands that will be run before install apk file into android + RUN_STEPS_ADB_POST = [] + #linux commands that will be run on the host after RUN_STEPS_ADB_POST + RUN_STEPS_HOST_POST = [] + + #pattern to parse the command output to generate the test result. + PATTERN = "^\s*(?P<test_case_id>\w+)=(?P<result>\w+)\s*$" + + inst = lava_android_test.testdef.AndroidTestInstaller(steps_host_pre=INSTALL_STEPS_HOST_PRE, + steps_adb_pre=INSTALL_STEPS_ADB_PRE, + apks=APKS, + steps_adb_post=INSTALL_STEPS_ADB_POST, + steps_host_post=INSTALL_STEPS_HOST_POST) + run = lava_android_test.testdef.AndroidTestRunner(steps_host_pre=RUN_STEPS_HOST_PRE, + steps_adb_pre=RUN_STEPS_ADB_PRE, + adbshell_steps=ADB_SHELL_STEPS, + steps_adb_post=RUN_STEPS_ADB_POST, + steps_host_post=RUN_STEPS_HOST_POST) + parser = lava_android_test.testdef.AndroidTestParser(PATTERN) + testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) + + +And in the command part, you can use "$(SERIAL)" to represent the device serial number, like:: + + RUN_STEPS_HOST_POST = [ 'python %s/android-0xbenchmark/android_0xbenchmark_wait.py $(SERIAL)' % curdir] + +and "$(OPTIONS)" to represent the option string passed from command line, like:: + + INSTALL_STEPS_HOST_PRE = [ 'echo $(OPTION)'] + RUN_STEPS_HOST_PRE = [ 'echo $(OPTION)'] + +then you can run lava-android-test install -o "install options string" or lava-android-test run -O "run options string" + +.. note:: + + Because lava-android-test will be run on lava-lab, and there will be multiple devices connected simultaneously, + So we should consider to pass the device serial number for each test tools. + If the test tools is defined for steps_adb_pre/adbshell_steps/steps_adb_post, + then there is no need to pass the device serial number, lava-android-test will do this for you. + + +6. you can: + +Here is a blog about install/test lava-android-test that you can reference: + http://www.linaro.org/linaro-blog/2011/12/01/local-lava-testing-of-android-ics + +* use "lava-android-test list-tests" to check if the test wrapper created can be recognized, +* use "lava-android-test install ${test_name}" to install the test, +* use "lava-android-test run ${test_name}" to execute the test, +* use "lava-android-test show ${result_id}" to show the output the test executed, +* use "lava-android-test parse ${result_id}" to to generate the result bundle for the test executed. + +7. Integrate Into Lava + +When you have done the above steps and verified your test that works well, +then you can integrate it in LAVA with the android-build. + +Here is a description about that: + https://wiki.linaro.org/Platform/Android/AndroidBuild-LavaIntegration + +8. Add Document + +At last don’t forget to add an entry and some document in the doc/tests.rst file. Like:: + + busybox + +++++++ + .. automodule:: lava_android_test.test_definitions.busybox + +Then the information will be listed in the below url: + http://lava-android-test.readthedocs.org/en/latest/tests.html + +9. Commit Modification + +In lava-android-test directory, run the following commands:: + + bzr launchpad-login ${your-lauchpad-id} + bzr commit -m '${commit msg} + bzr push lp:~${your-launchpad-id}/lava-android-test/${branch-name} + +Then you can see your branch in the following page: + https://code.launchpad.net/lava-android-test + +Click your branch, and click the “Propose for merging” link in your branch page to submit a merge proposal. +In the proposal page, please set Reviewer: to linaro-validation. + +Adding Results Parsing +++++++++++++++++++++++ + +Because every test has its own way of displaying results, there is no common, +enforced way of interpreting the results from any given test. That means that +every test definition also has to define a parser so that LAVA Android Test can +understand how to pick out the most useful bits of information from the output. +What we've tried to do, is make this as simple as possible for the most common +cases, while providing the tools necessary to handle more complex output. + +To start off, there are some fields you are always going to want to either pull +from the results, or define. For all tests: + +* test_case_id - This is just a field that uniquely identifies the test. + This can contain letters, numbers, underscores, dashes, or periods. + If you use any illegal characters, they will automatically be dropped + by the TestParser base class before parsing the results. Spaces will be + automatically converted to underscores. If you wish to change this behaviour, + make sure that you either handle fixing the test_case_id in your parser, + or override the TestParser.fixids() method. +* result - result is simply the result of the test. This applies to both qualitative + as well as quantitative tests, and the meaning is specific to the test itself. + The valid values for result are: "pass", "fail", "skip", or "unknown". + +For performance tests, you will also want to have the following two fields: + +* measurement - the "score" or resulting measurement from the benchmark. +* units - a string defining the units represented by the measurement in some way + that will be meaningful to someone looking at the results later. + +For results parsing, it's probably easier to look at some examples. Several +tests have already been defined in the lava-android-test test_definitions directory +that serve as useful examples. + +Defining a simple test +++++++++++++++++++++++ + +**Example 1** The tjunittest example might look something like this:: + + import os + import lava_android_test.testdef + + test_name = 'tjunittest' + + #linux commands that will be run on the host before INSTALL_STEPS_ADB_PRE" + INSTALL_STEPS_HOST_PRE = [] + #adb commands that will be run before install apk file into android + INSTALL_STEPS_ADB_PRE = [] + #APK file path list that will be intalled into android + APKS= [] + #adb commands that will be run before install apk file into android + INSTALL_STEPS_ADB_POST = [] + #linux commands that will be run on the host after INSTALL_STEPS_ADB_POST + INSTALL_STEPS_HOST_POST = [] + + #linux commands that will be run on the host before RUN_STEPS_ADB_PRE + RUN_STEPS_HOST_PRE = [] + #adb commands that will be run before install apk file into android + RUN_STEPS_ADB_PRE = [] + #commands that will be run on android + ADB_SHELL_STEPS = ['tjunittest'] + #adb commands that will be run before install apk file into android + RUN_STEPS_ADB_POST = [] + #linux commands that will be run on the host after RUN_STEPS_ADB_POST + RUN_STEPS_HOST_POST = [] + + #pattern to parse the command output to generate the test result. + PATTERN = "^\s*(?P<test_case_id>.+)\s+\.\.\.\s+(?P<result>\w+)\.\s+(?P<measurement>[\d\.]+)\s+(?P<units>\w+)\s*$" + + inst = lava_android_test.testdef.AndroidTestInstaller(steps_host_pre=INSTALL_STEPS_HOST_PRE, + steps_adb_pre=INSTALL_STEPS_ADB_PRE, + apks=APKS, + steps_adb_post=INSTALL_STEPS_ADB_POST, + steps_host_post=INSTALL_STEPS_HOST_POST) + run = lava_android_test.testdef.AndroidTestRunner(steps_host_pre=RUN_STEPS_HOST_PRE, + steps_adb_pre=RUN_STEPS_ADB_PRE, + adbshell_steps=ADB_SHELL_STEPS, + steps_adb_post=RUN_STEPS_ADB_POST, + steps_host_post=RUN_STEPS_HOST_POST) + parser = lava_android_test.testdef.AndroidTestParser(PATTERN) + testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) + +In this example, we just simply defined the tjunittest command in ADB_SHELL_STEPS variable, +and defined the PATTERN variable used by AndroidTestParser. + +If you were to save this under the test_definitions directory as 'tjunittest.py', +then run 'lava-android-test install tjunittest' and 'lava-android-test run tjunittest', +you would have a test result with the result id shown to you. +And you can also run 'lava-android-test parse ${result_id}' to get the test result in the json format, +which you can submit to lava. + diff --git a/lava_android_test/__init__.py b/lava_android_test/__init__.py new file mode 100644 index 0000000..7074800 --- /dev/null +++ b/lava_android_test/__init__.py @@ -0,0 +1,16 @@ +# Copyright (c) 2010, 2011 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +__version__ = (0, 16, 3, "final", 0) diff --git a/lava_android_test/adb.py b/lava_android_test/adb.py new file mode 100644 index 0000000..5bedb8c --- /dev/null +++ b/lava_android_test/adb.py @@ -0,0 +1,401 @@ +# Copyright (c) 2011 - 2012 Linaro +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import re +import subprocess +import tempfile +import threading +import time + +from Queue import Queue +from lava_android_test.config import get_config + +config = get_config() + + +class ADB(object): + ERR_CHMOD = 260 + ERR_WRAPPER = 300 + ERR_SHELL = 350 + ERR_PUSH = 400 + ERR_INSTALL = 450 + ERR_UNINSTALL = 450 + adb = 'adb' + serial = None + + target_dir = config.tempdir_android + + def __init__(self, serial=None, quiet=True): + self.cmdExecutor = CommandExecutor(quiet) + if serial is not None: + self.serial = serial + self.adb = 'adb -s %s' % serial + else: + self.serial = self.get_serial() + + def get_serial(self): + if not self.serial: + serial_ary = self.run_cmd_host('adb get-serialno')[1] + serial = serial_ary[0].strip() + if not serial or serial == 'unknown': + return '' + else: + return serial + else: + return self.serial + + def push(self, source=None, target=None): + if source is None: + return (-1, None) + + target_dir = self.target_dir + if target is None: + target = os.path.join(self.target_dir, os.path.basename(source)) + else: + target_dir = os.path.dirname(target) + + self.cmdExecutor.run('%s shell mkdir %s' % (self.adb, target_dir)) + s = self.cmdExecutor.run('%s push %s %s' % (self.adb, source, target)) + ret = s.returncode + return (ret, target) + + def pull(self, source=None, target=None): + if source is None: + return -1 + + if target is None: + cmd = '%s pull %s' % (self.adb, source) + else: + cmd = '%s pull %s %s' % (self.adb, source, target) + s = self.cmdExecutor.run(cmd) + return s.returncode + + def shell(self, command=None, stdout=None, stderr=None): + if command is None: + return 0 + tmpdir = config.tempdir_host + if not os.path.exists(tmpdir): + os.mkdir(tmpdir) + (tmpshell, tmpshell_name) = tempfile.mkstemp(suffix='.sh', + prefix='lava-android-test', + dir=tmpdir) + tmpfile_path = os.path.join(tmpdir, tmpshell_name) + os.write(tmpshell, '#/system/bin/sh\n') + os.write(tmpshell, 'base=/system\n') + os.write(tmpshell, ("export PATH=/sbin:/vendor/bin:/system/sbin:" + "/system/bin:/system/xbin\n")) + org_cmd = command + if stdout is not None: + command = '%s 1>>%s' % (command, stdout) + if stderr is not None: + command = '%s 2>>%s' % (command, stderr) + + os.write(tmpshell, command + '\n') + os.write(tmpshell, 'RET_CODE=$?\n') + if stdout is not None: + os.write(tmpshell, + 'echo ANDROID_TEST_COMMAND="%s">>%s\n' % (org_cmd, stdout)) + os.write(tmpshell, + 'echo ANDROID_TEST_RET_CODE=${RET_CODE} >>%s\n' % (stdout)) + + os.write(tmpshell, 'echo RET_CODE=${RET_CODE}\n') + os.close(tmpshell) + + (ret_code, target_path) = self.push(tmpfile_path) + os.remove(tmpfile_path) + if ret_code != 0: + return self.ERR_PUSH + + s = self.cmdExecutor.run( + '%s shell chmod 777 %s' % (self.adb, target_path)) + ret_code = s.returncode + if ret_code != 0: + return self.ERR_CHMOD + ret_code + #check the whether the output is empty + if len(s.stdout) != 0: + return self.ERR_CHMOD + + self.cmdExecutor.say('Begin to execute shell command: %s' % command) + s = self.cmdExecutor.run('%s shell %s' % (self.adb, target_path)) + ret_code = s.returncode + if ret_code != 0: + return self.ERR_SHELL + ret_code + output = s.stdout + ret_code_line = output[len(output) - 1] + self.cmdExecutor.run('%s shell rm %s' % (self.adb, target_path)) + + ret_code_pattern = "^RET_CODE=(?P<ret_code>\d+)\s*$" + pat = re.compile(ret_code_pattern) + match = pat.search(ret_code_line) + if not match: + return self.ERR_SHELL + else: + data = match.groupdict() + return int(data['ret_code'], 10) + + def exists(self, path): + ret_code = self.shell("ls %s" % path) + return ret_code == 0 + + def installapk(self, apkpath): + cmd = '%s install %s' % (self.adb, apkpath) + s = self.cmdExecutor.run(cmd) + ret_code = s.returncode + if ret_code != 0: + return self.ERR_INSTALL + ret_code + return 0 + + def uninstallapk(self, package): + cmd = '%s uninstall %s' % (self.adb, package) + s = self.cmdExecutor.run(cmd) + ret_code = s.returncode + if ret_code != 0: + return self.ERR_UNINSTALL + ret_code + return 0 + + def makedirs(self, path): + parent_path = os.path.dirname(path) + if parent_path == '/' or self.exists(parent_path): + return self.shell("mkdir %s" % path) + else: + ret = self.makedirs(parent_path) + if ret == 0: + return self.shell("mkdir %s" % path) + else: + return ret + + def rmtree(self, dirpath): + ret_code = self.shell("rm -r %s" % dirpath) + return ret_code + + def move(self, srcdir, destdir): + if srcdir is None: + return 0 + if destdir is None: + return 0 + ret_code = self.shell("mv %s %s" % (srcdir, destdir)) + return ret_code + + def copy(self, source_file, target_file): + if source_file is None: + return 0 + if target_file is None: + return 0 + if not self.exists(source_file): + return 0 + + ret_code = self.shell("dd if=%s of=%s" % (source_file, target_file)) + return ret_code + + def listdir(self, dirpath): + if self.exists(dirpath): + (ret_code, output) = self.run_cmd_host( + '%s shell ls %s ' % (self.adb, dirpath)) + return (ret_code, output) + else: + return (1, None) + + def read_file(self, filepath): + tmpfile_name = tempfile.mkstemp( + prefix='read_file_', dir=config.tempdir_host)[1] + ret_code = self.pull(filepath, tmpfile_name) + if ret_code != 0: + return None + data = None + try: + with open(tmpfile_name) as fd: + data = fd.read() + finally: + os.remove(tmpfile_name) + return data + + def get_shellcmdoutput(self, cmd=None, quiet=True): + return self.get_shellcmdoutput_with_stderr(cmd=cmd, quiet=True)[0:2] + + def run_adb_cmd(self, cmd, quiet=True): + return self.run_adb_cmd_with_stderr(cmd=cmd, quiet=quiet)[0:2] + + def run_cmd_host(self, cmd, quiet=True): + return self.run_cmd_host_with_stderr(cmd, quiet=quiet)[0:2] + + def get_shellcmdoutput_with_stderr(self, cmd=None, quiet=True): + if cmd is None: + return None + return self.run_adb_cmd_with_stderr(cmd='shell %s' % cmd, quiet=quiet) + + def run_adb_cmd_with_stderr(self, cmd, quiet=True): + if not self.isDeviceConnected(): + print ("Reconnect adb connection of device(%s) " + "for running command[%s]") % (self.get_serial(), cmd) + if not self.reconnect(): + raise Exception('Failed to connect the device(%s)' % ( + self.get_serial())) + return self.run_cmd_host_with_stderr(cmd='%s %s' % (self.adb, cmd), + quiet=quiet) + + def run_cmd_host_with_stderr(self, cmd, quiet=True): + result = self.cmdExecutor.run(cmd, quiet=quiet) + return (result.returncode, result.stdout, result.stderr) + + def run_adb_shell_for_test(self, cmd, stdoutlog=None, + stderrlog=None, quiet=False): + (ret_code, stdout, stderr) = self.get_shellcmdoutput_with_stderr( + cmd=cmd, + quiet=quiet) + if ret_code != 0: + return ret_code + self.push_stream_to_device(stdout, stdoutlog) + self.push_stream_to_device(stderr, stderrlog) + return ret_code + + def push_stream_to_device(self, stream_lines, path): + if self.serial: + android_info = 'android(%s)' % self.serial + else: + android_info = 'android' + + if not self.isDeviceConnected(): + if not self.reconnect(): + raise Exception('Failed to pull file(%s) to %s, ' + 'because the device is not connected' % ( + path, android_info)) + basename = os.path.basename(path) + tmp_path = os.path.join(config.tempdir_host, basename) + if self.exists(path): + retcode = self.pull(path, tmp_path) + if retcode != 0: + raise Exception( + 'Failed to pull file(%s) to %s' % (path, android_info)) + + with open(tmp_path, 'a') as tmp_fd: + tmp_fd.writelines(stream_lines) + tmp_fd.close() + + if self.push(tmp_path, path)[1] is None: + raise Exception( + 'Failed to pull file(%s) to %s' % (path, android_info)) + os.remove(tmp_path) + + def devices(self): + return self.run_cmd_host('%s devices' % self.adb) + + def isDeviceConnected(self): + lines = self.run_cmd_host('%s get-state' % self.adb)[1] + for line in lines: + if 'device' in line: + return True + return False + + def connect(self): + if self.serial: + self.run_cmd_host('adb connect %s' % self.serial, quiet=False) + return self.isDeviceConnected() + return False + + def disconnect(self): + if self.serial: + self.run_cmd_host('adb disconnect %s' % self.serial, quiet=False) + return not self.isDeviceConnected() + return False + + def reconnect(self): + for i in range(1, 5): + print "LAVA: try to reconnect the device(%s) %i/5 times" % ( + self.serial, i) + if self.disconnect(): + time.sleep(2) + if self.connect(): + return True + time.sleep(5) + return False + + +class CommandExecutor(object): + def __init__(self, quiet=True): + self._queue = Queue() + self.quiet = quiet + self.stdout = [] + self.stderr = [] + + def say(self, text, *args, **kwargs): + if not self.quiet: + print "LAVA:", text.format(*args, **kwargs) + + def display_subprocess_output(self, stream_name, line): + if stream_name == 'stdout': + self.say('(stdout) {0}', line.rstrip()) + elif stream_name == 'stderr': + self.say('(stderr) {0}', line.rstrip()) + + def _drain_queue(self): + while True: + args = self._queue.get() + if args is None: + break + self.display_subprocess_output(*args) + + def _read_stream(self, stream, stream_name): + if stream is None: + return + for line in iter(stream.readline, ''): + output_line = (stream_name, line) + self._queue.put(output_line) + if stream_name == 'stdout': + self.stdout.append(line) + elif stream_name == 'stderr': + self.stderr.append(line) + + def run(self, cmd, quiet=True): + self.quiet = quiet + self.stdout = [] + self.stderr = [] + self.say("Begin to execute command: %s" % + cmd.replace('{', '{{').replace('}', '}}')) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + shell=True) + + stdout_reader = threading.Thread( + target=self._read_stream, args=(proc.stdout, "stdout")) + stderr_reader = threading.Thread( + target=self._read_stream, args=(proc.stderr, "stderr")) + ui_printer = threading.Thread( + target=self._drain_queue) + + ui_printer.start() + stdout_reader.start() + stderr_reader.start() + try: + proc.wait() + except KeyboardInterrupt: + proc.kill() + finally: + stdout_reader.join() + stderr_reader.join() + self._queue.put(None) + ui_printer.join() + return CommandResult(proc.returncode, self.stdout, self.stderr) + + +class CommandResult(object): + def __init__(self, returncode, stdout=[], stderr=[]): + self.returncode = returncode + self.stdout = stdout + self.stderr = stderr diff --git a/lava_android_test/api.py b/lava_android_test/api.py new file mode 100644 index 0000000..624422e --- /dev/null +++ b/lava_android_test/api.py @@ -0,0 +1,44 @@ +""" +Public API for extending Abrek +""" +from abc import abstractmethod + + +class ITest(object): + """ + Abrek test. + + Something that can be installed and invoked by abre. + """ + + @abstractmethod + def install(self): + """ + Install the test suite. + + This creates an install directory under the user's XDG_DATA_HOME + directory to mark that the test is installed. The installer's + install() method is then called from this directory to complete any + test specific install that may be needed. + """ + + @abstractmethod + def uninstall(self): + """ + Uninstall the test suite. + + Uninstalling just recursively removes the test specific directory under + the user's XDG_DATA_HOME directory. This will both mark the test as + removed, and clean up any files that were downloaded or installed under + that directory. Dependencies are intentionally not removed by this. + """ + + @abstractmethod + def run(self, quiet=False): + # TODO: Document me + pass + + @abstractmethod + def parse(self, resultname): + # TODO: Document me + pass diff --git a/lava_android_test/commands.py b/lava_android_test/commands.py new file mode 100644 index 0000000..eb46c78 --- /dev/null +++ b/lava_android_test/commands.py @@ -0,0 +1,935 @@ +# Copyright (c) 2011, 2012 Linaro +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +import base64 +import os +import re +import urlparse +import versiontools +import zipfile + +from tempfile import mkdtemp +from uuid import uuid4 + +from lava_tool.interface import Command as LAVACommand +from lava_tool.interface import LavaCommandError +from linaro_dashboard_bundle.io import DocumentIO + +from lava_android_test.adb import ADB +from lava_android_test.config import get_config +from lava_android_test.provider import TestProvider +from lava_android_test.repository import GitRepository +from lava_android_test.testdef import AndroidTest +from lava_android_test.testdef import AndroidTestRunner, \ + AndroidTestInstaller, \ + AndroidTestParser +from lava_android_test import utils + + +class Command(LAVACommand): + + def __init__(self, parser, args): + super(Command, self).__init__(parser, args) + self.config = get_config() +# self._test_loader = TestLoader(self._config) + + @classmethod + def register_arguments(cls, parser): + parser.add_argument( + "-q", "--quiet", + action="store_true", + default=False, + help="Be less verbose about undertaken actions") + parser.add_argument( + "-Q", "--quiet-subcommands", + action="store_true", + default=False, + help="Hide the output of all sub-commands (including tests)") + + def say(self, text, *args, **kwargs): + print "LAVA:", text.format(*args, **kwargs) + + def say_begin(self, text, *args, **kwargs): + print "LAVA: --Start Operation: ", text.format(*args, **kwargs) + + def say_end(self, text, *args, **kwargs): + print "LAVA: --End Operation: ", text.format(*args, **kwargs), + + def display_subprocess_output(self, stream_name, line): + if self.args.quiet_subcommands: + return + if stream_name == 'stdout': + self.say('(stdout) {0}', line.rstrip()) + elif stream_name == 'stderr': + self.say('(stderr) {0}', line.rstrip()) + + +class extract_attachments(Command): + """ + Extract the attachment files from the result bundle file + generated by the -o option of run command + or from the output of parse command + """ + @classmethod + def register_arguments(self, parser): + super(extract_attachments, self).register_arguments(parser) + parser.add_argument("result_file", + help="The result bundle json file") + group = parser.add_argument_group("specify the output directory") + group.add_argument("-d", "--directory", + default=None, + metavar="directory", + help=("specify the directory where all the " + "attachment files will be put")) + + def invoke(self): + + if not os.path.exists(self.args.result_file): + raise LavaCommandError("The specified result file(%s) " + "does not exist." % self.args.result_file) + msg = "extract attachment file from result bundle file(%s)" % ( + self.args.result_file) + self.say_begin(msg) + badchars = "[^a-zA-Z0-9\._-]" + with open(self.args.result_file) as stream: + jobdata = stream.read() + result_data = DocumentIO.loads(jobdata)[1] + test_runs = result_data.get('test_runs') + if not self.args.directory: + attachment_dir = mkdtemp(prefix='attachments-', + dir=os.path.curdir) + elif not os.path.exists(self.args.directory): + os.makedirs(self.args.directory) + attachment_dir = self.args.directory + elif not os.path.isdir(self.args.directory): + raise LavaCommandError( + "The specified path(%s) is not a directory." + % self.args.directory) + else: + attachment_dir = self.args.directory + + for test in test_runs: + test_id = test.get('test_id').replace(" ", "_") + test_id = re.sub(badchars, "_", test_id) + target_dir = mkdtemp(prefix='%s' % test_id, dir=attachment_dir) + print "The test id is: %s" % test_id + attachments = test.get('attachments', []) + for attach in attachments: + pathname = attach.get('pathname') + file_name = os.path.basename(pathname) + content_decoded = base64.standard_b64decode( + attach.get("content")) + with open(os.path.join(target_dir, file_name), 'w') as fd: + fd.write(content_decoded) + self.say("All attachment files are put under directory(%s)" % + (attachment_dir)) + self.say_end(msg) + + +class list_devices(Command): + """ + List available devices + program::lava-android-test list-devices + """ + + def invoke(self): + + self.adb = ADB() + try: + output = self.adb.devices()[1] + if output is not None: + for line in output: + print line.strip() + else: + print "No device attached" + except OSError: + print "No device attached" + + +class list_tests(Command): + """ + List available tests + program:: lava-android-test list-tests + """ + + def invoke(self): + self.say("Known tests:") + for provider in TestProvider().get_test_provider_list(): + for test in provider().list_test(): + self.say(" - {test_id}", test_id=test) + + +class version(Command): + """ + Show LAVA Test version + """ + + def invoke(self): + self.say("version details:") + for framework in self._get_frameworks(): + self.say(" - {framework}: {version}", + framework=framework.__name__, + version=versiontools.format_version( + framework.__version__, framework)) + + def _get_frameworks(self): + import lava_tool + import lava_android_test + import linaro_dashboard_bundle + return [ + lava_android_test, + lava_tool, + linaro_dashboard_bundle] + + +class AndroidCommand(Command): + + @classmethod + def register_arguments(self, parser): + super(AndroidCommand, self).register_arguments(parser) + group = parser.add_argument_group("specify device serial number") + group.add_argument("-s", "--serial", + default=None, + metavar="serial", + help=("specify the device with serial number" + "that this command will be run on")) + + def test_installed(self, test_id): + if self.adb is None: + self.adb = ADB() + test_dir = os.path.join(self.config.installdir_android, test_id) + return self.adb.exists(test_dir) + + def get_device_serial(self): + return ADB(self.args.serial).get_serial() + + def assertDeviceIsConnected(self): + if not self.adb.isDeviceConnected(): + if self.adb.serial: + raise Exception("Device '%s' is not connected" % + self.adb.serial) + else: + raise Exception("No device found") + + def invoke(self): + serial = self.get_device_serial() + if not serial: + raise LavaCommandError("No device attached") + self.serial = serial + self.adb = ADB(self.serial) + + try: + self.assertDeviceIsConnected() + except Exception as err: + raise LavaCommandError(err) + + self.invoke_sub() + + def invoke_sub(self): + raise NotImplementedError + + +class AndroidTestCommand(AndroidCommand): + @classmethod + def register_arguments(self, parser): + super(AndroidTestCommand, self).register_arguments(parser) + parser.add_argument("test_id", + help="Test identifier") + + def get_tip_msg(self, text): + if self.args.serial: + tip_msg = "%s (%s) on device(%s)" % (text, + self.args.test_id, + self.args.serial) + else: + tip_msg = "%s (%s)" % (text, self.args.test_id) + return tip_msg + + +class AndroidResultCommand(AndroidCommand): + @classmethod + def register_arguments(self, parser): + super(AndroidResultCommand, self).register_arguments(parser) + parser.add_argument("result_id", + help="Test result identifier") + + +class AndroidResultsCommand(AndroidCommand): + @classmethod + def register_arguments(self, parser): + super(AndroidResultsCommand, self).register_arguments(parser) + parser.add_argument("result_id", nargs="+", + help="One or more result identifiers") + + +class list_installed(AndroidCommand): + """ + List installed tests for specified device. + program:: lava-android-test list-tests + program:: lava-android-test list-tests -s device_serial + """ + def invoke_sub(self): + + self.say("Installed tests:") + try: + output = self.adb.listdir(self.config.installdir_android)[1] + if output is not None: + for dir_name in output: + self.say(" - {test_id}", test_id=dir_name.strip()) + else: + self.say("No tests installed") + except OSError: + self.say("No tests installed") + + +class list_results(AndroidCommand): + """ + List results of tests that has been run on the specified device. + program:: lava-android-test list-results + program:: lava-android-test list-results -s device_serial + """ + def invoke_sub(self): + self.say("Saved results:") + try: + (ret_code, output) = self.adb.listdir( + self.config.resultsdir_android) + if ret_code != 0: + raise OSError() + for dir_name in output: + self.say(" - {result_id}", result_id=dir_name.strip()) + except OSError: + self.say("No results found") + + +class install(AndroidTestCommand): + """ + Install test to the specified device. + program:: lava-android-test install test-id + program:: lava-android-test install test-id -s device_serial + """ + + @classmethod + def register_arguments(cls, parser): + super(cls, install).register_arguments(parser) + parser.add_argument('-o', '--install-option') + + def invoke_sub(self): + tip_msg = self.get_tip_msg("Install test") + self.say_begin(tip_msg) + + if self.test_installed(self.args.test_id): + raise LavaCommandError("The test (%s) has already installed." % + self.args.test_id) + test = TestProvider().load_test(self.args.test_id, self.args.serial) + try: + test.install(self.args.install_option) + except Exception as strerror: + raise LavaCommandError("Test installation error: %s" % strerror) + + self.say_end(tip_msg) + + +class uninstall(AndroidTestCommand): + """ + Unistall test of the specified device. + program:: lava-android-test uninstall test-id + program:: lava-android-test uninstall test-id -s device_serial + """ + def invoke_sub(self): + tip_msg = self.get_tip_msg("Uninstall test") + self.say_begin(tip_msg) + + test = TestProvider().load_test(self.args.test_id, self.args.serial) + try: + test.uninstall() + except Exception as strerror: + raise LavaCommandError("Test uninstall error: %s" % strerror) + self.say_end(tip_msg) + + +class run(AndroidTestCommand): + """ + Run a previously installed test program on the specified device + program:: lava-android-test run test-id + program:: lava-android-test run test-id -s device_serial + program:: lava-android-test run test-id -s device_serial -o outputfile + """ + + @classmethod + def register_arguments(cls, parser): + super(run, cls).register_arguments(parser) + parser.add_argument('-O', '--run-option', + help=("Specified in the job file for using in " + "the real test action, so that we can customize" + " some test when need")) + group = parser.add_argument_group("specify the bundle output file") + group.add_argument("-o", "--output", + default=None, + metavar="FILE", + help=("After running the test parse the result" + " artefacts, fuse them with the initial" + " bundle and finally save the complete bundle" + " to the specified FILE.")) + + def invoke_sub(self): + tip_msg = self.get_tip_msg("Run test") + self.say_begin(tip_msg) + + if not self.test_installed(self.args.test_id): + raise LavaCommandError( + "The test (%s) has not been installed yet." % + self.args.test_id) + test = TestProvider().load_test(self.args.test_id, self.args.serial) + + if not self.test_installed(test.testname): + raise LavaCommandError( + "The test (%s) has not been installed yet." + % self.args.test_id) + + try: + result_id = test.run(quiet=self.args.quiet, + run_options=self.args.run_option) + if self.args.output: + output_dir = os.path.dirname(self.args.output) + if output_dir and (not os.path.exists(output_dir)): + os.makedirs(output_dir) + bundle = generate_bundle(self.args.serial, result_id) + with open(self.args.output, "wt") as stream: + DocumentIO.dump(stream, bundle) + + except Exception as strerror: + raise LavaCommandError("Test execution error: %s" % strerror) + + self.say_end(tip_msg) + + +class run_custom(AndroidCommand): + """ + Run the command(s) that specified by the -c option in the command line + program:: lava-android-test run-custom -c 'cm1' -c 'cmd2' -p 'parse-regex1' + program:: lava-android-test run test-id -s device_serial + program:: lava-android-test run test-id -s device_serial -o outputfile + """ + + @classmethod + def register_arguments(cls, parser): + super(run_custom, cls).register_arguments(parser) + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('-c', '--android-command', action='append', + help=("Specified in the job file for using" + " in the real test action, so that " + "we can customize some test when need")) + group.add_argument('-f', '--command-file', + help=("Specified the command file that will be " + "pushed into android and run.")) + parser.add_argument('-p', '--parse-regex', + help=("Specified the regular expression used" + " for analyzing command output")) + group = parser.add_argument_group("specify the bundle output file") + group.add_argument("-o", "--output", + default=None, + metavar="FILE", + help=("After running the test parse the result" + " artefacts, fuse them with the initial" + " bundle and finally save the complete bundle" + " to the specified FILE.")) + + def invoke_sub(self): + + test_name = 'custom' + ADB_SHELL_STEPS = [] + STEPS_HOST_PRE = [] + STEPS_ADB_PRE = [] + file_name = None + if self.args.android_command: + ADB_SHELL_STEPS = self.args.android_command + cmds_str = ','.join(ADB_SHELL_STEPS) + if len(cmds_str) > 40: + cmds_str = '%s...' % (cmds_str[:40]) + test_name_suffix = 'command=[%s]' % (cmds_str) + elif self.args.command_file: + file_url = self.args.command_file + urlpath = urlparse.urlsplit(file_url).path + file_name = os.path.basename(urlpath) + target_path = os.path.join(self.config.installdir_android, + test_name, file_name) + STEPS_HOST_PRE = ["wget %s -O %s" % (file_url, file_name)] + STEPS_ADB_PRE = ["push %s %s" % (file_name, target_path)] + ADB_SHELL_STEPS = ["chmod 777 %s" % target_path, + target_path] + file_name_str = file_name + if len(file_name_str) > 40: + file_name_str = '%s...' % (cmds_str[:40]) + test_name_suffix = 'command_file=%s' % (file_name_str) + + PATTERN = None + if self.args.parse_regex: + PATTERN = self.args.parse_regex + + tip_msg = '' + if self.args.serial: + tip_msg = ("Run following custom test(s) on device(%s):" + "\n\tcommands=%s" + "\n\tcommand-file=%s\n") % ( + self.args.serial, + '\n\t\t'.join(ADB_SHELL_STEPS), + file_name) + else: + tip_msg = ("Run following custom test(s):" + "\n\t\tcommands=%s" + "\n\tcommand-file=%s\n") % ( + '\n\t\t'.join(ADB_SHELL_STEPS), + file_name) + + self.say_begin(tip_msg) + + inst = AndroidTestInstaller() + + run = AndroidTestRunner(steps_host_pre=STEPS_HOST_PRE, + steps_adb_pre=STEPS_ADB_PRE, + adbshell_steps=ADB_SHELL_STEPS) + parser = AndroidTestParser(pattern=PATTERN) + test = AndroidTest(testname=test_name, + installer=inst, runner=run, parser=parser) + test.parser.results = {'test_results': []} + test.setadb(self.adb) + + if not self.test_installed(test.testname): + test.install() + + try: + result_id = test.run(quiet=self.args.quiet) + if self.args.output: + output_dir = os.path.dirname(self.args.output) + if output_dir and (not os.path.exists(output_dir)): + os.makedirs(output_dir) + bundle = generate_bundle(self.args.serial, + result_id, test=test, + test_id='%s(%s)' % (test_name, test_name_suffix)) + with open(self.args.output, "wt") as stream: + DocumentIO.dump(stream, bundle) + + except Exception as strerror: + raise LavaCommandError("Test execution error: %s" % strerror) + self.say_end(tip_msg) + + +class run_monkeyrunner(AndroidCommand): + """ + Run the monkeyrunner scripts that stored in the specified git repository + program:: lava-android-test run-monkeyrunner -g giturl -r resultfilelist + """ + + @classmethod + def register_arguments(cls, parser): + super(run_monkeyrunner, cls).register_arguments(parser) + parser.add_argument("url", + help="The repository url of the test scripts") + parser.add_argument('-t', '--repo-type', + default='git', + help=("Specify the type of the repository")) + group = parser.add_argument_group("specify the bundle output file") + group.add_argument("-o", "--output", + default=None, + metavar="FILE", + help=("After running the test parse the result" + " artefacts, fuse them with the initial" + " bundle and finally save the complete bundle" + " to the specified FILE.")) + + def invoke_sub(self): + + if not utils.check_command_exist('monkeyrunner'): + raise LavaCommandError('The command monkeyrunner can not be found') + + if self.args.repo_type == 'git': + target_dir = mkdtemp(prefix='git_repo', + dir=self.config.tempdir_host) + os.chmod(target_dir, 0755) + GitRepository(self.args.url).checkout(target_dir) + else: + raise LavaCommandError("The repository type(%s) is not supported" + % self.args.repo_type) + + script_list = utils.find_files(target_dir, '.py') + + test_id = self.args.url + if len(test_id) > 40: + test_id = '%s...' % (test_id[:40]) + test_id = 'monkeyrunner_%s' % test_id + + tip_msg = ("Run monkeyrunner scripts in following url on device(%s):" + "\n\turl=%s") % ( + self.serial, + self.args.url) + + self.say_begin(tip_msg) + bundles = [] + for script in script_list: + if "monkeycommon.py" == os.path.basename(script): + continue + sub_bundle = {} + from datetime import datetime + starttime = datetime.utcnow() + test_case_id = script.replace('%s/' % target_dir, '') + if len(test_case_id) > 50: + test_case_id = '%s...' % (test_case_id[:50]) + try: + sub_bundle = self.run_monkeyrunner_test(script, self.serial, + test_case_id) + test_result = {"test_case_id": test_case_id, + "result": 'pass'} + if sub_bundle: + sub_bundle['test_runs'][0]['test_results'].append( + test_result) + except Exception as strerror: + self.say('Failed to run script(%s) with error:\n%s' % ( + script, + strerror)) + + test_result = {"test_case_id": test_case_id, + "result": 'fail'} + TIMEFORMAT = '%Y-%m-%dT%H:%M:%SZ' + sub_bundle['test_runs'] = [{'test_results': [test_result], + 'test_id': 'monkeyrunner(%s)' % test_case_id, + 'time_check_performed': False, + 'analyzer_assigned_uuid': str(uuid4()), + 'analyzer_assigned_date': starttime.strftime(TIMEFORMAT)}] + if sub_bundle: + bundles.append(sub_bundle) + + if self.args.output: + output_dir = os.path.dirname(self.args.output) + if output_dir and (not os.path.exists(output_dir)): + os.makedirs(output_dir) + with open(self.args.output, "wt") as stream: + DocumentIO.dump(stream, merge_bundles(bundles)) + + self.say_end(tip_msg) + + def run_monkeyrunner_test(self, script, serial, test_case_id=None): + + inst = AndroidTestInstaller() + run = AndroidTestRunner(steps_host_pre=[ + 'monkeyrunner %s %s' % (script, serial)]) + parser = MonkeyrunnerTestParser() + parser.monkeyrunner_result = os.path.join(os.path.dirname(script), + 'results.txt') + test = AndroidTest(testname='monkeyrunner', + installer=inst, runner=run, parser=parser) + test.parser.results = {'test_results': []} + test.setadb(self.adb) + + ##By calling the install function, we will create the directory + ##on the target, and the the output file and error file + ##will be pushed there + if not self.test_installed(test.testname): + test.install() + + ##The png files here are generated to the host by the monkeyrunner + ##monkeyrunner is run on host, not on the target + bundle = {} + org_png_file_list = utils.find_files(self.config.tempdir_host, + '.%s' % 'png') + result_id = test.run(quiet=self.args.quiet) + if self.args.output: + cur_all_png_list = utils.find_files(self.config.tempdir_host, + '.%s' % 'png') + new_png_list = set(cur_all_png_list).difference(org_png_file_list) + test_id = 'monkeyrunner(%s)' % (test_case_id) + bundle = generate_bundle(self.args.serial, + result_id, test=test, + test_id=test_id, + attachments=list(new_png_list)) + utils.delete_files(new_png_list) + + return bundle + + +class MonkeyrunnerTestParser(AndroidTestParser): + ''' + Before this method is called, self.monkeyrunner_result must be set + to the right value + ''' + + + def real_parse(self, result_filename=None, output_filename=None, + test_name=''): + self.res_pattern = ("^\s*(?P<test_case_id>.*?)\s*=" + "\s*(?P<result>(true|false))\s*$") + self.measurement_pattern = ("^\s*(?P<test_case_id>.*?)\s*=" + "\s*(?P<measurement>[\.\d]+)\s*$") + self.measurement_units_pattern = ("^\s*(?P<test_case_id>.*?)\s*=" + "\s*(?P<measurement>[\.\d]+)\s+(?P<units>\S+)\s*$") + + res_pat = re.compile(self.res_pattern) + measurement_pat = re.compile(self.measurement_pattern) + measurement_units_pat = re.compile(self.measurement_units_pattern) + + + if not os.path.exists(self.monkeyrunner_result): + return + with open(self.monkeyrunner_result) as stream: + for lineno, line in enumerate(stream, 1): + match = res_pat.search(line) + if not match: + match = measurement_pat.search(line) + if not match: + match = measurement_units_pat.search(line) + if not match: + continue + data = match.groupdict() + data["log_filename"] = result_filename + data["log_lineno"] = lineno + if data.get('result') is None: + data['result'] = 'pass' + + self.results['test_results'].append(data) + + +class parse(AndroidResultsCommand): + """ + Parse the results of previous test that run on the specified device + program:: lava-android-test parse test-result-id + """ + def invoke_sub(self): + bundle = generate_combined_bundle(self.args.serial, + self.args.result_id) + try: + print DocumentIO.dumps(bundle) + except IOError: + pass + + +class parse_custom(AndroidResultsCommand): + """ + Parse the results of previous test that run with run-custom command + on the specified device + program:: lava-android-test parse-custom test-result-id -P + """ + @classmethod + def register_arguments(cls, parser): + super(parse_custom, cls).register_arguments(parser) + parser.add_argument('-p', '--parse-regex', + help=("Specified the regular expression used" + " for analyzing command output")) + + def invoke_sub(self): + PATTERN = None + if self.args.parse_regex: + PATTERN = self.args.parse_regex + test_name = 'custom' + inst = AndroidTestInstaller() + run = AndroidTestRunner() + parser = AndroidTestParser(pattern=PATTERN) + test = AndroidTest(testname=test_name, installer=inst, + runner=run, parser=parser) + test.parser.results = {'test_results': []} + test.setadb(self.adb) + + bundle = generate_combined_bundle(self.args.serial, + self.args.result_id, test=test) + try: + print DocumentIO.dumps(bundle) + except IOError: + pass + + +def generate_combined_bundle(serial=None, result_ids=None, test=None, + test_id=None): + if result_ids is None: + return {} + + bundle = None + + for rid in result_ids: + b = generate_bundle(serial, rid, test, test_id) + if rid == result_ids[0]: + bundle = b + else: + bundle['test_runs'].append(b['test_runs'][0]) + + return bundle + + +def merge_bundles(bundles=[]): + config = get_config() + merged_bundles = {"format": config.bundle_format, + 'test_runs': []} + for bundle in bundles: + if bundle['test_runs']: + merged_bundles['test_runs'].append(bundle['test_runs'][0]) + return merged_bundles + + +def generate_bundle(serial=None, result_id=None, test=None, + test_id=None, attachments=[]): + if result_id is None: + return {} + config = get_config() + adb = ADB(serial) + resultdir = os.path.join(config.resultsdir_android, result_id) + if not adb.exists(resultdir): + raise Exception("The result (%s) is not existed." % result_id) + + bundle_text = adb.read_file(os.path.join(resultdir, "testdata.json")) + bundle = DocumentIO.loads(bundle_text)[1] + test_tmp = None + if test: + test_tmp = test + else: + test_tmp = TestProvider().load_test(bundle['test_runs'][0]['test_id'], + serial) + if test_id: + bundle['test_runs'][0]['test_id'] = test_id + else: + attrs = bundle['test_runs'][0].get('attributes') + if attrs: + run_options = attrs.get('run_options') + if run_options: + test_id = '%s(%s)' % (bundle['test_runs'][0]['test_id'], + run_options) + bundle['test_runs'][0]['test_id'] = test_id + + test_tmp.parse(result_id) + stdout_text = adb.read_file(os.path.join(resultdir, + os.path.basename(test_tmp.org_ouput_file))) + if stdout_text is None: + stdout_text = '' + stderr_text = adb.read_file(os.path.join(resultdir, 'stderr.log')) + if stderr_text is None: + stderr_text = '' + bundle['test_runs'][0]["test_results"] = test_tmp.parser.results[ + "test_results"] + + ## following part is used for generating the attachment for normal test + attachment_bundles = [] + for attachment in test_tmp.attachments: + data_bundle = attachment.generate_bundle(adb=adb, resultsdir=resultdir) + if data_bundle: + attachment_bundles.append(data_bundle) + + bundle['test_runs'][0]["attachments"] = attachment_bundles + + ##following used for the attachment for monkeyrunner test + for attach in attachments: + if os.path.exists(attach): + with open(attach, 'rb') as stream: + data = stream.read() + if data: + bundle['test_runs'][0]["attachments"].append({ + "pathname": os.path.basename(attach), + "mime_type": 'image/png', + "content": base64.standard_b64encode(data)}) + return bundle + +class show(AndroidResultCommand): + """ + Display the output from a previous test that run on the specified device + program:: lava-android-test show result-id + program:: lava-android-test show result-id -s device_serial + """ + def invoke_sub(self): + resultsdir = os.path.join(self.config.resultsdir_android, + self.args.result_id) + if not self.adb.exists(resultsdir): + raise LavaCommandError( + "The result (%s) is not existed." % self.args.result_id) + + stdout = os.path.join(resultsdir, "stdout.log") + if not self.adb.exists(stdout): + self.say("No result found for '%s'" % self.args.result_id) + return + try: + output = self.adb.get_shellcmdoutput('cat %s' % stdout)[1] + if output is not None: + for line in output: + self.display_subprocess_output('stdout', line) + except IOError: + pass + + stderr = os.path.join(resultsdir, "stderr.log") + if not self.adb.exists(stderr): + return + try: + output = self.adb.get_shellcmdoutput('cat %s' % stderr)[1] + if output is not None: + for line in output: + self.display_subprocess_output('stderr', line) + except IOError: + pass + + +class rename(AndroidResultCommand): + """ + Rename the result's id of a previous test that run on the specified device + program:: lava-android-test rename result-id result-id-new + program:: lava-android-test remove result-id result-id-new -s device_serial + """ + + @classmethod + def register_arguments(self, parser): + super(rename, self).register_arguments(parser) + parser.add_argument("result_id_new", + help="New test result identifier") + + def invoke_sub(self): + srcdir = os.path.join(self.config.resultsdir_android, + self.args.result_id) + destdir = os.path.join(self.config.resultsdir_android, + self.args.result_id_new) + + if not self.adb.exists(srcdir): + self.say("Result (%s) not found" % self.args.result_id) + return + if self.adb.exists(destdir): + self.say("Destination result name already exists") + self.adb.move(srcdir, destdir) + + +class remove(AndroidResultsCommand): + """ + Remove the result of a previous test that run on the specified device + program:: lava-android-test remove result-id + program:: lava-android-test remove result-id0 result-id1 + program:: lava-android-test remove result-id -s device_serial + """ + + @classmethod + def register_arguments(self, parser): + super(remove, self).register_arguments(parser) + group = parser.add_argument_group("force to remove") + group.add_argument("-f", "--force", + action="store_true", + help=("give an interactive question about remove")) + + def remove(self, rid): + resultsdir = os.path.join(self.config.resultsdir_android, rid) + if not self.adb.exists(resultsdir): + self.say("No result found for '%s'" % rid) + return + if not self.args.force: + self.say("Remove result '%s' for good? [Y/N]" % rid) + response = raw_input() + if response[0].upper() != 'Y': + return + self.adb.rmtree(resultsdir) + + def invoke_sub(self): + for rid in self.args.result_id: + self.remove(rid) diff --git a/lava_android_test/config.py b/lava_android_test/config.py new file mode 100644 index 0000000..64bf278 --- /dev/null +++ b/lava_android_test/config.py @@ -0,0 +1,51 @@ +# Copyright (c) 2010-2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os + + +class LavaAndroidTestConfig(object): + def __init__(self): + home = os.environ.get('ANDROID_TEST_HOME', '/data/local/tmp/lava-android-test/') + config = os.environ.get('ANDROID_TEST_CONFIG_HOME', + os.path.join(home, '.config')) + basedata = os.environ.get('ANDROID_TEST_DATA_HOME', + os.path.join(home, 'share')) + self.configdir = config + self.installdir_android = os.path.join(basedata, 'installed-tests') + self.resultsdir_android = os.path.join(basedata, 'results') + self.tempdir_android = os.path.join(home, 'temp') + self.tempdir_host = os.environ.get('ANDROID_TEST_TEMP_HOST', + '/tmp/lava-android-test') + self.bundle_format = "Dashboard Bundle Format 1.3" + + +_config = None + + +def get_config(): + global _config + if _config is not None: + return _config + return LavaAndroidTestConfig() + + +def set_config(config): + global _config + _config = config diff --git a/lava_android_test/hwprofile.py b/lava_android_test/hwprofile.py new file mode 100644 index 0000000..1ac7b50 --- /dev/null +++ b/lava_android_test/hwprofile.py @@ -0,0 +1,174 @@ +# Copyright (c) 2010 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import re +import sys +from lava_android_test.adb import ADB + +ARM_KEYMAP = { + 'Processor': 'cpu_model_name', + 'Features': 'cpu_features', + 'CPU implementer': 'cpu_implementer', + 'CPU architecture': 'cpu_architecture', + 'CPU variant': 'cpu_variant', + 'CPU part': 'cpu_part', + 'CPU revision': 'cpu_revision', +} + +ARM_VALMAP = { + 'CPU implementer': lambda value: int(value, 16), + 'CPU architecture': int, + 'CPU variant': lambda value: int(value, 16), + 'CPU part': lambda value: int(value, 16), + 'CPU revision': int, +} + + +def _translate_cpuinfo(keymap, valmap, key, value): + """ + Translate a key and value using keymap and valmap passed in + """ + newkey = keymap.get(key, key) + newval = valmap.get(key, lambda x: x)(value) + return newkey, newval + + +def get_cpu_devs(adb=ADB()): + """ + Return a list of CPU devices + """ + + pattern = re.compile('^(?P<key>.+?)\s*:\s*(?P<value>.*)$') + cpunum = 0 + devices = [] + cpudevs = [] + cpudevs.append({}) + + # TODO maybe there is other types + keymap, valmap = ARM_KEYMAP, ARM_VALMAP + + try: + (retcode, cpuinfo) = adb.get_shellcmdoutput("cat /proc/cpuinfo") + if retcode != 0 or cpuinfo is None: + raise IOError("Faile to get content of file(%s)" % "/proc/cpuinfo") + for line in cpuinfo: + match = pattern.match(line) + if match: + key, value = match.groups() + key = key.strip() + value = value.strip() + try: + key, value = _translate_cpuinfo(keymap, valmap, key, value) + except ValueError: + pass + if cpudevs[cpunum].get(key): + cpunum += 1 + cpudevs.append({}) + cpudevs[cpunum][key] = value + for c in range(len(cpudevs)): + device = {} + device['device_type'] = 'device.cpu' + device['description'] = 'Processor #{0}'.format(c) + device['attributes'] = cpudevs[c] + devices.append(device) + except IOError: + print >> sys.stderr, "WARNING: Could not read cpu information" + return devices + + +def get_board_devs(adb=ADB()): + """ + Return a list of board devices + """ + devices = [] + attributes = {} + device = {} + + try: + (retcode, cpuinfo) = adb.get_shellcmdoutput("cat /proc/cpuinfo") + if retcode != 0 or cpuinfo is None: + raise IOError("Faile to get content of file(%s)" % "/proc/cpuinfo") + pattern = re.compile("^Hardware\s*:\s*(?P<description>.+)$", re.M) + found = False + for line in cpuinfo: + match = pattern.search(line) + if match: + found = True + device['description'] = match.group('description').strip() + if not found: + return devices + except IOError: + print >> sys.stderr, "WARNING: Could not read board information" + return devices + if attributes: + device['attributes'] = attributes + device['device_type'] = 'device.board' + devices.append(device) + return devices + + +def get_mem_devs(adb=ADB()): + """ Return a list of memory devices + + This returns up to two items, one for physical RAM and another for swap + """ + devices = [] + + pattern = re.compile('^(?P<key>.+?)\s*:\s*(?P<value>.+) kB$', re.M) + + try: + (retcode, meminfo) = adb.get_shellcmdoutput("cat /proc/meminfo") + if retcode != 0 or meminfo is None: + raise IOError("Faile to get content of file(%s)" % "/proc/meminfo") + for line in meminfo: + match = pattern.search(line) + if not match: + continue + key, value = match.groups() + key = key.strip() + value = value.strip() + if key not in ('MemTotal', 'SwapTotal'): + continue + #Kernel reports in 2^10 units + capacity = int(value) << 10 + if capacity == 0: + continue + if key == 'MemTotal': + kind = 'RAM' + else: + kind = 'swap' + description = "{capacity}MiB of {kind}".format( + capacity=capacity >> 20, kind=kind) + device = {} + device['description'] = description + device['attributes'] = {'capacity': str(capacity), 'kind': kind} + device['device_type'] = "device.mem" + devices.append(device) + except IOError: + print >> sys.stderr, "WARNING: Could not read memory information" + return devices + + +def get_hardware_context(adb=ADB()): + """ + Return a dict with all of the hardware profile information gathered + """ + hardware_context = {} + devices = [] + devices.extend(get_cpu_devs(adb)) + devices.extend(get_board_devs(adb)) + devices.extend(get_mem_devs(adb)) + hardware_context['devices'] = devices + return hardware_context diff --git a/lava_android_test/main.py b/lava_android_test/main.py new file mode 100644 index 0000000..cb39a72 --- /dev/null +++ b/lava_android_test/main.py @@ -0,0 +1,63 @@ +# Copyright (c) 2010-2012 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +import os +import sys +import shutil +from tempfile import mkdtemp +from lava_android_test import utils +from lava_android_test.config import get_config, set_config +from lava_tool.dispatcher import LavaDispatcher, run_with_dispatcher_class + + +class LAVAAndroidTestDispatcher(LavaDispatcher): + toolname = 'lava_android_test' + description = """ + LAVA Android Test wrapper framework + """ + epilog = """ + Please report all bugs using the Launchpad bug tracker: + http://bugs.launchpad.net/lava-android-test/+filebug + """ + + +def check_adb_installed(): + return utils.check_command_exist('adb') + + +def main(): + if not check_adb_installed(): + print >> sys.stderr, "Can't find the command adb." + print >> sys.stderr, ("Please add the path of adb" + " command to PATH environment.") + sys.exit(1) + + config = get_config() + try: + if not os.path.exists(config.tempdir_host): + os.makedirs(config.tempdir_host) + #make every user can write/read this directory + os.chmod(config.tempdir_host, 0777) + config.tempdir_host = mkdtemp(dir=config.tempdir_host) + set_config(config) + os.chmod(config.tempdir_host, 0755) + run_with_dispatcher_class(LAVAAndroidTestDispatcher) + finally: + #can't remove the parent directory, because there may be other + #instance using the parent directory + shutil.rmtree(config.tempdir_host) + + +if __name__ == '__main__': + main() diff --git a/lava_android_test/provider.py b/lava_android_test/provider.py new file mode 100644 index 0000000..4ded272 --- /dev/null +++ b/lava_android_test/provider.py @@ -0,0 +1,276 @@ +# Copyright (c) 2012 Linaro + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import traceback + +from pkgutil import walk_packages + +from lava_android_test import testdef +from lava_android_test import test_definitions +from lava_android_test.test_definitions import commands, instruments +from lava_android_test.adb import ADB +from lava_android_test.config import get_config +from lava_android_test.utils import find_files + + +class UnfoundTest(Exception): + """ + Raise this for unfound test errors + """ + + +class TestProvider(object): + + test_prefix = '' + + def list_test(self): + """ + Return the list of this type + """ + raise NotImplementedError() + + def import_mod(self, importpath): + try: + mod = __import__(importpath) + except ImportError: + raise UnfoundTest('The module(%s) is not found!' % importpath) + for i in importpath.split('.')[1:]: + mod = getattr(mod, i) + return mod + + def list_mod(self, pkg_path): + test_list = [] + for importer, mod, ispkg in walk_packages(pkg_path): + test_list.append(mod) + return test_list + + def gen_testobj(self, testname=None, installer=None, runner=None, + parser=None, adb=ADB()): + + if installer is None: + installer = testdef.AndroidTestInstaller() + if runner is None: + runner = testdef.AndroidTestRunner() + if parser is None: + parser = testdef.AndroidTestParser() + + testobj = testdef.AndroidTest(testname=testname, + installer=installer, runner=runner, parser=parser) + + testobj.parser.results = {'test_results': []} + testobj.setadb(adb) + return testobj + + def get_test_provider_list(self): + providers_hash = {} +# module = imp.load_source("module", os.path.realpath(__file__)) + module = self.import_mod('lava_android_test.provider') + for name, cls in module.__dict__.iteritems(): + if name.endswith('TestProvider') \ + and name != 'TestProvider': + providers_hash[name] = cls + names = providers_hash.keys() + names.sort() + providers_list = [] + common_test_provider = None + for name in names: + if name != 'CommonTestProvider': + providers_list.append(providers_hash.get(name)) + else: + common_test_provider = providers_hash.get(name) + if common_test_provider is not None: + providers_list.append(common_test_provider) + return providers_list + + def load_test(self, test_name=None, serial=''): + providers = self.get_test_provider_list() + err_msg = '' + for provider in providers: + try: + testobj = provider().load_test(test_name=test_name, + serial=serial) + if testobj is not None: + return testobj + except: + err_msg = err_msg + traceback.format_exc() + raise UnfoundTest('The test(%s) is not found! + Exception:\n%s' % ( + test_name, err_msg)) + + +class CommonTestProvider(TestProvider): + + def list_test(self): + return self.list_mod(test_definitions.__path__) + + def load_test(self, test_name=None, serial=None): + importpath = "lava_android_test.test_definitions.%s" % test_name + mod = self.import_mod(importpath) + + base = mod.testobj + base.parser.results = {'test_results': []} + base.setadb(ADB(serial)) + return base + + +class CommandTestProvider(TestProvider): + + test_prefix = 'command' + + def list_test(self): + test_list = self.list_mod(commands.__path__) + ret_list = [] + for test_id in test_list: + ret_list.append('%s-%s' % (self.test_prefix, test_id)) + return ret_list + + def load_test(self, test_name=None, serial=None): + if not test_name.startswith('%s-' % self.test_prefix): + raise UnfoundTest('The test(%s) is not found!' % test_name) + mod_name = test_name.replace('%s-' % self.test_prefix, '', 1) + importpath = "lava_android_test.test_definitions.%ss.%s" % ( + self.test_prefix, mod_name) + mod = self.import_mod(importpath) + if not mod.RUN_ADB_SHELL_STEPS: + raise UnfoundTest(("RUN_ADB_SHELL_STEPS not" + " defined in the test(%s).") % test_name) + if not mod.PATTERN: + raise UnfoundTest(("PATTERN not" + " defined in the test(%s).") % test_name) + testobj = self.gen_testobj( + testname=test_name, + runner=testdef.AndroidTestRunner( + adbshell_steps=mod.RUN_ADB_SHELL_STEPS), + parser=testdef.AndroidTestParser(pattern=mod.PATTERN), + adb=ADB(serial)) + return testobj + + +class InstrumentTestProvider(TestProvider): + + test_prefix = 'instrument' + + def list_test(self): + test_list = self.list_mod(instruments.__path__) + ret_list = [] + for test_id in test_list: + ret_list.append('%s-%s' % (self.test_prefix, test_id)) + return ret_list + + def load_test(self, test_name=None, serial=None): + if not test_name.startswith('%s-' % self.test_prefix): + raise UnfoundTest('The test(%s) is not found!' % test_name) + mod_name = test_name.replace('%s-' % self.test_prefix, '', 1) + importpath = "lava_android_test.test_definitions.%ss.%s" % ( + self.test_prefix, mod_name) + mod = self.import_mod(importpath) + if not mod.RUN_ADB_SHELL_STEPS: + raise UnfoundTest(("RUN_ADB_SHELL_STEPS not" + " defined in the test(%s).") % test_name) + + testobj = self.gen_testobj( + testname=test_name, + runner=testdef.AndroidTestRunner( + adbshell_steps=mod.RUN_ADB_SHELL_STEPS), + parser=testdef.AndroidInstrumentTestParser(), + adb=ADB(serial)) + return testobj + + +class ShellTestProvider(TestProvider): + + test_prefix = 'shell' + config = get_config() + dotext = '.sh' + + def list_test(self): + dotext = '.sh' + mod = self.import_mod("lava_android_test.test_definitions.shells") + sh_files = find_files(mod.curdir, dotext) + test_list = [] + for f in sh_files: + ##Assume that the file name only has one '.sh' + f_name_no_dotext = os.path.basename(f).replace(dotext, '') + test_list.append('%s-%s' % (self.test_prefix, f_name_no_dotext)) + return test_list + + def load_test(self, test_name=None, serial=None): + if not test_name.startswith('%s-' % self.test_prefix): + raise UnfoundTest('The test(%s) is not found!' % test_name) + f_name_no_dotext = test_name.replace('%s-' % self.test_prefix, '', 1) + + mod = self.import_mod("lava_android_test.test_definitions.%ss" % + self.test_prefix) + f_name = '%s%s' % (f_name_no_dotext, self.dotext) + sh_file = '%s/%s' % (mod.curdir, f_name) + + test_sh_android_path = os.path.join(self.config.installdir_android, + test_name, f_name) + + INSTALL_STEPS_ADB_PRE = [ + 'push %s %s ' % (sh_file, test_sh_android_path), + 'shell chmod 777 %s' % test_sh_android_path] + + ADB_SHELL_STEPS = ['%s $(OPTIONS)' % test_sh_android_path] + + testobj = self.gen_testobj( + testname=test_name, + installer=testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE), + runner=testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS), + parser=testdef.AndroidSimpleTestParser(), + adb=ADB(serial)) + return testobj + + +class HostShellTestProvider(TestProvider): + + test_prefix = 'hostshell' + config = get_config() + dotext = '.sh' + + def list_test(self): + dotext = '.sh' + mod = self.import_mod("lava_android_test.test_definitions.hostshells") + sh_files = find_files(mod.curdir, dotext) + test_list = [] + for f in sh_files: + ##Assume that the file name only has one '.sh' + f_name_no_dotext = os.path.basename(f).replace(dotext, '') + test_list.append('%s-%s' % (self.test_prefix, f_name_no_dotext)) + return test_list + + def load_test(self, test_name=None, serial=None): + if not test_name.startswith('%s-' % self.test_prefix): + raise UnfoundTest('The test(%s) is not found!' % test_name) + f_name_no_prefix = test_name.replace('%s-' % self.test_prefix, '', 1) + + mod = self.import_mod("lava_android_test.test_definitions.%ss" % + self.test_prefix) + f_name = '%s%s' % (f_name_no_prefix, self.dotext) + test_sh_path = '%s/%s' % (mod.curdir, f_name) + + HOST_SHELL_STEPS = ['bash %s -s $(SERIAL) $(OPTIONS)' % test_sh_path] + + testobj = self.gen_testobj( + testname=test_name, + installer=testdef.AndroidTestInstaller(), + runner=testdef.AndroidTestRunner( + steps_host_pre=HOST_SHELL_STEPS), + parser=testdef.AndroidSimpleTestParser(), + adb=ADB(serial)) + return testobj + diff --git a/lava_android_test/repository.py b/lava_android_test/repository.py new file mode 100644 index 0000000..ce57470 --- /dev/null +++ b/lava_android_test/repository.py @@ -0,0 +1,83 @@ +# Copyright (C) 2012 Linaro Limited +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +import os +import subprocess + +from lava_android_test import utils + + +class RepositoryError(Exception): + """ + Raise this for repository related errors + """ + + +class Repository(object): + ''' + Base class for all repository class used to checkout files. + This class and sub classes are base the repository command. + ''' + + def __init__(self, url, repo_type, cmds=[]): + self.url = url + self.repo_type = repo_type + self.check_cmds_exist(cmds) + + def checkout(self, target_dir=None): + """ + Checkout this repository to the specified the target_dir directory + """ + raise NotImplementedError() + + def check_cmds_exist(self, cmds=[]): + """ + check whether the necessary commands are existing. + """ + for cmd in cmds: + if not utils.check_command_exist(cmd): + raise RepositoryError(("The necessary command(%) does not" + " exist, Or can't be seen from path") + % cmd) + + +class GitRepository(Repository): + + git_cmd = 'git' + + def __init__(self, url): + super(GitRepository, self).__init__(url, 'git', [self.git_cmd]) + + def checkout(self, target_dir=None): + """ + Checkout this git repository to the specified the target_dir directory + """ + cmds = [] + if not target_dir: + cmds = [self.git_cmd, 'clone', self.url] + + else: + if not os.path.exists(target_dir): + os.makedirs(target_dir) + cmds = [self.git_cmd, 'clone', self.url, target_dir] + + rc = subprocess.call(cmds) + if rc != 0: + raise RepositoryError(("Failed to clone the specified " + "repository() with exist staus=%d") + % (self.url, rc)) diff --git a/lava_android_test/swprofile.py b/lava_android_test/swprofile.py new file mode 100644 index 0000000..1a74e67 --- /dev/null +++ b/lava_android_test/swprofile.py @@ -0,0 +1,95 @@ +# Copyright (c) 2010 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +import re +import sys +from datetime import datetime +from lava_android_test.adb import ADB + + +def get_properties(adb=ADB()): + if adb is None: + return {} + + properties = {} + try: + propinfo = adb.get_shellcmdoutput("getprop")[1] + if propinfo is None: + return properties + pattern = re.compile( + '^\[(?P<key>[^\]]+?)]\s*:\s*\[(?P<value>[^\]]+)\]\s*$', + re.M) + for line in propinfo: + match = pattern.search(line) + if match: + key, value = match.groups() + properties[key] = value + except IOError: + print >> sys.stderr, "WARNING: Could not read board information" + return properties + return properties + + +def get_image_name_from_properties(adb=ADB()): + props = get_properties(adb) + return props.get('ro.build.display.id', '') + + +def get_source_info(adb=ADB()): + + TIMEFORMAT = '%Y-%m-%dT%H:%M:%SZ' + source = [] + example = {'project_name': '', + 'branch_vcs': 'git', + 'branch_url': '', + 'branch_revision': '', + 'commit_timestamp': datetime.utcnow().strftime(TIMEFORMAT)} + source.append(example) + return source + + +def get_package_info(adb=ADB()): + + packages_info = [] + pkginfo = adb.get_shellcmdoutput('/system/bin/pm list packages -v')[1] + if pkginfo is None: + return packages_info + pattern = re.compile( + ("^\s*package:\s*(?P<package_name>[^:]+?)\s*:" + "\s*(?P<version>[^\s].+)\s*$"), re.M) + for line in pkginfo: + match = pattern.search(line) + if match: + package_name, version = match.groups() + package = {'name': package_name.strip(), + 'version': version.strip()} + packages_info.append(package) + return packages_info + + +def get_software_context(adb=ADB()): + """ Return dict used for storing software_context information + + image - the image information of the android system + sources - the source information about the android system + packages - the apk packages information in the android system + """ + if adb is None: + return {} + + software_context = {'image': {'name': get_image_name_from_properties(adb)}, + 'sources': get_source_info(adb), + 'packages': get_package_info(adb) + } + return software_context diff --git a/lava_android_test/test_definitions/0xbench.py b/lava_android_test/test_definitions/0xbench.py new file mode 100644 index 0000000..8327629 --- /dev/null +++ b/lava_android_test/test_definitions/0xbench.py @@ -0,0 +1,89 @@ +# Copyright (c) 2011 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +0xbench integrates several popular benchmarks into a single Android +app that can be run to get benchmark reports for a given device. +Here by default we will run the math/2d/3d test on the target device. + +**URL:** http://code.google.com/p/0xbench/ + +**Default options:** "--ez math true --ez 2d true --ez 3d true --ez vm true" +""" + +import os +import json + +import lava_android_test.testdef + +curdir = os.path.realpath(os.path.dirname(__file__)) + +# "-timeout timeout" must be specified with at least one test +# can not only specified the "-timeout timeout" as option +DEFAULT_OPTIONS = '--ez math true --ez 2d true --ez 3d true --ez vm true' +INSTALL_STEPS_HOST_POST = [ + ("python %s/android-0xbenchmark/android_0xbenchmark_modify_path.py" + " $(SERIAL)") % curdir] + +RUN_STEPS_HOST_PRE = [ + ("python %s/android-0xbenchmark/android_0xbenchmark_kill.py" + " $(SERIAL)") % curdir] +RUN_STEPS_ADB_SHELL = ['logcat -c', + ("am start -n org.zeroxlab.zeroxbenchmark/" + "org.zeroxlab.zeroxbenchmark.Benchmark --ez autorun true $(OPTIONS)")] +RUN_STEPS_HOST_POST = [ + 'python %s/android-0xbenchmark/android_0xbenchmark_wait.py ' + '$(SERIAL) $(OPTIONS)' % curdir] + + +class ZeroXBenchmarkTestParser(lava_android_test.testdef.AndroidTestParser): + + def parse(self, result_filename=None, output_filename='0xBenchmark.bundle', + test_name=''): + """Parse test output to gather results + Use the pattern specified when the class was instantiated to look + through the results line-by-line and find lines that match it. + Results are then stored in self.results. If a fixupdict was supplied + it is used to convert test result strings to a standard format. + """ + with open(output_filename) as stream: + test_results_data = stream.read() + test_results_json = json.loads(test_results_data) + self.results['test_results'] = test_results_json[ + 'test_runs'][0]['test_results'] + if self.fixupdict: + self.fixresults(self.fixupdict) + if self.appendall: + self.appendtoall(self.appendall) + self.fixmeasurements() + self.fixids() + +save_dir = '/data/data/org.zeroxlab.zeroxbenchmark/files' +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_host_post=INSTALL_STEPS_HOST_POST) +run = lava_android_test.testdef.AndroidTestRunner( + steps_host_pre=RUN_STEPS_HOST_PRE, + adbshell_steps=RUN_STEPS_ADB_SHELL, + steps_host_post=RUN_STEPS_HOST_POST) +parser = ZeroXBenchmarkTestParser() +testobj = lava_android_test.testdef.AndroidTest(testname="0xbench", + installer=inst, runner=run, parser=parser, + org_ouput_file=os.path.join(save_dir, '0xBenchmark.bundle'), + default_options=DEFAULT_OPTIONS) diff --git a/lava_android_test/test_definitions/__init__.py b/lava_android_test/test_definitions/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lava_android_test/test_definitions/__init__.py diff --git a/lava_android_test/test_definitions/android-0xbenchmark/ZeroxBench_Preference.xml b/lava_android_test/test_definitions/android-0xbenchmark/ZeroxBench_Preference.xml new file mode 100644 index 0000000..6f07a12 --- /dev/null +++ b/lava_android_test/test_definitions/android-0xbenchmark/ZeroxBench_Preference.xml @@ -0,0 +1,5 @@ +<?xml version='1.0' encoding='utf-8' standalone='yes' ?> +<map> +<string name="KEY_RESULT_CUSTOM_DIR">/data/data/org.zeroxlab.zeroxbenchmark/files</string> +<int name="KEY_RESULT_SELECTION" value="1" /> +</map> diff --git a/lava_android_test/test_definitions/android-0xbenchmark/android_0xbenchmark_kill.py b/lava_android_test/test_definitions/android-0xbenchmark/android_0xbenchmark_kill.py new file mode 100755 index 0000000..17a4fd7 --- /dev/null +++ b/lava_android_test/test_definitions/android-0xbenchmark/android_0xbenchmark_kill.py @@ -0,0 +1,69 @@ +#!/usr/bin/python + +# Copyright (c) 2011 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import re +import sys +import time +from commands import getstatusoutput + +if len(sys.argv) == 1: + adb_cmd = "adb" +else: + adb_cmd = "adb -s %s" % (sys.argv[1]) + + +def back(): + back_cmd = '%s shell input keyevent 4' % (adb_cmd) + rc, output = getstatusoutput(back_cmd) + if rc != 0: + print 'Failed to execute command %s:%s' % (back_cmd, output) + sys.exit(1) +back() +back() +back() + +##app_76 861 80 165896 28848 ffffffff afd0eb18 S +## org.zeroxlab.zeroxbenchmark +pattern = re.compile( + '^\S+\s+(?P<pid>\d+?)\s+.*org\.zeroxlab\.zeroxbenchmark\s*$') +while True: + pscmd = '%s shell ps' % (adb_cmd) + rc, output = getstatusoutput(pscmd) + if rc != 0: + print ("Failed to get process information about " + "org.zeroxlab.zeroxbenchmark:%s") % output + sys.exit(1) + pid = None + for line in output.splitlines(): + match = pattern.match(line) + if match: + pid = match.group('pid') + break + + if pid is None: + sys.exit(0) + + killcmd = '%s shell kill %s' % (adb_cmd, pid) + rc, output = getstatusoutput(killcmd) + if rc != 0: + print 'Failed to kill process(%s):%s' % (pid, output) + sys.exit(1) + time.sleep(2) diff --git a/lava_android_test/test_definitions/android-0xbenchmark/android_0xbenchmark_modify_path.py b/lava_android_test/test_definitions/android-0xbenchmark/android_0xbenchmark_modify_path.py new file mode 100644 index 0000000..0b0d309 --- /dev/null +++ b/lava_android_test/test_definitions/android-0xbenchmark/android_0xbenchmark_modify_path.py @@ -0,0 +1,121 @@ +#!/usr/bin/python + +# Copyright (c) 2011 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +import sys +import re +import os +from commands import getstatusoutput + +curdir = os.path.realpath(os.path.dirname(__file__)) +source = '%s/ZeroxBench_Preference.xml' % curdir +target = ("/data/data/org.zeroxlab.zeroxbenchmark/shared_prefs/" + "ZeroxBench_Preference.xml") + +if len(sys.argv) == 1: + adbcmd = 'adb' +else: + adbcmd = 'adb -s %s' % (sys.argv[1]) + +target_dir = '/data/data' +lscmd = '%s shell ls -l %s' % (adbcmd, target_dir) +rc, output = getstatusoutput(lscmd) +if rc != 0: + print 'Failed to get group and owner of directory(%s) : %s' % (target_dir, + output) + sys.exit(1) +group = None +owner = None +##drwxr-x--x app_76 app_76 2011-10-21 14:40 +## org.zeroxlab.zeroxbenchmark +pattern = re.compile( + ("^d\S+\s+(?P<group>\S+?)\s+(?P<owner>\S+?)\s+" + "\S+\s+\S+\s+org\.zeroxlab\.zeroxbenchmark\s*$")) +for line in output.splitlines(): + match = pattern.match(line) + if match: + group, owner = match.groups() + break +if (group is None) or (owner is None): + print 'Failed to get group and owner of directory(%s): %s' % (target_dir, + output) + sys.exit(1) + +target_dir = '/data/data/org.zeroxlab.zeroxbenchmark/shared_prefs' +mkdircmd = '%s shell mkdir %s' % (adbcmd, target_dir) +rc, output = getstatusoutput(mkdircmd) +if rc != 0: + print 'Failed to create directory(%s): %s' % (source, target, output) + sys.exit(1) + +chowncmd = '%s shell chown %s.%s %s' % (adbcmd, owner, group, target_dir) +rc, output = getstatusoutput(chowncmd) +if rc != 0: + print 'Failed to change group(%s) and owner(%s) of file(%s): %s' % (group, + owner, target_dir, output) + sys.exit(1) + +chmodcmd = '%s shell chmod 771 %s' % (adbcmd, target_dir) +rc, output = getstatusoutput(chmodcmd) +if rc != 0: + print 'Failed to change chmod to 771 for file(%s): %s' % (target_dir, + output) + sys.exit(1) + +pushcmd = '%s push %s %s' % (adbcmd, source, target) +rc, output = getstatusoutput(pushcmd) +if rc != 0: + print 'Failed to push file(%s) to file(%s): %s' % (source, target, + output) + sys.exit(1) + +chowncmd = '%s shell chown %s.%s %s' % (adbcmd, owner, group, target) +rc, output = getstatusoutput(chowncmd) +if rc != 0: + print 'Failed to change group(%s) and owner(%s) of file(%s): %s' % (group, + owner, target, output) + sys.exit(1) + +chmodcmd = '%s shell chmod 660 %s' % (adbcmd, target) +rc, output = getstatusoutput(chmodcmd) +if rc != 0: + print 'Failed to change chmod to 771 for file(%s): %s' % (target, output) + sys.exit(1) + +target_dir = '/data/data/org.zeroxlab.zeroxbenchmark/files' +mkdircmd = '%s shell mkdir %s' % (adbcmd, target_dir) +rc, output = getstatusoutput(mkdircmd) +if rc != 0: + print 'Failed to create directory(%s): %s' % (target_dir, output) + sys.exit(1) + +chowncmd = '%s shell chown %s.%s %s' % (adbcmd, owner, group, target_dir) +rc, output = getstatusoutput(chowncmd) +if rc != 0: + print 'Failed to change group(%s) and owner(%s) of file(%s): %s' % (group, + owner, target_dir, output) + sys.exit(1) + +chmodcmd = '%s shell chmod 771 %s' % (adbcmd, target_dir) +rc, output = getstatusoutput(chmodcmd) +if rc != 0: + print 'Failed to change chmod to 771 for file(%s): %s' % (target_dir, + output) + sys.exit(1) diff --git a/lava_android_test/test_definitions/android-0xbenchmark/android_0xbenchmark_wait.py b/lava_android_test/test_definitions/android-0xbenchmark/android_0xbenchmark_wait.py new file mode 100755 index 0000000..dcfdbfc --- /dev/null +++ b/lava_android_test/test_definitions/android-0xbenchmark/android_0xbenchmark_wait.py @@ -0,0 +1,54 @@ +#!/usr/bin/python + +# Copyright (c) 2011 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +import sys +import time + +from lava_android_test.utils import stop_at_pattern + +adb_cmd = "adb" +# here assumes that there is no serial number will start with '-' +# and the options passed are start with '-' as first option +if len(sys.argv) > 1 and (not sys.argv[1].startswith('-')): + adb_cmd = "adb -s %s" % (sys.argv[1]) + +timeout = 2400 +for index in range(1, len(sys.argv)): + arg = sys.argv[index] + if arg == '-timeout' and \ + (index + 1 < len(sys.argv)) and \ + sys.argv[index + 1]: + try: + timeout = int(sys.argv[index + 1]) + except ValueError: + pass + finally: + break + +logcat_cmd = '%s logcat' % (adb_cmd) +pattern = "Displayed org.zeroxlab.zeroxbenchmark/.Report" + +if not stop_at_pattern(command=logcat_cmd, pattern=pattern, timeout=timeout): + print "0xbench Test: TIMEOUT Fail" + sys.exit(1) + +time.sleep(3) +sys.exit(0) diff --git a/lava_android_test/test_definitions/bctest.py b/lava_android_test/test_definitions/bctest.py new file mode 100644 index 0000000..5609277 --- /dev/null +++ b/lava_android_test/test_definitions/bctest.py @@ -0,0 +1,52 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Android Team <linaro-android@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +bctest test covers testing of a couple of binder IOCTLS. +We can think of it as a subset of "shell-binder" test, +which is much more exhaustive and is the main binder test to go for. +binder test "bctest" that is pre-intalled on Juice Android builds. + +**URL:** http://android.git.linaro.org/gitweb?p=platform/frameworks/base.git;a=blob;f=cmds/servicemanager/bctest.c + +**Default options:** "publish 1" +""" + +import lava_android_test.config +import lava_android_test.testdef + +test_name = 'bctest' + +DEFAULT_OPTIONS = 'publish 1' + +INSTALL_STEPS_ADB_PRE = [] +ADB_SHELL_STEPS = ['bctest $(OPTIONS)'] +PATTERN = "(?P<test_case_id>.*ioctl)\s(?P<result>(PASS|FAIL)?).*" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser, + default_options=DEFAULT_OPTIONS) diff --git a/lava_android_test/test_definitions/big_LITTLE.py b/lava_android_test/test_definitions/big_LITTLE.py new file mode 100644 index 0000000..7aa6b1f --- /dev/null +++ b/lava_android_test/test_definitions/big_LITTLE.py @@ -0,0 +1,51 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Drives big.LITTLE test scripts that are pre-intalled on Linaro Android +builds of big.LITTLE. +By default will run all the tests on the target including tests on: +basic module and switcher/cache-coherency/data-corruption/disk-io/governor/memory/perf/switcher/vfp-ffmpeg + +**URL:** https://linaro-private.git.linaro.org/gitweb?p=bL_tests/bL_iks_tests.git;a=summary + +**Default options:** "-a" +""" + +import lava_android_test.testdef + +test_name = 'big_LITTLE' + +DEFAULT_OPTIONS='-a' + +INSTALL_STEPS_ADB_PRE = [] +ADB_SHELL_STEPS = ['run_stress_switcher_tests.sh $(OPTIONS)'] +PATTERN = "(?P<test_case_id>.*-*)\s+:\s+(?P<result>(PASS|FAIL))" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser, + default_options=DEFAULT_OPTIONS) diff --git a/lava_android_test/test_definitions/blackbox.py b/lava_android_test/test_definitions/blackbox.py new file mode 100644 index 0000000..790569b --- /dev/null +++ b/lava_android_test/test_definitions/blackbox.py @@ -0,0 +1,494 @@ +# Copyright (c) 2012 Linaro Limited + +# Author: Zygmunt Krynicki <zygmunt.krynicki@linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Bridge for the black-box testing implemented by lava-blackbox. +It covers all the available tests in AOSP. +The list is available here from APMTest to ZipFileROTest + +**Sample Result URL:** http://validation.linaro.org/lava-server/dashboard/image-reports/linaro-android-member-ti_panda-linaro + +**URL:** https://github.com/zyga/lava-blackbox + +**Default options:** None +""" + +import datetime +import functools +import logging +import os +import pdb +import shutil +import subprocess +import tempfile + +from linaro_dashboard_bundle.evolution import DocumentEvolution +from linaro_dashboard_bundle.io import DocumentIO + +from lava_android_test.config import get_config + + +def debuggable_real(func): + """ + Helper for debugging functions that otherwise have their exceptions + consumed by the caller. Any exception raised from such a function will + trigger a pdb session when 'DEBUG_DEBUGGABLE' environment is set. + """ + @functools.wraps(func) + def debuggable_decorator(*args, **kwargs): + try: + return func(*args, **kwargs) + except: + logging.exception("exception in @debuggable function") + pdb.post_mortem() + return debuggable_decorator + + +def debuggable_noop(func): + return func + + +if os.getenv("DEBUG_DEBUGGABLE"): + debuggable = debuggable_real +else: + debuggable = debuggable_noop + + +class SuperAdb(object): + """ + Class that implements certain parts of ADB()-like API differently. + """ + + def __init__(self, stock_adb): + # Name of the adb executable with any required arguments, + # such as -s 'serial' + self._adb_cmd = stock_adb.adb.split() + + def __call__(self, command, *args, **kwargs): + """ + Invoke adb command. + + This call is somewhat special that it wraps two subprocess helper + functions: check_call and check_output. They are called depending + on the keyword argument 'stdout', if passed as None then output + is _not_ saved and is instantly streamed to the stdout of the running + program. In any other case stdout is buffered and saved, then returned + """ + cmd = self._adb_cmd + command + if "stdout" in kwargs and kwargs['stdout'] is None: + del kwargs['stdout'] + return subprocess.check_call(cmd, *args, **kwargs) + else: + return subprocess.check_output(cmd, *args, **kwargs) + + def listdir(self, dirname): + """ + List directory entries on the android device. + + Similar to adb.listdir() as implemented in ADB() but generates + subsequent lines instead of returning a big lump of text for the + developer to parse. Also, instead of using 'ls' on the target it + uses the special 'ls' command built into adb. + + The two special entries, . and .., are omitted + """ + for line in self(['ls', dirname]).splitlines(): + # a, b and c are various pieces of stat data + # but we don't need that here. + a, b, c, pathname = line.split(' ', 3) + if pathname not in ('.', '..'): + yield pathname + + +class AdbMixIn(object): + """ + Mix-in class that assists in setting up ADB. + + lava-android-test uses the setadb()/getadb() methods to pass the ADB object + (which encapsulates connection data for the specific device we will be + talking to). + + Since the ADB object has fixed API and changes there are beyond the scope + of this test any extra stuff we want from ADB will be provided by the + SuperAdb class. + + This mix-in class that has methods expected by lava-android-test and + exposes two properties, adb and super_adb. + """ + + adb = None + + def setadb(self, adb=None): + if self.adb is None and adb is not None: + self.adb = adb + else: + self.adb = adb + self.super_adb = SuperAdb(adb) + + def getadb(self): + return self.adb + + +class Sponge(object): + """ + A simple namespace-like object that anyone can assign and read freely. + + To get some understanding of what is going on both reads and writes are + logged. + """ + + def __getattr__(self, attr): + return super(Sponge, self).__getattr__(attr) + + def __setattr__(self, attr, value): + super(Sponge, self).__setattr__(attr, value) + + +class FutureFormatDetected(Exception): + """ + Exception raised when the code detects a new, unsupported + format that was created after this library was written. + + Since formats do not have partial ordering we can only detect + a future format when the document format is already at the "latest" + value, as determined by DocumentEvolution.is_latest(), but the actual + format is not known to us. + + Typically this won't happen often as document upgrades are not performed + unless necessary. The only case when this may happen is where the bundle + loaded from the device was already using a future format to begin with. + """ + + def __init__(self, format): + self.format = format + + def __str__(self): + "Unsupported, future format: %s" % self.format + + def __repr__(self): + return "FutureFormatDetected(%r)" % self.format + + +class BlackBoxTestBridge(AdbMixIn): + """ + Bridge for interacting with black box tests implemented as something that + looks like android test definition. + """ + + # NOTE: none of the tests will actually carry this ID, it is simply used + # here so that it's not a magic value. + testname = 'blackbox' + + def __init__(self): + """ + Initialize black-box test bridge + """ + # The sponge object is just a requirement from the API, it is not + # actually used by us in any way. The framework assigns a skeleton + # test result there but we don't really need it. The Sponge object + # is a simple 'bag' or namespace that will happily accept and record + # any values. + self.parser = Sponge() + + def install(self, install_options=None): + """ + "Install" blackbox on the test device. + + Black box tests cannot be installed, they must be pre-baked into the + image. To conform to the 'protocol' used by lava-android-test we will + perform a fake 'installation' of the black box tests by creating a + directory that lava-android-test is checking for. We do that only if + the lava-blackbox executable, which is the entry point to black box + tests exists in the image. + + ..note:: + This method is part of the lava-android-test framework API. + """ + if not self.adb.exists(self._blackbox_pathname): + # Sadly lava-android-test has no exception hierarchy that we can + # use so all problems are reported as RuntimeError + raise RuntimeError( + 'blackbox test cannot be "installed" as they must be built' + ' into the image.' + ' See https://github.com/zyga/android-lava-wrapper' + ' for details.') + else: + self.adb.makedirs(self._fake_install_path) + + def uninstall(self): + """ + Conformance method to keep up with the API required by + lava-android-test. It un-does what install() did by removing the + _fake_install_path directory from the device. + + ..note:: + This method is part of the lava-android-test framework API. + """ + if self.adb.exists(self._fake_install_path): + self.adb.rmtree(self._fake_install_path) + + @debuggable + def run(self, quiet=False, run_options=None): + """ + Run the black-box test on the target device. + + Use ADB to run the black-box executable on the device. Keep the results + in the place that lava-android-test expects us to use. + + ..note:: + This method is part of the lava-android-test framework API. + """ + # The blackbox test runner will create a directory each time it is + # started. All of those directories will be created relative to a so + # called spool directory. Instead of using the default spool directory + # (which can also change) we will use the directory where + # lava-android-test keeps all of the results. + spool_dir = get_config().resultsdir_android + logging.debug("Using spool directory for black-box testing: %r", spool_dir) + stuff_before = frozenset(self.super_adb.listdir(spool_dir)) + blackbox_command = [ + 'shell', self._blackbox_pathname, + '--spool', spool_dir, + '--run-all-tests'] + # Let's run the blackbox executable via ADB + logging.debug("Starting black-box tests...") + self.super_adb(blackbox_command, stdout=None) + logging.debug("Black-box tests have finished!") + stuff_after = frozenset(self.super_adb.listdir(spool_dir)) + # Check what got added to the spool directory + new_entries = stuff_after - stuff_before + if len(new_entries) == 0: + raise RuntimeError("Nothing got added to the spool directory") + elif len(new_entries) > 1: + raise RuntimeError("Multiple items added to the spool directory") + result_id = list(new_entries)[0] + print "The blackbox test have finished running, the result id is %r" % result_id + return result_id + + def parse(self, result_id): + """ + UNIMPLEMENTED METHOD + + Sadly this method is never called as lava-android-test crashes before + it gets to realize it is processing blackbox results and load this + class. This crash _may_ be avoided by hiding the real results of + blackbox and instead populating the results directory with dummy test + results that only let LAVA figure out that blackbox is the test to + load. Then we could monkey patch other parts and it could be + implemented. + + ONCE THIS IS FIXED THE FOLLOWING DESCRIPTION SHOULD APPLY + + Parse and save results of previous test run. + + The result_id is a name of a directory on the Android device ( + relative to the resultsdir_android configuration option). + + ..note:: + This method is part of the lava-android-test framework API. + """ + # Sadly since the goal is integration with lava lab I don't have the + # time to do it. In the lab we use lava-android-test run -o anyway. + raise NotImplementedError() + + def _get_combined_bundle(self, result_id): + """ + Compute the combined bundle of a past run and return it + """ + config = get_config() + temp_dir = tempfile.mkdtemp() + remote_bundle_dir = os.path.join(config.resultsdir_android, result_id) + try: + self._copy_all_bundles(remote_bundle_dir, temp_dir) + bundle = self._combine_bundles(temp_dir) + finally: + shutil.rmtree(temp_dir) + return bundle + + # Desired format name, used in a few methods below + _desired_format = "Dashboard Bundle Format 1.3" + + def _copy_all_bundles(self, android_src, host_dest): + """ + Use adb pull to copy all the files from android_src (android + fileystem) to host_dest (host filesystem). + """ + logging.debug("Saving bundles from %s to %s", android_src, host_dest) + for name in self.super_adb.listdir(android_src): + logging.debug("Considering file %s", name) + # NOTE: We employ simple filtering for '.json' files. This prevents + # spurious JSON parsing errors if the result directory has + # additional files of any kind. + # + # We _might_ want to lessen that eventually restriction but at this + # time blackbox is really designed to be self-sufficient so there + # is no point of additional files. + if not name.endswith('.json'): + continue + remote_pathname = os.path.join(android_src, name) + local_pathname = os.path.join(host_dest, name) + try: + logging.debug( + "Copying %s to %s", remote_pathname, local_pathname) + self.adb.pull(remote_pathname, local_pathname) + except: + logging.exception("Unable to copy bundle %s", name) + + def _combine_bundles(self, dirname): + """ + Combine all bundles from a previous test run into one bundle. + + Returns the aggregated bundle object + + Load, parse and validate each bundle from the specified directory and + combine them into one larger bundle. This is somewhat tricky. Each + bundle we coalesce may be generated by a different, separate programs + and may, thus, use different formats. + + To combine them all correctly we need to take two precautions: + 1) All bundles must be updated to a single, common format + 2) No bundle may be upgraded beyond the latest format known + to this code. Since the hypothetical 2.0 format may be widely + different that we cannot reliably interpret anything beyond + the format field. To prevent this we use the evolution API + to carefully upgrade only to the "sentinel" format, 1.3 + (at this time) + """ + # Use DocumentIO.loads() to preserve the order of entries. + # This is a very small touch but it makes reading the results + # far more pleasant. + aggregated_bundle = DocumentIO.loads( + '{\n' + '"format": "' + self._desired_format + '",\n' + '"test_runs": []\n' + '}\n')[1] + # Iterate over all files there + for name in os.listdir(dirname): + bundle_pathname = os.path.join(dirname, name) + # Process bundle one by one + try: + format, bundle = self._load_bundle(bundle_pathname) + self._convert_to_common_format(format, bundle) + self._combine_with_aggregated(aggregated_bundle, bundle) + except: + logging.exception("Unable to process bundle %s", name) + # Return the aggregated bundle + return aggregated_bundle + + def _load_bundle(self, local_pathname): + """ + Load the bundle from local_pathname. + + There are various problems that can happen here but + they should all be treated equally, the bundle not + being used. This also transparently does schema validation + so the chance of getting wrong data is lower. + """ + with open(local_pathname, 'rt') as stream: + format, bundle = DocumentIO.load(stream) + return format, bundle + + def _convert_to_common_format(self, format, bundle): + """ + Convert the bundle to the common format. + + This is a careful and possibly fragile process that may + raise FutureFormatDetected exception. If that happens + then desired_format (encoded in the function itself) must be + changed and the code reviewed for any possible changes + required to support the more recent format. + """ + while True: + # Break conditions, encoded separately for clarity + if format == self._desired_format: + # This is our desired break condition, when format + # becomes (or starts as) the desired format + break + if DocumentEvolution.is_latest(bundle): + # This is a less desired break condition, if we + # got here then the only possible explanation is + # that some program started with format > desired_format + # and the DocumentEvolution API is updated to understand + # it but we are not. In that case let's raise an exception + raise FutureFormatDetected(format) + # As long as the document format is old keep upgrading it + # step-by-step. Evolution is done in place + DocumentEvolution.evolve_document(bundle, one_step=True) + + def _combine_with_aggregated(self, aggregated_bundle, bundle): + """ + Combine the bundle with the contents of aggregated_bundle. + + This method simply transplants all the test runs as that is what + the bundle format was designed to be - a simple container for test + runs. + """ + assert bundle["format"] == self._desired_format + assert aggregated_bundle["format"] == self._desired_format + aggregated_bundle["test_runs"].extend(bundle.get("test_runs", [])) + + @property + def _blackbox_pathname(self): + """ + The path to the blackbox bridge on the device. + """ + return "/system/bin/lava-blackbox" + + @property + def _fake_install_path(self): + """ + The path that we create on the android system to + indicate that the black box test is installed. + + This is used by uninstall() and install() + """ + config = get_config() + return os.path.join(config.installdir_android, self.testname) + + def _monkey_patch_lava(self): + """ + Monkey patch the implementation of lava_android_test.commands.generate_bundle + + This change is irreversible but given the one-off nature of + lava-android-test this is okay. It should be safe to do this since + LAVA will only load the blackbox test module if we explicitly request + to run it. At that time no other tests will run in the same process. + + This method should not be used once lava-android-test grows a better + API to allow us to control how bundles are generated. + """ + from lava_android_test import commands + def _phony_generate_bundle(serial=None, result_id=None, + test=None, test_id=None, attachments=[]): + if result_id is None: + raise NotImplementedError + return self._get_combined_bundle(result_id) + commands.generate_bundle = _phony_generate_bundle + logging.warning( + "The 'blackbox' test definition has monkey-patched the function" + " lava_android_test.commands.generate_bundle() if you are _not_" + " running the blackbox test or are experiencing odd problems/crashes" + " below please look at this method first") + + +# initialize the blackbox test definition object +testobj = BlackBoxTestBridge() + +# Then monkey patch lava-android-test so that parse keeps working +testobj._monkey_patch_lava() diff --git a/lava_android_test/test_definitions/bluetooth.py b/lava_android_test/test_definitions/bluetooth.py new file mode 100644 index 0000000..2ca1d8c --- /dev/null +++ b/lava_android_test/test_definitions/bluetooth.py @@ -0,0 +1,47 @@ +# copyright (C) 2012 Linaro Limited +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +This test helps validating basic bluetooth functionality by executing the +Android BluetoothTestRunner tests. + +**URL:** http://android.git.linaro.org/gitweb?p=platform/frameworks/base.git;a=blob;f=core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestRunner.java + +**Default options:** None +""" + +import lava_android_test.testdef + +test_name = 'bluetooth' + +cmd = ("am instrument -r -e enable_iterations 2 -e discoverable_iterations 2" + " -e scan_iterations 2 -e enable_pan_iterations 2 -e pair_iterations 1 " + " -e device_address $(OPTIONS) " + " -w com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner") +RUN_ADB_SHELL_STEPS = [cmd] + +inst = lava_android_test.testdef.AndroidTestInstaller() +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=RUN_ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidInstrumentTestParser() +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/lava_android_test/test_definitions/busybox.py b/lava_android_test/test_definitions/busybox.py new file mode 100644 index 0000000..cc32fcc --- /dev/null +++ b/lava_android_test/test_definitions/busybox.py @@ -0,0 +1,57 @@ +# Copyright (c) 2011 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +This is a simple test to ensure busybox is installed on an Android build and +can execute some basic busybox commands + +**URL:** http://www.busybox.net/ + +**Default Options:** None +""" + +import os +import lava_android_test.testdef +from lava_android_test.config import get_config + +test_name = 'busybox' +config = get_config() +curdir = os.path.realpath(os.path.dirname(__file__)) +test_sh_name = 'busybox_test.sh' +test_sh_path = os.path.join(curdir, test_name, test_sh_name) +test_sh_android_path = os.path.join(config.installdir_android, + test_name, test_sh_name) + +INSTALL_STEPS_ADB_PRE = ['push %s %s ' % (test_sh_path, + test_sh_android_path), + 'shell chmod 777 %s' % test_sh_android_path] + +ADB_SHELL_STEPS = [test_sh_android_path] +#PATTERN = "^(?P<test_case_id>\w+):\W+(?P<measurement>\d+\.\d+)" +PATTERN = "^\s*(?P<test_case_id>\w+)=(?P<result>\w+)\s*$" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/lava_android_test/test_definitions/busybox/busybox_test.sh b/lava_android_test/test_definitions/busybox/busybox_test.sh new file mode 100755 index 0000000..4b3bd4e --- /dev/null +++ b/lava_android_test/test_definitions/busybox/busybox_test.sh @@ -0,0 +1,35 @@ +#!/system/bin/sh + +test_func(){ + if [ ! -f /system/bin/busybox ]; then + echo "busybox=unexist" + exit + fi + + if /system/bin/busybox [ $# -lt 1 ]; then + return 0 + fi + test_cmd=$1 + /system/bin/busybox "$@" 1>/dev/null 2>/dev/null + if /system/bin/busybox [ $? -ne 0 ]; then + echo "${test_cmd}=fail" + else + echo "${test_cmd}=pass" + fi +} + +rm -r /data/busybox 1>/dev/null 2>/dev/null + +test_func mkdir /data/busybox +test_func touch /data/busybox/test.txt +test_func ls /data/busybox/test.txt +test_func ps +test_func whoami +test_func which busybox +test_func basename /data/busybox/test.txt +test_func cp /data/busybox/test.txt /data/busybox/test2.txt +test_func rm /data/busybox/test2.txt +test_func dmesg +test_func grep service /init.rc + +rm -r /data/busybox 1>/dev/null 2>/dev/null diff --git a/lava_android_test/test_definitions/cache_coherency.py b/lava_android_test/test_definitions/cache_coherency.py new file mode 100644 index 0000000..72f1709 --- /dev/null +++ b/lava_android_test/test_definitions/cache_coherency.py @@ -0,0 +1,47 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Stressapptest tries to maximize randomized traffic to memory from processor +and I/O, with the intent of creating a realistic high load situation +in order to test the existing hardware devices in a computer. +Used for cache-coherency testing on big.LITTLE here. + +**URL:** http://android.git.linaro.org/gitweb?p=platform/external/stressapptest.git;a=summary + +**Default options:** None +""" +import lava_android_test.testdef + +test_name = 'cache_coherency' + +INSTALL_STEPS_ADB_PRE = [] +ADB_SHELL_STEPS = ['stressapptest -M 16 --cc_test -s 10'] +PATTERN = "^\s*(?P<test_case_id>Status?):\s+(?P<result>(PASS|FAIL)?)\s+-\s+" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/lava_android_test/test_definitions/commands/__init__.py b/lava_android_test/test_definitions/commands/__init__.py new file mode 100644 index 0000000..075f164 --- /dev/null +++ b/lava_android_test/test_definitions/commands/__init__.py @@ -0,0 +1,30 @@ +# copyright (C) 2012 Linaro Limited +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +This directory contains the test that only needs to run an android command and +specify the output pattern that to parse the command ouptu to get result. +Please see the example.py for a reference. +Please note this is not a test that can be run. + +**URL:** None + +**Default options:** None +""" diff --git a/lava_android_test/test_definitions/commands/bionic_libc_tests.py b/lava_android_test/test_definitions/commands/bionic_libc_tests.py new file mode 100644 index 0000000..4beaac3 --- /dev/null +++ b/lava_android_test/test_definitions/commands/bionic_libc_tests.py @@ -0,0 +1,29 @@ +# Copyright (c) 2013 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +Runs the stock bionic tests. + +**URL:** http://android.git.linaro.org/gitweb?p=platform/system/extras.git;a=tree;f=tests/bionic/libc + +**Default Options:** None +""" + +RUN_ADB_SHELL_STEPS = ['run-bionic-tests.sh'] +PATTERN = "(?P<test_case_id>.*-*)\s+:\s+(?P<result>(PASS|FAIL))" diff --git a/lava_android_test/test_definitions/commands/example.py b/lava_android_test/test_definitions/commands/example.py new file mode 100644 index 0000000..2a175da --- /dev/null +++ b/lava_android_test/test_definitions/commands/example.py @@ -0,0 +1,31 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Example for how to add tests that only need to run an android command +and specify the output pattern to parse the command ouput to get result. + +**URL:** None + +**Default options:** None +""" +RUN_ADB_SHELL_STEPS = ['tjunittest'] +PATTERN = ("^\s*(?P<test_case_id>.+)\s+\.\.\.\s+(?P<result>\w+)\." + "\s+(?P<measurement>[\d\.]+)\s+(?P<units>\w+)\s*$") diff --git a/lava_android_test/test_definitions/commands/linaro_android_kernel_test.py b/lava_android_test/test_definitions/commands/linaro_android_kernel_test.py new file mode 100644 index 0000000..39fd33c --- /dev/null +++ b/lava_android_test/test_definitions/commands/linaro_android_kernel_test.py @@ -0,0 +1,30 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +Runs the linaro kernel unit tests including: + ashmem/ashmem_expanded/alarmdev/logger/binder/sync + +**URL:** https://linaro-private.git.linaro.org/gitweb?p=android/linaro-android-kernel-test.git;a=summary + +**Default Options:** None +""" + +RUN_ADB_SHELL_STEPS = ['linaro-android-kernel-tests.sh'] +PATTERN = "\s*\[(?P<test_case_id>\w+)\]:\s\w+\s(?P<result>\w+)" diff --git a/lava_android_test/test_definitions/commands/tjunittest.py b/lava_android_test/test_definitions/commands/tjunittest.py new file mode 100644 index 0000000..e377fc4 --- /dev/null +++ b/lava_android_test/test_definitions/commands/tjunittest.py @@ -0,0 +1,30 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Tests the various code paths in the TurboJPEG C Wrapper + +**URL:** https://git.linaro.org/gitweb?p=people/tomgall/libjpeg-turbo/libjpeg-turbo.git;a=blob_plain;f=tjunittest.c + +**Default options:** None +""" +ADB_SHELL_STEPS = ['tjunittest'] +PATTERN = ("^\s*(?P<test_case_id>.+)\s+\.\.\.\s+(?P<result>\w+)\." + "\s+(?P<measurement>[\d\.]+)\s+(?P<units>\w+)\s*$") diff --git a/lava_android_test/test_definitions/cts.py b/lava_android_test/test_definitions/cts.py new file mode 100644 index 0000000..6e0eec7 --- /dev/null +++ b/lava_android_test/test_definitions/cts.py @@ -0,0 +1,70 @@ +# Copyright (C) 2012 Linaro Limited + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +This test executes the Android Compatibility Test Suite (CTS) to verify if +a given build meets all the criteria. + +**URL:** http://source.android.com/compatibility/cts-intro.html + +**Default Options:** None +""" + +import os + +from lava_android_test.testdef import (Attachment, + AndroidTest, + AndroidTestInstaller, + AndroidTestRunner, + AndroidTestParser) + +test_name = 'cts' + +curdir = os.path.realpath(os.path.dirname(__file__)) + +RUN_STEPS_HOST_PRE = ['python %s/cts/cts_wrapper.py $(SERIAL) $(OPTIONS)' % ( + curdir)] + +inst = AndroidTestInstaller() +run = AndroidTestRunner(steps_host_pre=RUN_STEPS_HOST_PRE) + +# cts-tf > [2K06-17 14:24:02 I/10.254.21.142:5555: android.acceleration. +# cts.HardwareAccelerationTest#testIsHardwareAccelerated PASS +pattern = ("^cts-tf.*\s*[\d-]+\s+[\d:]+\s+I\/\S+\:\s+(?P<test_case_id>\S+#\S+)" + "\s+(?P<result>\S+)\s*$") +parser = AndroidTestParser(pattern=pattern, + fixupdict={'PASS': 'pass', 'FAIL': 'fail'}) + +attachments = [ + Attachment(pathname="/data/local/tmp/logcat.log", + mime_type="text/plain"), + Attachment(pathname="/data/local/tmp/kmsg.log", + mime_type="text/plain"), + Attachment(pathname="/data/local/tmp/cts-results.zip", + mime_type="application/zip"), + Attachment(pathname="/data/local/tmp/device_logcat.zip", + mime_type="application/zip"), + Attachment(pathname="/data/local/tmp/host_log.zip", + mime_type="application/zip") + ] +testobj = AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser, + attachments=attachments) diff --git a/lava_android_test/test_definitions/cts/cts_list_result_wrapper.sh b/lava_android_test/test_definitions/cts/cts_list_result_wrapper.sh new file mode 100755 index 0000000..b6ef869 --- /dev/null +++ b/lava_android_test/test_definitions/cts/cts_list_result_wrapper.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# Copyright (C) 2012 Linaro Limited + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +#http://source.android.com/compatibility/downloads.html + +echo "./android-cts/tools/cts-tradefed l r" +./android-cts/tools/cts-tradefed l r |tee cts_list_results.log + +exit 0
\ No newline at end of file diff --git a/lava_android_test/test_definitions/cts/cts_prepare.sh b/lava_android_test/test_definitions/cts/cts_prepare.sh new file mode 100755 index 0000000..6b677a6 --- /dev/null +++ b/lava_android_test/test_definitions/cts/cts_prepare.sh @@ -0,0 +1,131 @@ +#!/bin/bash +# Copyright (C) 2012 Linaro Limited + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +#http://source.android.com/compatibility/downloads.html +if [ -z "$cts_pkg" ]; then +cts_pkg="android-cts-linux_x86-arm-latest.zip" +fi +media_pkg="android-cts-media-latest.zip" +site_url="http://testdata.validation.linaro.org/cts/" +#site_url="http://192.168.1.127/images/cts/" +#export http_proxy=http://localhost:3128 + +cts_pkg_url="${site_url}${cts_pkg}" +media_pkg_url="${site_url}${media_pkg}" + +ADB_OPTION="" +SERIAL="" +if [ "x${1}" != "x" ]; then + ADB_OPTION="-s ${1}" + SERIAL="${1}" +fi +ADB_CMD="adb ${ADB_OPTION}" + + +function download_unzip(){ + if [ -z "$1" ] || [ -z "$2" ]; then + return + fi + url="${1}" + pkg="${2}" + + echo "wget --connect-timeout=30 -S --progress=dot -e dotbytes=2M ${url} -O ${pkg}" + wget -c -t 20 --connect-timeout=30 -S --progress=dot -e dotbytes=2M "${url}" -O ${pkg} + if [ $? -ne 0 ]; then + echo "Failed to get the package ${url}" + exit 1 + fi + echo "unzip ${pkg}" + unzip ${pkg} + if [ $? -ne 0 ]; then + echo "Faild to unzip the package " + exit 1 + fi +} + +function main(){ + rm -fr ${cts_pkg} ${media_pkg} android-cts + download_unzip "${cts_pkg_url}" ${cts_pkg} + + #1. Your phone should be running a user build (Android 4.0 and later) from source.android.com + #2. Please refer to this link on the Android developer site and set up your device accordingly. + #3. Make sure that your device has been flashed with a user build (Android 4.0and later) before you run CTS. + ####Step 1~3 is done by deployment + + #4. You need to ensure the Text To Speech files are installed on the device. + # You can check via Settings > Speech synthesis > Install voice data + # before running CTS tests. + # (Note that this assumes you have Android Market installed on the device, + # if not you will need to install the files manually via adb) + ##TODO don't know how to do this yet + + #5. Make sure the device has a SD card plugged in and the card is empty. + # Warning: CTS may modify/erase data on the SD card plugged in to the device. + #6. Do a factory data reset on the device (Settings > SD Card & phone storage >Factory data reset). + # Warning: This will erase all user data from the phone. + #7. Make sure no lock pattern is set on the device (Settings > Security > Screen Lock should be 'None'). + #8. Make sure the "USB Debugging" development option is checked (Settings >Developer options > USB debugging). + #9. Make sure Settings > Developer options > Stay Awake is checked + #10. Make sure Settings > Developer options > Allow mock locations is checked + ####Step 5~10 is done by deployment + + #11. Make sure device is connected to a functioning Wi-Fi network (Settings > WiFi) + ${ADB_CMD} shell am start -a android.intent.action.MAIN -n com.android.settings/.Settings + ${ADB_CMD} shell service call wifi 13 i32 1 + sleep 5 + + #12. Make sure the device is at the home screen at the start of CTS (Press the home button). + ${ADB_CMD} shell input keyevent 3 + sleep 3 + + #13. While a device is running tests, it must not be used for any other tasks. + #14. Do not press any keys on the device while CTS is running. + # Pressing keys or touching the screen of a test device will interfere with the running tests and may lead to test failures. + #####Steps 13~14 should be the ok because nobody will operation the test target. + + #15. Set up accessibility tests: + echo "${ADB_CMD} install -r android-cts/repository/testcases/CtsDelegatingAccessibilityService.apk" + ${ADB_CMD} install -r android-cts/repository/testcases/CtsDelegatingAccessibilityService.apk + if [ $? -ne 0 ]; then + echo "Faild to install CtsDelegatingAccessibilityService.apk" + exit 1 + fi + ## On the device, enable Settings > Accessibility > DelegatingAccessibility Service + ${ADB_CMD} push $2 /data/local/tmp/ + ${ADB_CMD} shell am start -a android.intent.action.VIEW -n com.android.settings/.Settings + ${ADB_CMD} shell uiautomator runtest ctshelper.jar -c com.linaro.ctshelper#AccessibilityHelper + + + #16. Set up device administration tests: + echo "${ADB_CMD} install -r android-cts/repository/testcases/CtsDeviceAdmin.apk" + ${ADB_CMD} install -r android-cts/repository/testcases/CtsDeviceAdmin.apk + if [ $? -ne 0 ]; then + echo "Faild to install CtsDeviceAdmin.apk" + exit 1 + fi + ## On the device, enable Settings > Security > Device Administrators >android.deviceadmin.cts.CtsDeviceAdmin* settings + ${ADB_CMD} shell am start -a android.intent.action.VIEW -n com.android.settings/.Settings + ${ADB_CMD} shell uiautomator runtest ctshelper.jar -c com.linaro.ctshelper#SecurityHelper + ${ADB_CMD} shell am start -a android.intent.action.VIEW -n com.android.launcher/com.android.launcher2.Launcher + + exit 0 +} + +main "$@" diff --git a/lava_android_test/test_definitions/cts/cts_redirect.sh b/lava_android_test/test_definitions/cts/cts_redirect.sh new file mode 100755 index 0000000..b23b3a5 --- /dev/null +++ b/lava_android_test/test_definitions/cts/cts_redirect.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# Copyright (C) 2012 Linaro Limited + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +output_file=${1} && shift +eval "$@" &> ${output_file} & +echo $! +exit 0 diff --git a/lava_android_test/test_definitions/cts/cts_run_wrapper.sh b/lava_android_test/test_definitions/cts/cts_run_wrapper.sh new file mode 100755 index 0000000..6e4e5ba --- /dev/null +++ b/lava_android_test/test_definitions/cts/cts_run_wrapper.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# Copyright (C) 2012 Linaro Limited + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +#http://source.android.com/compatibility/downloads.html + +echo ./android-cts/tools/cts-tradefed "$@" --disable-reboot +./android-cts/tools/cts-tradefed "$@" --disable-reboot > ./cts_output.log 2>&1 +exit 0 diff --git a/lava_android_test/test_definitions/cts/cts_wrapper.py b/lava_android_test/test_definitions/cts/cts_wrapper.py new file mode 100755 index 0000000..b6d46bf --- /dev/null +++ b/lava_android_test/test_definitions/cts/cts_wrapper.py @@ -0,0 +1,353 @@ +#!/usr/bin/python + +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import re +import sys +import pexpect +import time +import xml.dom.minidom +from zipfile import ZipFile + +from lava_android_test.adb import ADB +from lava_android_test.utils import stop_at_pattern +from lava_android_test.utils import find_files + +adb = ADB(sys.argv[1]) +curdir = os.path.realpath(os.path.dirname(__file__)) + + +def stop_at_cts_pattern(command=None, pattern=None, timeout=-1): + if not command: + return + + if not pattern: + response = [pexpect.EOF] + else: + response = [pattern, pexpect.EOF] + + result = True + proc_cts = pexpect.spawn(command, logfile=sys.stdout) + time.sleep(200) + try: + match_id = proc_cts.expect(response, timeout=timeout) + if match_id == 0: + time.sleep(5) + except pexpect.TIMEOUT: + result = False + finally: + proc_cts.sendcontrol('C') + proc_cts.sendline('') + target_dir = os.path.join(os.getcwd(), + './android-cts/repository/results/') + for zip_f in find_files(target_dir, '.zip'): + ret_code = adb.push(zip_f, '/data/local/tmp/cts-results.zip')[0] + if ret_code != 0: + print "Failed to push file %s to device(%s)" % (zip_f, + adb.get_serial()) + log_target_dir = os.path.join(os.getcwd(), + './android-cts/repository/logs/') + for zip_f in find_files(log_target_dir, '.zip'): + base_name = os.path.basename(zip_f) + if base_name.startswith('device_logcat_'): + base_name = 'device_logcat.zip' + if base_name.startswith('host_log_'): + base_name = 'host_log.zip' + + ret_code = adb.push(zip_f, '/data/local/tmp/%s' % base_name)[0] + if ret_code != 0: + print "Failed to push file %s to device(%s)" % (zip_f, + adb.get_serial()) + with ZipFile(zip_f) as log_fd: + print '=========Log file [%s] starts=========>>>>>' % ( + base_name) + f_name = base_name.replace('.zip', '.txt') + for line in log_fd.open(f_name).readlines(): + print line.rstrip() + print '<<<<<=========Log file [%s] ends=========' % base_name + return result + + +def get_not_executed(): + list_result_path = os.path.join(curdir, 'cts_list_result_wrapper.sh') + list_result_cmd = "bash %s" % list_result_path + + pattern = 'CTS unknown' + if not stop_at_pattern(command=list_result_cmd, + pattern=pattern, timeout=5): + print "Failed to list the cts result for device(%s)" % adb.get_serial() + + with open('cts_list_results.log') as fd: + #0 17237 126 0 2012.06.23_03.31.49 CTS unknown + pattern = ("\s*\d+\s+\d+\s+\d+\s+(?P<no_executed>\d+)" + "\s+.+CTS\s+unknown\s*$") + pat = re.compile(pattern) + for line in fd.readlines(): + match = pat.search(line) + if not match: + continue + return match.groupdict()['no_executed'] + return 0 + + +def prepare_cts(): + cts_prepare_path = os.path.join(curdir, 'cts_prepare.sh') + cts_helper_jar_path = os.path.join(curdir, 'ctshelper.jar') + cts_prepare_cmd = "bash %s" % cts_prepare_path + if not stop_at_pattern(command="%s %s %s" % (cts_prepare_cmd, + adb.get_serial(), cts_helper_jar_path), + timeout=18000): + print "Preapration for CTS test times out" + return False + return True + + +def run_cts_with_plan(cts_cmd=None, plan='CTS', timeout=36000): + pattern = "Time:" + plan_command = '--plan %s' % plan + if cts_cmd: + plan_command = "%s %s --disable-reboot" % (cts_cmd, plan_command) + if not stop_at_cts_pattern(command=plan_command, pattern=pattern, + timeout=timeout): + print "CTS test times out" + return False + + return True + + +def run_cts_with_package(cts_cmd=None, package=None, timeout=36000): + if not package: + return True + pattern = "Time:" + plan_command = '--package %s' % package + if cts_cmd: + plan_command = "%s %s --disable-reboot" % (cts_cmd, plan_command) + if not stop_at_cts_pattern(command=plan_command, pattern=pattern, + timeout=timeout): + print "CTS test times out" + return False + + return True + + +def run_cts_with_class(cts_cmd=None, cls=None, method=None, timeout=36000): + if not cls: + return True + pattern = "Time:" + cmd = '--class %s' % cls + if method: + cmd = '%s --method %s' % (cmd, method) + + if cts_cmd: + cmd = "%s %s --disable-reboot" % (cts_cmd, cmd) + if not stop_at_cts_pattern(command=cmd, pattern=pattern, + timeout=timeout): + print "CTS test times out" + return False + + return True + + +def run_cts_continue(cts_cmd=None): + pattern = "Time:" + continue_command = '--continue-session 0' + if cts_cmd: + continue_command = "%s %s" % (cts_cmd, continue_command) + + while True: + number_of_not_executed = get_not_executed() + if number_of_not_executed and int(number_of_not_executed) > 0: + print ('Reconnect the adb connection before continuing ' + 'the CTS on device(%s)') % adb.get_serial() + if not adb.reconnect(): + print "Faile to reconnect the adb connection of device(%s)" % ( + adb.get_serial()) + break + + print "Continue the uncompleted CTS test on device(%s)" % ( + adb.get_serial()) + + if not stop_at_cts_pattern(command=continue_command, + pattern=pattern, + timeout=36000): + print "CTS test times out" + else: + break + + +def collect_log(command=None, output_file=None): + if command and output_file: + print 'Redirect the output of command[%s] to file[%s]' % (command, + output_file) + cmd = 'bash %s %s "%s"' % (os.path.join(curdir, 'cts_redirect.sh'), + output_file, command) + stdout = adb.run_cmd_host(cmd)[1] + if stdout: + return stdout[0].strip() + + return None + + +def collect_logs(): + + kmsg = {'command': + 'adb -s %s shell cat /proc/kmsg' % (adb.get_serial()), + 'output_file': 'kmsg.log'} + + logcat = {'command': + 'adb -s %s logcat -c; adb -s %s logcat -v time' % ( + adb.get_serial(), adb.get_serial()), + 'output_file': 'logcat.log'} + + ## define all the logs need to be collected + logs = [kmsg, logcat] + for log in logs: + pid = collect_log(command=log.get('command'), + output_file=log.get('output_file')) + if pid: + log['pid'] = pid + return logs + + +def push_log(logs=[]): + for log in logs: + log_file = log.get('output_file') + base_name = os.path.basename(log_file) + if log_file: + ret_code = adb.push(log_file, '/data/local/tmp/%s' % base_name)[0] + if ret_code != 0: + print "Failed to push file %s to device(%s)" % (log_file, + adb.get_serial()) + with open(log_file) as log_fd: + print '=========Log file [%s] starts=========>>>>>' % ( + log_file) + for line in log_fd.readlines(): + print line.rstrip() + print '<<<<<=========Log file [%s] ends=========' % log_file + + +def get_all_packages(plan_file=None): + if not plan_file: + return [] + if not os.path.exists(plan_file): + print "file(%s) does not exist" % plan_file + return [] + + package_list = [] + try: + dom = xml.dom.minidom.parse(plan_file) + test_plan = dom.getElementsByTagName("TestPlan")[0] + for entry in test_plan.getElementsByTagName("Entry"): + package_list.append(entry.attributes.get('uri').value) + except Exception as e: + print "Has exception to parse the xml file" + print "Exception: %s" % e + finally: + return package_list + + +def get_value_from_paras(paras=[], option=None, default=None): + if not option: + return default + + if not option in paras: + return default + + index = paras.index(option) + if len(paras) > index + 1: + return paras[index + 1] + + return default + + +def main(): + + package_name = None + plan_name = 'CTS' + class_name = None + method_name = None + timeout = 36000 + force_abi = None + #--cts_pkg cts_package_file --package package_name --timeout 36000 + #--cts_pkg cts_package_file --plan plan_name --timeout 36000 + if len(sys.argv) > 2: + paras = sys.argv[2:] + cts_pkg = get_value_from_paras(paras=paras, option='--cts-pkg') + if cts_pkg: + os.environ["cts_pkg"] = cts_pkg + + java_home = get_value_from_paras(paras=paras, option='--java-home') + if java_home: + os.environ["PATH"] = java_home + "/bin" + os.pathsep + java_home \ + + "/jre/bin" + os.pathsep + os.environ["PATH"] + os.environ["JAVA_HOME"] = java_home + + package_name = get_value_from_paras(paras=paras, option='--package') + plan_name = get_value_from_paras(paras=paras, + option='--plan', + default='CTS') + timeout = get_value_from_paras(paras=paras, option='--timeout', + default=36000) + if timeout: + timeout = int(timeout) + + class_name = get_value_from_paras(paras=paras, option='--class') + method_name = get_value_from_paras(paras=paras, option='--method') + + force_abi = get_value_from_paras(paras=paras, option='--force-abi') + + run_wrapper_path = os.path.join('./android-cts/tools/cts-tradefed ') + run_wrapper_cmd = "%s" % run_wrapper_path + run_wrapper_cmd = '%s run cts --serial %s' % (run_wrapper_cmd, + adb.get_serial()) + + if force_abi: + run_wrapper_cmd = '%s --force-abi %s' % (run_wrapper_cmd, + force_abi) + + logs = collect_logs() + if not prepare_cts(): + sys.exit(1) + + try: + if package_name: + run_cts_with_package(cts_cmd=run_wrapper_cmd, package=package_name, + timeout=timeout) + elif class_name: + run_cts_with_class(cts_cmd=run_wrapper_cmd, cls=class_name, + method=method_name, timeout=timeout) + else: + run_cts_with_plan(cts_cmd=run_wrapper_cmd, plan=plan_name, + timeout=timeout) + + finally: + for log in logs: + pid = log.get('pid') + if pid: + adb.run_cmd_host('kill -9 %s' % pid) + + push_log(logs) + + sys.exit(0) + + +if __name__ == '__main__': + main() diff --git a/lava_android_test/test_definitions/cts/ctshelper.jar b/lava_android_test/test_definitions/cts/ctshelper.jar Binary files differnew file mode 100644 index 0000000..0c253ae --- /dev/null +++ b/lava_android_test/test_definitions/cts/ctshelper.jar diff --git a/lava_android_test/test_definitions/gatortest.py b/lava_android_test/test_definitions/gatortest.py new file mode 100644 index 0000000..a04ad6c --- /dev/null +++ b/lava_android_test/test_definitions/gatortest.py @@ -0,0 +1,52 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Ensures the gator daemon required by DS5 is up and running on the Android +device. + +**URL:** https://wiki.linaro.org/Platform/Android/DebugAndroidUsingDS-5 + +**Default Options:** None +""" + +import os + +import lava_android_test.testdef + +curdir = os.path.realpath(os.path.dirname(__file__)) +test_name = "gatortest" + +RUN_STEPS_HOST_POST = ['python %s/gatortest/daemoncheck.py $(SERIAL)' % curdir, + 'python %s/gatortest/modulecheck.py $(SERIAL)' % curdir] + +PATTERN = "^\s*(?P<test_case_id>\w+)\s*=\s*(?P<result>\w+)\s*$" + +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) + +run = lava_android_test.testdef.AndroidTestRunner( + steps_host_post=RUN_STEPS_HOST_POST) +# dummy installer +inst = lava_android_test.testdef.AndroidTestInstaller() + +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + runner=run, + installer=inst, + parser=parser) diff --git a/lava_android_test/test_definitions/gatortest/daemoncheck.py b/lava_android_test/test_definitions/gatortest/daemoncheck.py new file mode 100644 index 0000000..a1fa1b9 --- /dev/null +++ b/lava_android_test/test_definitions/gatortest/daemoncheck.py @@ -0,0 +1,20 @@ +import sys +from commands import getstatusoutput + +if len(sys.argv) == 1: + adbcmd = 'adb' +else: + adbcmd = 'adb -s %s' % (sys.argv[1]) + +cmd = '%s shell ps' % (adbcmd) +rc, output = getstatusoutput(cmd) +if rc != 0: + print 'Failed to run command %s : %s' % (cmd, output) + sys.exit(1) + +# parse output + +if output.find("gator") != -1: + print "gator_daemon_check=pass" +else: + print "gator_daemon_check=fail" diff --git a/lava_android_test/test_definitions/gatortest/modulecheck.py b/lava_android_test/test_definitions/gatortest/modulecheck.py new file mode 100644 index 0000000..23f0ba6 --- /dev/null +++ b/lava_android_test/test_definitions/gatortest/modulecheck.py @@ -0,0 +1,20 @@ +import sys +from commands import getstatusoutput + +if len(sys.argv) == 1: + adbcmd = 'adb' +else: + adbcmd = 'adb -s %s' % (sys.argv[1]) + +cmd = '%s shell lsmod' % (adbcmd) +rc, output = getstatusoutput(cmd) +if rc != 0: + print 'Failed to run command %s : %s' % (cmd, output) + sys.exit(1) + +# parse output + +if output.find("gator") != -1: + print "gator_module_check=pass" +else: + print "gator_module_check=fail" diff --git a/lava_android_test/test_definitions/glmark2.py b/lava_android_test/test_definitions/glmark2.py new file mode 100644 index 0000000..f111c90 --- /dev/null +++ b/lava_android_test/test_definitions/glmark2.py @@ -0,0 +1,52 @@ +# Copyright (C) 2010-2012 Linaro Limited + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Executes the glmark2 benchmark. + +**URL:** https://launchpad.net/glmark2 + +**Default Options:** None +""" + +import os +import lava_android_test.testdef +from lava_android_test.config import get_config + +test_name = 'glmark2' +config = get_config() +curdir = os.path.realpath(os.path.dirname(__file__)) +test_sh_name = 'glmark2.sh' +test_sh_path = os.path.join(curdir, test_name, test_sh_name) +RUN_STEPS_HOST_PRE = ['/bin/bash %s $(SERIAL)' % test_sh_path] + +#I/glmark2 ( 1818): [texture] texture-filter=nearest: FPS: 8 FrameTime: 125.000 ms +PATTERN = ("^\s*I/glmark2\s*\(.+\):\s+(?P<test_case_id>\[\w+\]\s+\S+)" + "\s+FPS:\s+(?P<measurement>\d+)") + +inst = lava_android_test.testdef.AndroidTestInstaller() +run = lava_android_test.testdef.AndroidTestRunner( + steps_host_pre=RUN_STEPS_HOST_PRE) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN, + appendall={'units': 'FPS'}) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/lava_android_test/test_definitions/glmark2/glmark2.sh b/lava_android_test/test_definitions/glmark2/glmark2.sh new file mode 100755 index 0000000..2a9b410 --- /dev/null +++ b/lava_android_test/test_definitions/glmark2/glmark2.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# Copyright (C) 2012 Linaro Limited + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +ADB_CMD="adb" +prog_dir=`dirname $0` + +function main(){ + if [ "x${1}" != "x" ]; then + ADB_CMD="${ADB_CMD} -s ${1}" + fi + ${ADB_CMD} logcat -c + ${ADB_CMD} shell am start -W org.linaro.glmark2/.Glmark2Activity + python ${prog_dir}/glmark2_wait.py ${1} + #${ADB_CMD} logcat -d glmark2:I *:S + ${ADB_CMD} logcat -d +} + +main "$@" diff --git a/lava_android_test/test_definitions/glmark2/glmark2_wait.py b/lava_android_test/test_definitions/glmark2/glmark2_wait.py new file mode 100755 index 0000000..5c680ce --- /dev/null +++ b/lava_android_test/test_definitions/glmark2/glmark2_wait.py @@ -0,0 +1,51 @@ +#!/usr/bin/python + +# Copyright (C) 2012 Linaro Limited + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +import pexpect +import sys +import time + +if len(sys.argv) == 1: + adb_cmd = "adb" +else: + adb_cmd = "adb -s %s" % (sys.argv[1]) + +logcat_cmd = '%s logcat -v time' % (adb_cmd) +pattern1 = "glmark2 Score:" +#pattern1 = "\[loop\] fragment-steps=5:fragment-uniform=true: +#vertex-steps=5: FPS:" +pattern2 = "Process org.linaro.glmark2.+has died" +pattern3 = ("No suitable EGLConfig for GLES2.0 found." + " Please check that proper GLES2.0 drivers are installed.") + +try: + proc = pexpect.spawn(logcat_cmd, logfile=sys.stdout) + match_id = proc.expect([pattern1, pattern2, pattern3, pexpect.EOF], + timeout=1000) + print "in glmark2_wait.py match_id = %s\n" % match_id + if (match_id == 0) or (match_id == 1) or (match_id == 2): + proc.sendcontrol('C') +except pexpect.TIMEOUT: + print "glmark2 Test: TIMEOUT Fail\n" + sys.exit(1) +finally: + proc.sendcontrol('C') + +time.sleep(3) +sys.exit(0) diff --git a/lava_android_test/test_definitions/helloworld.py b/lava_android_test/test_definitions/helloworld.py new file mode 100644 index 0000000..40ad04e --- /dev/null +++ b/lava_android_test/test_definitions/helloworld.py @@ -0,0 +1,46 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Example for how to add test wrapper for lava-android-test + +**URL:** None + +**Default options:** None +""" + +import lava_android_test.config +import lava_android_test.testdef + +test_name = 'helloworld' + +INSTALL_STEPS_ADB_PRE = [] +ADB_SHELL_STEPS = ['echo helloworld: PASS'] +PATTERN = "^\s*(?P<test_case_id>[^:]+?):\s+(?P<result>(PASS|FAIL)?)\s*$" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/lava_android_test/test_definitions/hostshells/__init__.py b/lava_android_test/test_definitions/hostshells/__init__.py new file mode 100644 index 0000000..dcb0716 --- /dev/null +++ b/lava_android_test/test_definitions/hostshells/__init__.py @@ -0,0 +1,31 @@ +# copyright (C) 2012 Linaro Limited +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +This directory contains the tests that only need to run a host command. +Please see the example.sh for a reference. +Please note this is not a test that can be run. + +**URL:** None + +**Default options:** None +""" + +import os +curdir = os.path.dirname(os.path.realpath(__file__)) diff --git a/lava_android_test/test_definitions/hostshells/connect-lab-wifi.sh b/lava_android_test/test_definitions/hostshells/connect-lab-wifi.sh new file mode 100755 index 0000000..d04233d --- /dev/null +++ b/lava_android_test/test_definitions/hostshells/connect-lab-wifi.sh @@ -0,0 +1,170 @@ +#!/bin/bash +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +function generate_wpa_conf(){ + conf=$1 && ssid=$2 passwd=$3 + if [ -z "${conf}" ];then + return + fi + + if [ -z "${ssid}" ]; then + cat >wpa_supplicant.conf <<__EOF__ +ctrl_interface=wlan0 +update_config=1 +device_type=0-00000000-0 + +__EOF__ + + elif [ -z "${passwd}" ]; then + cat >wpa_supplicant.conf <<__EOF__ +ctrl_interface=wlan0 +update_config=1 +device_type=0-00000000-0 + +network={ + ssid="${ssid}" + key_mgmt=NONE + priority=2 +} + +__EOF__ + + else + cat >wpa_supplicant.conf <<__EOF__ +ctrl_interface=wlan0 +update_config=1 +device_type=0-00000000-0 + +network={ + ssid="${ssid}" + psk="${passwd}" + key_mgmt=WPA-PSK + priority=2 +} + +__EOF__ + + fi +} + +function enable_wifi(){ + conf=$1 && ssid=$2 && serial=$3 + if [ -z "${conf}" ]; then + return + fi + ADB_OPTION="" + if [ -n "${serial}" ]; then + ADB_OPTION="-s ${serial}" + fi + + adb ${ADB_OPTION} shell am start -a android.intent.action.MAIN -n com.android.settings/.Settings + sleep 3 + adb ${ADB_OPTION} shell service call wifi 13 i32 0 + sleep 5 + adb ${ADB_OPTION} push "${conf}" /data/misc/wifi/wpa_supplicant.conf + adb ${ADB_OPTION} shell chown wifi.wifi /data/misc/wifi/wpa_supplicant.conf + adb ${ADB_OPTION} shell chmod 660 /data/misc/wifi/wpa_supplicant.conf + adb ${ADB_OPTION} shell ls -l /data/misc/wifi/wpa_supplicant.conf + adb ${ADB_OPTION} shell service call wifi 13 i32 1 + #extend the wait time because the time to turn wifi on some devices(like + #Origen) will take a little longer + sleep 60 + for i in {1..30}; do + adb ${ADB_OPTION} shell wpa_cli list_networks|grep -E "^\s*[[:digit:]]+\s+${ssid}\s+any\s+\[CURRENT\]" + if [ $? -eq 0 ];then + break + fi + sleep 5 + done + + if [ $i -eq 30 ]; then + echo "connect-lava-wifi-${ssid}=fail" + return 1 + else + echo "connect-lava-wifi-${ssid}=pass" + return 0 + fi +} + +function parse_argv() { + # Parse command line arguments + # Sets: VERBOSE, dev + while test -n "$1"; do + case "$1" in + --serial|-s) + SERIAL="$2" + shift 2 + ;; + --passwd|-p) + PASSWD="$2" + shift 2 + ;; + *) + if [ -n "${SSID}" ]; then + show_usage + exit 1 + else + SSID="$1" + shift + fi + ;; + esac + done +} + +function show_usage(){ + # Display the usage line + echo "Usage 1, Specify the ssid and pawword via command line:" + echo " $0 [--passwd|-p passwd] [--serial|-s serial] ssid" + echo "Usage 2, Specify the ssid and pawword via configuration file:" + echo " Specify the file path via 'WIFI_DEV_CONF' environment variable," + echo " /etc/lava/devices/wifi.conf is the default value if not specified" + echo " The content of this file like this:" + echo " SSID=the ssid of wifi" + echo " PASSWD=the password of the specified wifi via SSID" +} + +function main(){ + if [ -z "${WIFI_DEV_CONF}" ]; then + wifi_dev_conf="/etc/lava/devices/wifi.conf" + else + wifi_dev_conf="${WIFI_DEV_CONF}" + fi + + echo "Will use ${wifi_dev_conf} as the configuration file for wifi if exists" + if [ -f "${wifi_dev_conf}" ]; then + . "${wifi_dev_conf}" + fi + parse_argv "$@" + + if [ -z "${SSID}" ]; then + show_usage + exit 1 + fi + + wifi_conf="wpa_supplicant.conf" + generate_wpa_conf "${wifi_conf}" "${SSID}" "${PASSWD}" + enable_wifi "${wifi_conf}" "${SSID}" "${SERIAL}" + RET=$? + rm -f "${wifi_conf}" + exit $RET +} + +main "$@" diff --git a/lava_android_test/test_definitions/hostshells/example.sh b/lava_android_test/test_definitions/hostshells/example.sh new file mode 100755 index 0000000..50c81b7 --- /dev/null +++ b/lava_android_test/test_definitions/hostshells/example.sh @@ -0,0 +1,62 @@ +#!/bin/bash +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +function parse_argv() { + # Parse command line arguments + while test -n "$1"; do + case "$1" in + --serial|-s) + SERIAL="$2" + if [ -n "${SERIAL}" ]; then + shift 2 + else + show_usage + exit 1 + fi + ;; + --help|-h) + show_usage + exit 1 + ;; + *) + if [ -n "${OPTIONS}" ]; then + OPTIONS="${OPTIONS} $1" + else + OPTIONS="$1" + fi + shift + ;; + esac + done +} + +function show_usage(){ + # Display the usage line + echo "Usage $(basename $0) [--serial <serial>|-s <serial>] <other-option>" + echo "Usage $(basename $0) [--help|-h]" +} + +function main(){ + parse_argv "$@" + echo "hostshells-example-fail=fail" + echo "hostshells-example-pass=pass" +} + +main "$@" diff --git a/lava_android_test/test_definitions/hostshells/install-overlay.sh b/lava_android_test/test_definitions/hostshells/install-overlay.sh new file mode 100755 index 0000000..996bcbb --- /dev/null +++ b/lava_android_test/test_definitions/hostshells/install-overlay.sh @@ -0,0 +1,79 @@ +#!/bin/bash +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +function parse_argv() { + # Parse command line arguments + while test -n "$1"; do + case "$1" in + --serial|-s) + SERIAL="$2" + if [ -n "${SERIAL}" ]; then + shift 2 + else + show_usage + exit 1 + fi + ;; + --url|-u) + URL="$2" + if [ -n "${URL}" ]; then + shift 2 + else + show_usage + exit 1 + fi + ;; + --help|-h) + show_usage + exit 1 + ;; + *) + if [ -n "${OPTIONS}" ]; then + OPTIONS="${OPTIONS} $1" + else + OPTIONS="$1" + fi + shift + ;; + esac + done +} + +function show_usage(){ + # Display the usage line + echo "Usage $(basename $0) [--serial <serial>|-s <serial>] <other-option>" + echo "Usage $(basename $0) [--help|-h]" +} + +function main(){ + parse_argv "$@" + # Fetch the overlay and extract it. + wget $URL overlay.tar.bz2 + tar -xvf overlay.tar.bz2 + + # Push the overlay + adb -s ${SERIAL} remount + adb -s ${SERIAL} push overlay/ / + adb -s ${SERIAL} shell sync + adb -s ${SERIAL} shell stop + adb -s ${SERIAL} shell start +} + +main "$@" diff --git a/lava_android_test/test_definitions/hostshells/sdcard-mounted.sh b/lava_android_test/test_definitions/hostshells/sdcard-mounted.sh new file mode 100755 index 0000000..4257850 --- /dev/null +++ b/lava_android_test/test_definitions/hostshells/sdcard-mounted.sh @@ -0,0 +1,65 @@ +#!/bin/bash +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +function parse_argv() { + # Parse command line arguments + while test -n "$1"; do + case "$1" in + --serial|-s) + SERIAL="$2" + if [ -n "${SERIAL}" ]; then + shift 2 + else + show_usage + exit 1 + fi + ;; + --help|-h) + show_usage + exit 1 + ;; + *) + shift + ;; + esac + done +} + +function show_usage(){ + # Display the usage line + echo "Usage $(basename $0) [--serial <serial>|-s <serial>]" + echo "Usage $(basename $0) [--help|-h]" +} + +function main(){ + parse_argv "$@" + ADB_OPTION='' + if [ -n "${SERIAL}" ]; then + ADB_OPTION="-s ${SERIAL}" + fi + adb ${ADB_OPTION} shell mount |grep -e '/sdcard' -e 'emulated' + if [ $? -eq 0 ]; then + echo "sdcard-mounted=pass" + else + echo "sdcard-mounted=fail" + fi +} + +main "$@" diff --git a/lava_android_test/test_definitions/hostshells/workload.sh b/lava_android_test/test_definitions/hostshells/workload.sh new file mode 100755 index 0000000..a01a4a1 --- /dev/null +++ b/lava_android_test/test_definitions/hostshells/workload.sh @@ -0,0 +1,146 @@ +#!/bin/bash +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +function parse_argv() { + # Parse command line arguments + while test -n "$1"; do + case "$1" in + --serial|-s) + SERIAL="$2" + if [ -n "${SERIAL}" ]; then + shift 2 + else + show_usage + exit 1 + fi + ;; + --config|-c) + CONFIG="$2" + if [ -n "${CONFIG}" ]; then + shift 2 + else + show_usage + exit 1 + fi + ;; + --git|-g) + GIT_URL="$2" + if [ -n "${GIT_URL}" ]; then + shift 2 + else + show_usage + exit 1 + fi + ;; + --help|-h) + show_usage + exit 1 + ;; + *) + if [ -n "${OPTIONS}" ]; then + OPTIONS="${OPTIONS} $1" + else + OPTIONS="$1" + fi + shift + ;; + esac + done +} + +function show_usage(){ + # Display the usage line + echo "Usage $(basename $0) [--serial|-s <serial>] [--config|-c <config_file>] [--git|g <git-url>] <other-option>" + echo "Usage $(basename $0) [--help|-h]" +} + +function parse_output_result(){ + result_f=${1} + if [ ! -f "${1}" ]; then + echo "There is no result file output/results.csv" + return + fi + + file_tmp=${result_f}.tmp + sed 's/ /_/g' ${result_f} > ${file_tmp} + keys=`head -n 1 ${file_tmp}` + values=`tail -n 1 ${file_tmp}` + for ((i=1; i<21; i++)); do + key=`echo ${keys}|cut -d , -f ${i}|sed 's/\r//'` + value=`echo ${values}|cut -d , -f ${i}|sed 's/\r//'` + + echo ${value}|grep -P '^[.\d]+$' &>/dev/null + if [ $? -ne 0 ]; then + key="${key}_${value}" + value="true" + fi + echo ${key}=${value} + done + rm -f ${file_tmp} +} + +function main(){ + local_git="file:///home/bhoj/workload-automation.git" + branch="lava" + outputdir="outputdir" + result="${outputdir}/result.csv" + + parse_argv "$@" + + config_file="config.csv" + if [ -n "${CONFIG}" ]; then + config_file="${CONFIG}" + fi + + if [ -n "${GIT_URL}" ]; then + git_url="${GIT_URL}" + else + git_url="${local_git}" + fi + + git clone "${git_url}" -b ${branch} + if [ $? -ne 0 ]; then + echo "Failed to clone git repository: ${git_url}" + exit 1 + fi + ip=`echo ${SERIAL}|sed 's/:5555//'` + cd "workload-automation" + + #update the ip address and patch config.csv file + sed -i "s/192.168.1.38/${ip}/g" workload_config.py + + python workload_setup_dependencies.py + if [ $? -ne 0 ]; then + echo "Failed to run workload_setup_dependencies.py" + exit 1 + fi + + rm -fr ${outputdir} + python workload.py ${config_file} ${outputdir}/ + if [ $? -ne 0 ]; then + echo "Failed to run workload.py config.csv outputdir/" + exit 1 + fi + cat ${result} + parse_output_result ${result} +} + +main "$@" + diff --git a/lava_android_test/test_definitions/ime.py b/lava_android_test/test_definitions/ime.py new file mode 100644 index 0000000..aacaef6 --- /dev/null +++ b/lava_android_test/test_definitions/ime.py @@ -0,0 +1,57 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Performs testing of Android Input Method Manager by listing the available +input methods on the system. + +**URL:** http://android.git.linaro.org/gitweb?p=platform/frameworks/base.git;a=blob;f=cmds/ime/src/com/android/commands/ime/Ime.java + +**Default options:** None +""" + +import os +import lava_android_test.testdef +from lava_android_test.config import get_config + +test_name = 'ime' +config = get_config() +curdir = os.path.realpath(os.path.dirname(__file__)) +test_sh_name = 'ime_test.sh' +test_sh_path = os.path.join(curdir, test_name, test_sh_name) +test_sh_android_path = os.path.join(config.installdir_android, + test_name, test_sh_name) + +INSTALL_STEPS_ADB_PRE = ['push %s %s ' % (test_sh_path, + test_sh_android_path), + 'shell chmod 777 %s' % test_sh_android_path] + +ADB_SHELL_STEPS = [test_sh_android_path] +PATTERN = "^\s*(?P<test_case_id>ime)=(?P<result>\w+)\s*$" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/lava_android_test/test_definitions/ime/ime_test.sh b/lava_android_test/test_definitions/ime/ime_test.sh new file mode 100755 index 0000000..6a6d7a1 --- /dev/null +++ b/lava_android_test/test_definitions/ime/ime_test.sh @@ -0,0 +1,13 @@ +#!/system/bin/sh + +test_func(){ + if [ ! -f /system/bin/ime ]; then + echo "ime=fail" + exit + fi + + /system/bin/ime list -a + echo "ime=pass" +} + +test_func diff --git a/lava_android_test/test_definitions/install_prep_4bench.py b/lava_android_test/test_definitions/install_prep_4bench.py new file mode 100644 index 0000000..2687adc --- /dev/null +++ b/lava_android_test/test_definitions/install_prep_4bench.py @@ -0,0 +1,46 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Remove the Linaro wallpaper before start the benchmark test + +**URL:** None + +**Default options:** None +""" +import lava_android_test.config +import lava_android_test.testdef + +test_name = 'install_prep_4bench' + +INSTALL_STEPS_ADB_PRE = [] +ADB_SHELL_STEPS = ['rm /data/system/wallpaper_info.xml', + "echo install_prep_4bench.wallpaper: PASS"] +PATTERN = "^\s*(?P<test_case_id>[^:]+?):\s+(?P<result>(PASS|FAIL)?)\s*$" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/lava_android_test/test_definitions/instruments/__init__.py b/lava_android_test/test_definitions/instruments/__init__.py new file mode 100644 index 0000000..43e06ba --- /dev/null +++ b/lava_android_test/test_definitions/instruments/__init__.py @@ -0,0 +1,28 @@ +# copyright (C) 2012 Linaro Limited +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +This directory contains the tests that only need to run the "am instrument -w" +command on android. Please see the example.py for a reference. +Please note this is not a test that can be run. + +**URL:** None + +**Default options:** None +""" diff --git a/lava_android_test/test_definitions/instruments/example.py b/lava_android_test/test_definitions/instruments/example.py new file mode 100644 index 0000000..b5c73d0 --- /dev/null +++ b/lava_android_test/test_definitions/instruments/example.py @@ -0,0 +1,32 @@ +# copyright (C) 2012 Linaro Limited +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Example for how to add instrument tests into lava-android-test. +You can try this test with the android emulator which has this test integrated. + +**URL:** http://android.git.linaro.org/gitweb?p=platform/development.git;a=blob;f=tools/emulator/test-apps/ConnectivityTest/src/com/android/emulator/connectivity/test/ConnectivityTest.java + +**Default options:** None +""" + +cmd = ("am instrument -r -w " + "com.android.emulator.connectivity.test/" + "android.test.InstrumentationTestRunner") +RUN_ADB_SHELL_STEPS = [cmd] diff --git a/lava_android_test/test_definitions/iozone.py b/lava_android_test/test_definitions/iozone.py new file mode 100644 index 0000000..ab9a0b2 --- /dev/null +++ b/lava_android_test/test_definitions/iozone.py @@ -0,0 +1,118 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Perform the iozone test on the target device + +**URL:** http://android.git.linaro.org/gitweb?p=platform/external/iozone.git;a=summary + +**Default options:** None +""" +from lava_android_test.config import get_config +import lava_android_test.testdef +import os +import re + + +class IozoneParser(lava_android_test.testdef.AndroidTestParser): + '''Custom parser for Iozone. -b with a results file must be specified. + The results file is not parsed. However the addition of this parameter + causes an organized results report to be printed at the bottom + ''' + #used to find each report + PATTERN_REPORT = '(?P<report_name>.*?)report' + #used to determined output units + PATTERN_UNITS = 'Output is in (?P<units>\S*)' + + def real_parse(self, result_filename='stdout.log', + output_filename='stdout.log', + test_name=''): + '''Parse the results of stdout. + This requires the -b option be specified to IOZONE. + ''' + #filename = artifacts.stdout_pathname + pat_report = re.compile(self.PATTERN_REPORT) + pat_units = re.compile(self.PATTERN_UNITS) + units = '' + with open(output_filename, 'r') as fd: + lines = fd.readlines() + for i in range(0, len(lines)): + line = lines[i] + match_report = pat_report.search(line) + match_units = pat_units.search(line) + #found report. + if match_report: + ''' The results are the following format + <report name> report + reclen 1 + block_size results 1 + ''' + report_name = match_report.groupdict()['report_name' + ].replace("\"", "") + i += 1 + rclen_line = lines[i].replace("\"", "") + i += 1 + results_line = lines[i].replace("\"", "") + reclen_split = rclen_line.split() + results_split = results_line.split() + #first value is the block size + size = results_split[0] + for n in range(0, len(reclen_split)): + results = {'test_case_id': + "iozone_%sKB_%s_rclen_%s" % (report_name, + str(size), + str(reclen_split[n])), + 'result': 'pass', + 'measurement': int(results_split[n + 1]), + 'units': units} + self.results['test_results'].append(results) + elif match_units: + units = match_units.groupdict()['units'] + + +test_name = 'iozone' + +config = get_config() +curdir = os.path.realpath(os.path.dirname(__file__)) +iozone_sh_name = 'iozone.sh' +iozone_dir_path = os.path.join(curdir, 'iozone') +#copy the whole directory over +#this will alow users to place the crosscompiled izone binary +#in the folder and modify iozone.sh to remount the root fs. +iozone_dir_android_path = os.path.join(config.installdir_android, + test_name) +iozone_sh_android_path = os.path.join(iozone_dir_android_path, + iozone_sh_name) + +INSTALL_STEPS_ADB_PRE = ['push %s %s ' % (iozone_dir_path, + iozone_dir_android_path), + 'shell chmod -R 777 %s' % iozone_dir_android_path] + +ADB_SHELL_STEPS = ["%s %s" % (iozone_sh_android_path, iozone_dir_android_path)] + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = IozoneParser() +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/lava_android_test/test_definitions/iozone/iozone.sh b/lava_android_test/test_definitions/iozone/iozone.sh new file mode 100755 index 0000000..1820f86 --- /dev/null +++ b/lava_android_test/test_definitions/iozone/iozone.sh @@ -0,0 +1,14 @@ +#!/system/bin/sh +#$1 is the testing location. The -b must be specified for parser. +#the file itself does not matter as it is not used. +#The -b cause results reports to be printed to stdout. + +#uncomment the following and add cross compiled iozone to this directory. +#mount -o remount,rw / +#iozone_cmd=$1"/iozone -a -i 0 -i 2 -s 16m -V teststring -b iozone_results" + +#The original command with a -b so excel results are printed to stdout and can be parsed +iozone_cmd="iozone -a -i 0 -i 2 -s 16m -V teststring -b iozone_results" +echo execute command=${iozone_cmd} +${iozone_cmd} +echo IOZONE_RET_CODE=$? diff --git a/lava_android_test/test_definitions/memtester.py b/lava_android_test/test_definitions/memtester.py new file mode 100644 index 0000000..2ddad92 --- /dev/null +++ b/lava_android_test/test_definitions/memtester.py @@ -0,0 +1,45 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Perform the memtester test on the target device. +memtester is a utility for testing the memory subsystem in a computer to determine if it is faulty. + +**URL:** http://android.git.linaro.org/gitweb?p=platform/external/memtester.git;a=summary + +**Default options:** None +""" +import lava_android_test.testdef + +test_name = 'memtester' + +INSTALL_STEPS_ADB_PRE = [] +ADB_SHELL_STEPS = ['memtester 1M 1'] +PATTERN = "^\s*(?P<test_case_id>.*?)\s*:\s*(?P<result>\w+)\s*$" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/lava_android_test/test_definitions/methanol.py b/lava_android_test/test_definitions/methanol.py new file mode 100644 index 0000000..5785317 --- /dev/null +++ b/lava_android_test/test_definitions/methanol.py @@ -0,0 +1,65 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +The Methanol is a page load benchmarking engine. +The benchmark engine measures the overall page layouting and rendering time of the browser. +The methanol now includs test for css/canvas/smp/svg test + +**URL:** https://github.com/szeged/methanol.git + +**Default options:** None +""" + +import os +import json + +import lava_android_test.testdef + +from lava_android_test.config import get_config + +curdir = os.path.realpath(os.path.dirname(__file__)) +config = get_config() + +result_dir = config.resultsdir_android +RUN_STEPS_HOST_PRE = ["bash %s/methanol/methanol.sh $(SERIAL) $(OPTIONS)" % curdir] + +class MethanolTestParser(lava_android_test.testdef.AndroidTestParser): + + def real_parse(self, result_filename=None, output_filename='methanol_result.json', + test_name=''): + """Parse test output to gather results + Use the pattern specified when the class was instantiated to look + through the results line-by-line and find lines that match it. + Results are then stored in self.results. If a fixupdict was supplied + it is used to convert test result strings to a standard format. + """ + with open(output_filename) as stream: + test_results_data = stream.read() + test_results_json = json.loads(test_results_data) + self.results['test_results'] = test_results_json + + +inst = lava_android_test.testdef.AndroidTestInstaller() +run = lava_android_test.testdef.AndroidTestRunner(steps_host_pre=RUN_STEPS_HOST_PRE) +parser = MethanolTestParser() +testobj = lava_android_test.testdef.AndroidTest(testname="methanol", + installer=inst, runner=run, parser=parser, + org_ouput_file='/data/local/tmp/methanol/methanol_result.json') diff --git a/lava_android_test/test_definitions/methanol/methanol.sh b/lava_android_test/test_definitions/methanol/methanol.sh new file mode 100755 index 0000000..81e2598 --- /dev/null +++ b/lava_android_test/test_definitions/methanol/methanol.sh @@ -0,0 +1,327 @@ +#!/bin/bash +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +#the default ip or domain used by the client to access the server +DEFAULT_DOMAIN_IP=`ifconfig | awk -F':' '/inet addr/&&!/127.0.0.1/{split($2,_," ");print _[1]}'` +DEFAULT_BROWSER='DEFAULT' + +######################################################## +###### NOT MODIFY SOURCE OF BELOW ##### +######################################################## +THIS_FILE="$0" +methanol_git="git://github.com/szeged/methanol.git" +chrome_apk_url="http://testdata.validation.linaro.org/chrome/Chrome-latest.apk" +server_settings_file="/etc/lava/web_server/settings.conf" +result_dir_android="/data/local/tmp/methanol" +declare -a RESULTS=(); +methanol_url="/" +report_url="/cgi/save_methanol_data.py" +report_res_dir="/tmp/methanol" +target_dir="" +server_pid="" + +ADB_OPTION="" +domain_ip="${DEFAULT_DOMAIN_IP}" +browser="${DEFAULT_BROWSER}" +test_target="" + +function parse_arg(){ + serial="" + while test -n "$1"; do + case "$1" in + --browser|-b) + if [ "x$2" = "x" ]; then + echo "Error: $1 requires an argument which should be DEFAULT or CHROME" + exit 1 + fi + browser="$2" + if [ "X${browser}" != "XDEFAULT" ] && [ "X${browser}" != "XCHROME" ]; then + echo "Error: $1 requires an argument which should be DEFAULT or CHROME" + exit 1 + fi + shift 2 + ;; + --domain|-d) + if [ "x$2" = "x" ]; then + echo "Error: $1 requires an argument" + exit 1 + fi + domain_ip="$2" + shift 2 + ;; + --target|-t) + if [ "x$2" = "x" ]; then + echo "Error: $1 requires an argument" + exit 1 + fi + test_target="$2" + shift 2 + ;; + --help|-h) + show_usage + exit 0 + ;; + *) + if [ -n "${serial}" ]; then + show_usage + echo "Too many arguments, see --help for details" + exit 1 + else + serial="$1" + shift + fi + ;; + esac + done + + if [ -n "${serial}" ]; then + ADB_OPTION="-s ${serial}" + fi +} + +function show_usage(){ + echo "`basename ${THIS_FILE}` [serial_no] [-b DEFAULT|CHROME] [-d domain_ip]" +} + +function patch_sources(){ + src_root_dir=${1} + if [ -z ${src_root_dir} ]; then + return + fi + + if [ \! -d ${src_root_dir} ]; then + return + fi + + ## The following test case cannot be on android browser, so comment them out + ## Patch the engine.js + sed -i "s% + results;% + results.replace\(new RegExp('/','gm'), '_'\);%" ${src_root_dir}/engine.js + + ##Patch svg.js + sed -i s%\"svg/anim/earth.svg\",%\"svg/anim/earth.svg\"/*,% ${src_root_dir}/svg.js + sed -i s%\"svg/anim/svg.svg\"%\"svg/anim/svg.svg\"*/% ${src_root_dir}/svg.js + + ##Patch smp.js + sed -i s%\"smp/3d-terrain-demo/single/index.html\",%//\"smp/3d-terrain-demo/single/index.html\",% ${src_root_dir}/smp.js + sed -i s%\"smp/3d-terrain-demo/worker/index.html\",%//\"smp/3d-terrain-demo/worker/index.html\",% ${src_root_dir}/smp.js + sed -i s%\"smp/fire-on-water/worker/index.html\",%//\"smp/fire-on-water/worker/index.html\",% ${src_root_dir}/smp.js +} + +function deploy(){ + + if [ "${browser}" = "CHROME" ]; then + echo "wget --progress=dot -e dotbytes=1M -np -l 10 --no-check-certificate ${chrome_apk_url} -O ./Chrome-latest.apk" + wget --progress=dot -e dotbytes=1M -np -l 10 --no-check-certificate ${chrome_apk_url} -O ./Chrome-latest.apk + if [ $? -ne 0 ]; then + echo "Failed to download the chrome apk file from ${chrome_apk_url}." + cleanup + exit 1 + fi + + adb ${ADB_OPTION} uninstall com.android.chrome + + echo "adb ${ADB_OPTION} install ./Chrome-latest.apk" + adb ${ADB_OPTION} install ./Chrome-latest.apk + if [ $? -ne 0 ]; then + echo "Failed to install the Chrome browser application." + cleanup + rm -f ./Chrome-latest.apk + exit 1 + fi + rm -f ./Chrome-latest.apk + adb ${ADB_OPTION} shell am start com.android.chrome/com.google.android.apps.chrome.Main + sleep 10 + f_preferences='/data/data/com.android.chrome/shared_prefs/com.android.chrome_preferences.xml' + f_preferences_base=`basename ${f_preferences}` + owner_grp=`adb ${ADB_OPTION} shell ls -l ${f_preferences}|cut -d \ -f2` + if [ -z "${owner_grp}" ]; then + echo "Failed to get the user/group infromation of chrome preferences file." + cleanup + rm -f ./Chrome-latest.apk + exit 1 + fi + adb ${ADB_OPTION} pull ${f_preferences} ./${f_preferences_base} + sed -i '/<map>/ a\<boolean name="first_run_flow" value="true" />' ./${f_preferences_base} + adb ${ADB_OPTION} push ./${f_preferences_base} ${f_preferences} + adb ${ADB_OPTION} shell chown ${owner_grp}:${owner_grp} ${f_preferences} + chrome_pid=`adb ${ADB_OPTION} shell ps |grep -P 'chrome\s*$'|tr -s ' '|cut -d \ -f2` + if [ -n "${chrome_pid}" ]; then + adb ${ADB_OPTION} shell kill ${chrome_pid} + fi + rm -f ./${f_preferences_base} + fi + + cur_path=`pwd` + target_dir=`mktemp -u --tmpdir=${cur_path} methanol-XXX` + git clone "${methanol_git}" "${target_dir}" + if [ $? -ne 0 ];then + echo "Failed to clone the methanol source from ${methanol_git}" + cleanup + exit 1 + fi + + #patch just because some test can not be run on android + patch_sources "${target_dir}" + + url_file=`mktemp -u --tmpdir=${cur_path} url-XXX` + nohup python `dirname $0`/start_server.py "${domain_ip}" "${target_dir}" "${url_file}" &>server.log & + server_pid=$! + sleep 5 + domain_protocol=`cat ${url_file}` + if [ -z "${domain_protocol}" ]; then + echo "Cannot get the url of the temporary created server." + echo "Failed to deploy the temporary server" + cleanup + exit 1 + fi +} + +function check_url(){ + if [ -n "${report_url}" ]; then + wget -q "${domain_protocol}/${report_url}" -O /dev/null + if [ $? -ne 0 ]; then + echo "The report url(${domain_protocol}/${report_url}) cannot be accessed" + echo "Please put the save_methanol_data.py to the cgi-bin directory" + echo "of your web server, and make sure it is accessible." + cleanup + exit 1 + fi + fi + + if [ -n "${methanol_url}" ]; then + wget -q "${domain_protocol}/${methanol_url}" -O /dev/null + if [ $? -ne 0 ]; then + echo "The url(${domain_protocol}/${methanol_url}) cannot be accessed" + echo "Please clone the methanol directory to local via following command" + echo " git clone ${methanol_git}" + echo "and copy the entire directory to some place of your web server" + echo "and make sure it is accessible." + cleanup + exit 1 + fi + else + echo "Please speecify the methanol url that will be used for test." + cleanup + exit 1 + fi +} + +function wait_result(){ + if [ -n "$1" ]; then + file_path="$1" + else + return 0 + fi + + for (( i=1; ; i++ )); do + sleep 300 + if [ -f "${file_path}" ]; then + return 0 + fi + done + return 1 +} + +function test_methanol(){ + if [ -n "$1" ]; then + test_type="-${1}" + else + test_type="" + fi + + result_file=`mktemp -u --tmpdir=${report_res_dir} fire${test_type}-XXX.json` + res_basename=`basename ${result_file}` + test_url="${domain_protocol}/${methanol_url}/fire${test_type}.html" + if [ -n "${report_url}" ]; then + test_url="${test_url}?reportToUrl=${report_url}%3Fsave2file=${res_basename}" + fi + + component_default="com.android.browser/com.android.browser.BrowserActivity" + component_chrome=" com.android.chrome/com.google.android.apps.chrome.Main" + if [ "${browser}" = "CHROME" ]; then + component=${component_chrome} + else + component=${component_default} + fi + echo "adb ${ADB_OPTION} shell am start -a android.intent.action.VIEW -d ${test_url} -n ${component}" + adb ${ADB_OPTION} shell "am start -a android.intent.action.VIEW -d ${test_url} -n ${component}" + wait_result "${result_file}" + if [ $? -eq 0 ]; then + cur_path=`pwd` + cp -uvf ${result_file} ${cur_path}/${res_basename} + echo "result_file=${cur_path}/${res_basename}" + RESULTS[${#RESULTS[@]}]="${cur_path}/${res_basename}" + + rm -f ${result_file} + else + echo "Failed to get the test result of fire${test_type}.html" + #cleanup + #exit 1 + fi +} + +function cleanup(){ + echo "DO CLEAN UP" + rm -fr methanol_result.json "${RESULTS[@]}" + if [ -n "${server_pid}" ]; then + kill -9 ${server_pid} + fi + if [ -n "${target_dir}" ]; then + rm -fr "${target_dir}" + fi + if [ "${browser}" = "CHROME" ]; then + adb ${ADB_OPTION} uninstall com.android.chrome + fi +} + +function main(){ + parse_arg "$@" + + ## delete the test result for last time + adb ${ADB_OPTION} shell rm "${result_dir_android}/methanol_result.json" + + trap cleanup EXIT + + deploy + + check_url + + page_suffix='${test_target}' + if [ -n "${page_suffix}" ]; then + page_suffix="-${test_target}" + fi + echo `date`: starts to test fire${page_suffix}.html + test_methanol "${test_target}" + echo `date`: all tests completed + + echo "Merge results of file: ${RESULTS[@]}" + `dirname $0`/methanol_merge_results.py methanol_result.json "${RESULTS[@]}" + if [ $? -eq 0 ]; then + adb ${ADB_OPTION} shell mkdir ${result_dir_android} + adb ${ADB_OPTION} push methanol_result.json "${result_dir_android}/methanol_result.json" + for f in "${RESULTS[@]}"; do + adb ${ADB_OPTION} push "${f}" "${result_dir_android}" + done + echo "The result is also push to android: ${result_dir_android}/${res_basename}" + else + echo "Failed to merge the results" + fi +} +main "$@" diff --git a/lava_android_test/test_definitions/methanol/methanol_merge_results.py b/lava_android_test/test_definitions/methanol/methanol_merge_results.py new file mode 100755 index 0000000..a57c602 --- /dev/null +++ b/lava_android_test/test_definitions/methanol/methanol_merge_results.py @@ -0,0 +1,86 @@ +#!/usr/bin/python +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import re +import string +import sys + +import simplejson as json + +if len(sys.argv) < 3: + basename = os.path.basename(sys.argv[0]) + print 'Please specified the merge target file and source files like:' + print '\t %s target-result-file source-file1 source-file2 ...' + sys.exit(1) + +target_file = sys.argv[1] +test_results = [] +for f in sys.argv[2:]: + if not os.path.exists(f): + print "The file(%s) does not exist" % f + continue + + with open(f) as stream: + f_basename = os.path.basename(f) + last_hyphen_index = string.rfind(f_basename, '-') + if last_hyphen_index != -1: + file_id = f_basename[:last_hyphen_index] + else: + file_id = '' + + jobdata = stream.read() + results_data = json.loads(jobdata) + for res in results_data: + test_case_id = res.get('test_case_id') + average = res.get('average') + avg_dev = res.get('average_deviate') + units = res.get('units') + if file_id and test_case_id == 'summary': + test_case_id = '%s-summary' % file_id + test_case_id = test_case_id.replace('/', '_') + badchars = "[^a-zA-Z0-9\._-]" + test_case_id = re.sub(badchars, "", test_case_id.replace(" ", "_")) + if not units: + units = 'ms' + test_results.append({'test_case_id': '%s_avg' % test_case_id, + 'result': 'pass', + 'measurement': average, + 'units': units}) + if avg_dev: + test_results.append({ + 'test_case_id': '%s_avg_dev' % test_case_id, + 'result': 'pass', + 'measurement': avg_dev, + 'units': '%'}) + + +with open(target_file, 'w') as fd: + indent = ' ' * 2 + separators = (', ', ': ') + json.dump(test_results, fd, + use_decimal=True, + indent=indent, + separators=separators, + sort_keys=False) + +print "The result has been merged in file: %s" % target_file +sys.exit(0) diff --git a/lava_android_test/test_definitions/methanol/start_server.py b/lava_android_test/test_definitions/methanol/start_server.py new file mode 100755 index 0000000..6ca96b5 --- /dev/null +++ b/lava_android_test/test_definitions/methanol/start_server.py @@ -0,0 +1,62 @@ +#/usr/bin/python +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import sys +import CGIHTTPServer +import BaseHTTPServer + +### check parameter +if len(sys.argv) < 3: + print 'Please spsecify the ip and directory like this:' + print ' %s domain-or-ip directory-path url-file' % ( + os.path.basename(__file__)) + sys.exit(1) + +domain = sys.argv[1] +directory = sys.argv[2] +if len(sys.argv) == 4: + url_file = sys.argv[3] +else: + url_file = '' + +## change to that directory +old_dir = os.getcwd() +os.chdir(directory) + +## set the server configuration before start +cgi_handler = CGIHTTPServer.CGIHTTPRequestHandler +cgi_handler.cgi_directories.append('/cgi') +httpd = BaseHTTPServer.HTTPServer((domain, 0), cgi_handler) +url = '%s://%s:%s/' % ('http', httpd.socket.getsockname()[0], + httpd.socket.getsockname()[1]) + +## out put the url information to console and file for other script reference +print "serving at url=", url +if url_file: + with open(url_file, 'w') as stream: + stream.write(url) + print 'The information of url also have been wirtten into file(%s)' % ( + url_file) + +try: + httpd.serve_forever() +finally: + os.chdir(old_dir) diff --git a/lava_android_test/test_definitions/mmtest.py b/lava_android_test/test_definitions/mmtest.py new file mode 100644 index 0000000..985a650 --- /dev/null +++ b/lava_android_test/test_definitions/mmtest.py @@ -0,0 +1,63 @@ +# Copyright (C) 2011-2012 Linaro Limited +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Performs a test of multimedia functionality in Android by playing a variety +of different multimedia formats on Android. + +**URL:** http://android.git.linaro.org/gitweb?p=platform/frameworks/base.git;a=tree;f=media/tests/MediaFrameworkTest + +**Default options:** None +""" + +import os +import lava_android_test.testdef +from lava_android_test.utils import get_local_name +from lava_android_test.config import get_config + +test_name = 'mmtest' +config = get_config() + +site = 'http://samplemedia.linaro.org/' +local_name = get_local_name(site) +RUN_STEPS_HOST_PRE = [ + 'wget --progress=dot -e dotbytes=1M -r -np -l 10 -R csv,txt,css,html,gif,pdf %s -P %s' % (site, + local_name), + r'find %s -type f -name "index*" -exec rm -f \{\} \;' % local_name, + r'find %s -type f -name "README" -exec rm -f \{\} \;' % local_name] + +test_files_target_path = os.path.join(config.installdir_android, + test_name, local_name) +RUN_STEPS_ADB_PRE = ['push %s %s' % (local_name, test_files_target_path)] +RUN_ADB_SHELL_STEPS = ['am instrument -r -e targetDir %s \ + -w com.android.mediaframeworktest/.MediaFrameworkTestRunner' + % test_files_target_path, + 'rm -r %s' % (test_files_target_path)] + +inst = lava_android_test.testdef.AndroidTestInstaller() +run = lava_android_test.testdef.AndroidTestRunner( + steps_host_pre=RUN_STEPS_HOST_PRE, + steps_adb_pre=RUN_STEPS_ADB_PRE, + adbshell_steps=RUN_ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidInstrumentTestParser() +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/lava_android_test/test_definitions/monkey.py b/lava_android_test/test_definitions/monkey.py new file mode 100644 index 0000000..944d8ae --- /dev/null +++ b/lava_android_test/test_definitions/monkey.py @@ -0,0 +1,57 @@ +# Copyright (c) 2011 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +Performs a test of monkey functionality in Android with the monkey command + +**URL:** http://android.git.linaro.org/gitweb?p=platform/development.git;a=blob;f=cmds/monkey/monkey + +**Default options:** None +""" +import os +import lava_android_test.testdef +from lava_android_test.config import get_config + +test_name = 'monkey' +config = get_config() +curdir = os.path.realpath(os.path.dirname(__file__)) +monkey_sh_name = 'monkey.sh' +monkey_sh_path = os.path.join(curdir, 'monkey', monkey_sh_name) +monkey_sh_android_path = os.path.join(config.installdir_android, + test_name, monkey_sh_name) + +INSTALL_STEPS_ADB_PRE = ['push %s %s ' % (monkey_sh_path, + monkey_sh_android_path), + 'shell chmod 777 %s' % monkey_sh_android_path] + +ADB_SHELL_STEPS = [monkey_sh_android_path] +#PATTERN = "^(?P<test_case_id>\w+):\W+(?P<measurement>\d+\.\d+)" +PATTERN = "## Network stats: elapsed time=(?P<measurement>\d+)ms" +FAILURE_PATTERNS = [] +#FAILURE_PATTERNS = ['\*\* Monkey aborted due to error.', +# '\*\* System appears to have crashed'] + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN, + appendall={'units': 'ms'}, failure_patterns=FAILURE_PATTERNS) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, runner=run, parser=parser) diff --git a/lava_android_test/test_definitions/monkey/monkey.sh b/lava_android_test/test_definitions/monkey/monkey.sh new file mode 100755 index 0000000..c774680 --- /dev/null +++ b/lava_android_test/test_definitions/monkey/monkey.sh @@ -0,0 +1,6 @@ +#!/system/bin/sh +#monkey_cmd="monkey -s 1 --pct-touch 10 --pct-motion 20 --pct-nav 20 --pct-majornav 30 --pct-appswitch 20 --throttle 500 2147483647" +monkey_cmd="monkey -s 1 --pct-touch 10 --pct-motion 20 --pct-nav 20 --pct-majornav 30 --pct-appswitch 20 --throttle 500 500" +echo execute command=${monkey_cmd} +${monkey_cmd} +echo MONKEY_RET_CODE=$? diff --git a/lava_android_test/test_definitions/monkey_long_run.py b/lava_android_test/test_definitions/monkey_long_run.py new file mode 100644 index 0000000..d3d448d --- /dev/null +++ b/lava_android_test/test_definitions/monkey_long_run.py @@ -0,0 +1,78 @@ +# Copyright (c) 2011 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +Performs a test of monkey functionality in Android with some +black list packages provided. + +**URL:** http://android.git.linaro.org/gitweb?p=platform/development.git;a=blob;f=cmds/monkey/monkey + +**Default options:** "generic_target" +""" +import os +import lava_android_test.testdef +from lava_android_test.config import get_config + +test_name = 'monkey_long_run' +config = get_config() +curdir = os.path.realpath(os.path.dirname(__file__)) +monkey_sh_name = 'monkey_long_run.sh' +monkey_sh_path = os.path.join(curdir, test_name, monkey_sh_name) +monkey_sh_android_path = os.path.join(config.installdir_android, + test_name, monkey_sh_name) +monkey_blacklist_name = 'package_black_list' +monkey_blacklist_path = os.path.join(curdir, test_name, monkey_blacklist_name) +monkey_blacklist_android_path = os.path.join(config.installdir_android, + test_name, monkey_blacklist_name) +juice_monkey_blacklist_name = 'juice_package_black_list' +juice_monkey_blacklist_path = os.path.join(curdir, test_name, + juice_monkey_blacklist_name) +juice_monkey_blacklist_android_path = os.path.join(config.installdir_android, + test_name, + juice_monkey_blacklist_name) + +DEFAULT_OPTIONS = 'generic_target' +INSTALL_STEPS_ADB_PRE = ['push %s %s ' % (monkey_sh_path, + monkey_sh_android_path), + 'push %s %s ' % (monkey_blacklist_path, + monkey_blacklist_android_path), + 'push %s %s ' % (juice_monkey_blacklist_path, + juice_monkey_blacklist_android_path), + 'shell chmod 777 %s' % monkey_sh_android_path] + +ADB_SHELL_STEPS = ['%s $(OPTIONS) %s %s' % (monkey_sh_android_path, + juice_monkey_blacklist_android_path, + monkey_blacklist_android_path)] +#PATTERN = "^(?P<test_case_id>\w+):\W+(?P<measurement>\d+\.\d+)" +PATTERN = "## Network stats: elapsed time=(?P<measurement>\d+)ms" +FAILURE_PATTERNS = ['\*\* Monkey aborted due to error.', + '\*\* System appears to have crashed'] + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN, + appendall={'units': 'ms'}, failure_patterns=FAILURE_PATTERNS) +testobj = lava_android_test.testdef.AndroidTest( + testname=test_name, + installer=inst, + runner=run, + parser=parser, + default_options=DEFAULT_OPTIONS) diff --git a/lava_android_test/test_definitions/monkey_long_run/juice_package_black_list b/lava_android_test/test_definitions/monkey_long_run/juice_package_black_list new file mode 100644 index 0000000..8899c05 --- /dev/null +++ b/lava_android_test/test_definitions/monkey_long_run/juice_package_black_list @@ -0,0 +1,7 @@ +com.android.browser +com.android.development +com.android.quicksearchbox +com.android.speechrecorder +com.android.connectivitymanagertest +org.linaro.glmark2 +com.android.gallery3d diff --git a/lava_android_test/test_definitions/monkey_long_run/monkey_long_run.sh b/lava_android_test/test_definitions/monkey_long_run/monkey_long_run.sh new file mode 100755 index 0000000..afdc249 --- /dev/null +++ b/lava_android_test/test_definitions/monkey_long_run/monkey_long_run.sh @@ -0,0 +1,13 @@ +#!/system/bin/sh +#monkey_cmd="monkey -s 1 --pct-touch 10 --pct-motion 20 --pct-nav 20 --pct-majornav 30 --pct-appswitch 20 --throttle 500 2147483647" +if [ $1 == 'juice' ]; then +monkey_cmd="monkey -s 1 --pct-touch 10 --pct-motion 20 --pct-nav 20 --pct-majornav 30 --pct-appswitch 20 --throttle 500 --pkg-blacklist-file $2 30000" +elif [ $1 == 'juno' ]; then +monkey_cmd="monkey -s 1 --pct-touch 10 --pct-motion 20 --pct-nav 20 --pct-majornav 30 --pct-appswitch 20 --throttle 500 --pkg-blacklist-file /data/juno_monkey_blacklist 30000" +else +monkey_cmd="monkey -s 1 --pct-touch 10 --pct-motion 20 --pct-nav 20 --pct-majornav 30 --pct-appswitch 20 --throttle 500 --pkg-blacklist-file $3 25000" +fi + +echo execute command=${monkey_cmd} +${monkey_cmd} +echo MONKEY_RET_CODE=$? diff --git a/lava_android_test/test_definitions/monkey_long_run/package_black_list b/lava_android_test/test_definitions/monkey_long_run/package_black_list new file mode 100644 index 0000000..0fc6125 --- /dev/null +++ b/lava_android_test/test_definitions/monkey_long_run/package_black_list @@ -0,0 +1,2 @@ +com.android.camera +com.android.connectivitymanagertest diff --git a/lava_android_test/test_definitions/pm_qa.py b/lava_android_test/test_definitions/pm_qa.py new file mode 100644 index 0000000..bf2cff8 --- /dev/null +++ b/lava_android_test/test_definitions/pm_qa.py @@ -0,0 +1,58 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Linaro PM-QA tests for platforms + +**URL:** https://git.linaro.org/gitweb?p=tools/pm-qa.git;a=summary + +**Default options:** /data/benchmark/pm-qa +""" + +import os +import lava_android_test.testdef +from lava_android_test.config import get_config + +DEFAULT_OPTIONS = '/data/benchmark/pm-qa' +test_name = 'pm_qa' +config = get_config() +curdir = os.path.realpath(os.path.dirname(__file__)) +test_sh_name = 'pm-qa.sh' +test_sh_path = os.path.join(curdir, test_name, test_sh_name) +test_sh_android_path = os.path.join(config.installdir_android, + test_name, test_sh_name) + +INSTALL_STEPS_ADB_PRE = ['push %s %s ' % (test_sh_path, + test_sh_android_path), + 'shell chmod 777 %s' % test_sh_android_path] + +ADB_SHELL_STEPS = ["%s $(OPTIONS)" % test_sh_android_path] +PATTERN = "^\s*(?P<test_case_id>\w+)=(?P<result>\w+)\s*$" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser, + default_options=DEFAULT_OPTIONS) diff --git a/lava_android_test/test_definitions/pm_qa/pm-qa.sh b/lava_android_test/test_definitions/pm_qa/pm-qa.sh new file mode 100755 index 0000000..a570d8e --- /dev/null +++ b/lava_android_test/test_definitions/pm_qa/pm-qa.sh @@ -0,0 +1,63 @@ +#!/system/bin/sh + +scripts_dir=$1 && shift +if [ -z "${scripts_dir}" ];then + scripts_dir="/data/benchmark/pm-qa" +fi +test_func(){ + if [ ! -d "${scripts_dir}" ]; then + echo "pm_qa=fail" + exit + fi + + mkdir /data/bin/ + cd /data/bin + + busybox ln -s -f /system/bin/busybox awk + busybox ln -s -f /system/bin/busybox basename + busybox ln -s -f /system/bin/busybox chmod + busybox ln -s -f /system/bin/busybox chown + busybox ln -s -f /system/bin/busybox cp + busybox ln -s -f /system/bin/busybox diff + busybox ln -s -f /system/bin/busybox find + busybox ln -s -f /system/bin/busybox grep + busybox ln -s -f /system/bin/busybox rm + busybox ln -s -f /system/bin/busybox seq + busybox ln -s -f /system/bin/busybox taskset + busybox ln -s -f /system/bin/busybox tee + busybox ln -s -f /system/bin/busybox printf + busybox ln -s -f /system/bin/busybox wc + + busybox ln -s -f /system/bin/fake_command command + busybox ln -s -f /system/bin/fake_sudo sudo + busybox ln -s -f /system/bin/fake_udevadm udevadm + + export PATH=/data/bin:$PATH + + cd "${scripts_dir}" + + pwd_dir=$PWD + echo $pwd + tests_dirs="cpuidle cpufreq cpuhotplug sched_mc suspend thermal utils" + + for dir in $tests_dirs; do + subDir=${pwd_dir}/$dir + if [ -d $subDir ]; then + cd $subDir + else + continue + fi + + echo `pwd` + for file in `find . -name "*.sh"`; do + path=$file + echo $path + /system/bin/sh $path + done + cd .. + done + + echo "pm_qa=pass" +} + +test_func diff --git a/lava_android_test/test_definitions/sched_tests.py b/lava_android_test/test_definitions/sched_tests.py new file mode 100644 index 0000000..df91439 --- /dev/null +++ b/lava_android_test/test_definitions/sched_tests.py @@ -0,0 +1,49 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Drives scheduler test scripts that are pre-intalled on Linaro Android +builds of big.LITTLE + +**URL:** https://linaro-private.git.linaro.org/gitweb?p=bL_tests/sched_tests.git + +**Default options:** None +""" + +import lava_android_test.testdef + +test_name = 'sched_tests' + +DEFAULT_OPTIONS='output all' + +INSTALL_STEPS_ADB_PRE = [] +ADB_SHELL_STEPS = ['run_sched_test $(OPTIONS)'] +PATTERN = "(?P<test_case_id>.*-*)\s+:\s+(?P<result>(SUCCESS|FAILED))" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser, + default_options=DEFAULT_OPTIONS) diff --git a/lava_android_test/test_definitions/shells/__init__.py b/lava_android_test/test_definitions/shells/__init__.py new file mode 100644 index 0000000..7c13426 --- /dev/null +++ b/lava_android_test/test_definitions/shells/__init__.py @@ -0,0 +1,33 @@ +# copyright (C) 2012 Linaro Limited +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +This directory contains the tests that only need to run the android shell +scripts that stored under this directory. +Please see the example.sh for a reference. +Please note this is not a test that can be run. + +**URL:** None + +**Default options:** None +""" + + +import os +curdir = os.path.dirname(os.path.realpath(__file__)) diff --git a/lava_android_test/test_definitions/shells/binder.sh b/lava_android_test/test_definitions/shells/binder.sh new file mode 100755 index 0000000..d3fb43d --- /dev/null +++ b/lava_android_test/test_definitions/shells/binder.sh @@ -0,0 +1,13 @@ +#!/system/bin/sh + +chmod 777 /data/nativebenchmark/binderAddInts +if [ -z "$1" ]; then + /data/nativebenchmark/binderAddInts -n 10 +else + /data/nativebenchmark/binderAddInts -n $1 +fi +if [ $? -eq 0 ]; then + echo "binder=pass"; +else + echo "binder=fail"; +fi diff --git a/lava_android_test/test_definitions/shells/custom.sh b/lava_android_test/test_definitions/shells/custom.sh new file mode 100755 index 0000000..4b78632 --- /dev/null +++ b/lava_android_test/test_definitions/shells/custom.sh @@ -0,0 +1,14 @@ +#!/system/bin/sh + +echo "The custom shell will be run is:" +echo " $@" +echo "Shell starts:" +$@ +echo "Shell ends:" +RET=$? +echo "The exit status is: $RET" +if [ $? -ne 0 ]; then + echo "custom=fail" +else + echo "custom=pass" +fi diff --git a/lava_android_test/test_definitions/shells/dalvik-vm-unit-tests.sh b/lava_android_test/test_definitions/shells/dalvik-vm-unit-tests.sh new file mode 100755 index 0000000..65ca818 --- /dev/null +++ b/lava_android_test/test_definitions/shells/dalvik-vm-unit-tests.sh @@ -0,0 +1,12 @@ +#!/system/bin/sh +# +# Dalvik-VM unit tests. +# + +chmod 777 /data/nativetest/dalvik-vm-unit-tests/dalvik-vm-unit-tests +/data/nativetest/dalvik-vm-unit-tests/dalvik-vm-unit-tests +if [ $? -eq 0 ]; then + echo "dalvik-vm-unit-tests=pass" +else + echo "dalvik-vm-unit-tests=fail" +fi diff --git a/lava_android_test/test_definitions/shells/example.sh b/lava_android_test/test_definitions/shells/example.sh new file mode 100755 index 0000000..7e7e858 --- /dev/null +++ b/lava_android_test/test_definitions/shells/example.sh @@ -0,0 +1,4 @@ +#!/system/bin/sh + +echo "test_case_fail=fail" +echo "test_case_pass=pass"
\ No newline at end of file diff --git a/lava_android_test/test_definitions/skia.py b/lava_android_test/test_definitions/skia.py new file mode 100644 index 0000000..8edbaee --- /dev/null +++ b/lava_android_test/test_definitions/skia.py @@ -0,0 +1,89 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Runs the skia benchmark to test 2D graphics performance. + +**URL:** https://sites.google.com/site/skiadocs/ + +**Default options:** None +""" + +import re +import lava_android_test.testdef + +test_name = 'skia' + +DEFAULT_OPTIONS = '1000' + +INSTALL_STEPS_ADB_PRE = [] +# Skia can do many more benchmarks, but it becomes almost too much data +# to make a nice chart for. The -match limits the ones we run +ADB_SHELL_STEPS = ['logcat -c', + 'skia_bench -repeat $(OPTIONS) -timers w -config 565 -match bitmap', + 'skia_bench -repeat $(OPTIONS) -timers w -config 565 -match rects', + 'skia_bench -repeat $(OPTIONS) -timers w -config 565 -match repeat', + 'logcat -d -s "skia:*"'] + + +class SkiaTestParser(lava_android_test.testdef.AndroidTestParser): + + def parse(self, result_filename=None, output_filename=None, + test_name=test_name): + pat_test = re.compile(r'running bench \[.*?\]\W+(?P<test>\w+)\W+$') + pat_type = re.compile( + r'\d+\):\W+(?P<type>\w+):\W+msecs =\W+(?P<time>\d+.\d+)') + + test = None + with open(output_filename, 'r') as stream: + for lineno, line in enumerate(stream, 1): + match = pat_test.search(line) + if match: + test = match.group('test') + else: + match = pat_type.search(line) + if match: + data = {} + data['test_case_id'] = "%s_%s" % (test, + match.group('type')) + data['measurement'] = match.group('time') + data['result'] = 'pass' + data['units'] = 'ms' + data['log_filename'] = result_filename + data['log_lineno'] = lineno + self.results['test_results'].append(data) + + if self.fixupdict: + self.fixresults(self.fixupdict) + if self.appendall: + self.appendtoall(self.appendall) + self.fixmeasurements() + self.fixids() + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = SkiaTestParser() +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser, + default_options=DEFAULT_OPTIONS) diff --git a/lava_android_test/test_definitions/sleep.py b/lava_android_test/test_definitions/sleep.py new file mode 100644 index 0000000..faf39ad --- /dev/null +++ b/lava_android_test/test_definitions/sleep.py @@ -0,0 +1,48 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Action for sleeping some time between test actions + +**URL:** None + +**Default options:** None +""" +import lava_android_test.config +import lava_android_test.testdef + +test_name = 'sleep' + +DEFAULT_OPTIONS = '10' + +INSTALL_STEPS_ADB_PRE = [] +ADB_SHELL_STEPS = ['sleep $(OPTIONS); echo sleep_$(OPTIONS): PASS'] +PATTERN = "^\s*(?P<test_case_id>[^:]+?):\s+(?P<result>(PASS|FAIL)?)\s*$" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser, + default_options=DEFAULT_OPTIONS) diff --git a/lava_android_test/test_definitions/task_placement.py b/lava_android_test/test_definitions/task_placement.py new file mode 100644 index 0000000..04fe252 --- /dev/null +++ b/lava_android_test/test_definitions/task_placement.py @@ -0,0 +1,49 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Drives task placement scripts that are pre-intalled on Linaro Android +builds of big.LITTLE + +**URL:** https://linaro-private.git.linaro.org/gitweb?p=bL_tests/task-placement-tests.git + +**Default options:** None +""" + +import lava_android_test.testdef + +test_name = 'task_placement' + +DEFAULT_OPTIONS='' + +INSTALL_STEPS_ADB_PRE = [] +ADB_SHELL_STEPS = ['run_all_task_placement_tests.sh $(OPTIONS)'] +PATTERN = "(?P<test_case_id>.*-*)\s+:\s+(?P<result>(PASS|FAIL))" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser, + default_options=DEFAULT_OPTIONS) diff --git a/lava_android_test/test_definitions/tjbench.py b/lava_android_test/test_definitions/tjbench.py new file mode 100644 index 0000000..f86f3d6 --- /dev/null +++ b/lava_android_test/test_definitions/tjbench.py @@ -0,0 +1,140 @@ +# Copyright (c) 2011-2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Tests the performance of libjpegturbo + +**URL:** http://sourceforge.net/projects/libjpeg-turbo/ + +**Default options:** None +""" + +import os +import re +import lava_android_test.testdef +from lava_android_test.config import get_config + +test_name = 'tjbench' +config = get_config() +curdir = os.path.realpath(os.path.dirname(__file__)) +ppm_file_name = 'nightshot_iso_100.ppm' +ppm_url = ("http://testdata.validation.linaro.org/tjbench/" + "nightshot_iso_100.ppm") +ppm_temp_path = os.path.join(config.tempdir_host, ppm_file_name) +ppm_android_path = os.path.join(config.tempdir_android, test_name, + ppm_file_name) +ppm_tmpfs_path = os.path.join('/data/local/tmp/mytmpfs', ppm_file_name) +INSTALL_STEPS_HOST_PRE = ['wget --no-check-certificate -q "%s" -O ./%s' % ( + ppm_url, ppm_file_name)] +INSTALL_STEPS_ADB_PRE = ['push %s %s' % (ppm_temp_path, ppm_android_path)] + +RUN_STEPS_ADB_SHELL = ['mkdir /data/local/tmp/mytmpfs', + 'mount -t tmpfs -o mode=777 tmpfs /data/local/tmp/mytmpfs', + 'dd if=%s of=%s' % (ppm_android_path, ppm_tmpfs_path), + 'tjbench %s 95 -rgb -quiet scale 1/2' % ppm_tmpfs_path, + 'tjbench %s 95 -rgb -quiet' % ppm_tmpfs_path, + 'umount /data/local/tmp/mytmpfs', + 'rmdir /data/local/tmp/mytmpfs'] + + +class TjbenchTestParser(lava_android_test.testdef.AndroidTestParser): + + def parse(self, result_filename='stdout.log', output_filename='stdout.log', + test_name=''): + """Parse test output to gather results + Use the pattern specified when the class was instantiated to look + through the results line-by-line and find lines that match it. + Results are then stored in self.results. If a fixupdict was supplied + it is used to convert test result strings to a standard format. + """ + try: + unit_pat = re.compile( + r'^\s*All performance values in (?P<units>\S+)\s*$') + measure_pat = re.compile( + ('^\s*(?P<format>\S+)\s+\S+\s+(?P<subsamp>\S+)\s+' + '(?P<qual>\d+)\s+\d+\s+\d+\s+(?P<comp_perf>[\d\.]+)\s+' + '(?P<comp_ratio>[\d\.]+)\s+(?P<dcomp_perf>[\d\.]+)\s*$') + ) + except Exception as strerror: + raise RuntimeError( + "AndroidTestParser - Invalid regular expression '%s' - %s" % ( + self.pattern, strerror)) + units = None + prefix_hash = {} + with open(output_filename, 'r') as stream: + for lineno, line in enumerate(stream, 1): + if units is None: + match = unit_pat.search(line) + if not match: + continue + else: + units = match.group('units') + + match = measure_pat.search(line) + if match: + tmpdata = match.groupdict() + test_case_prefix = '%s_%s_%s' % (tmpdata['format'], + tmpdata['subsamp'], + tmpdata['qual']) + if not prefix_hash.get(test_case_prefix): + prefix_hash[test_case_prefix] = True + test_case_prefix = '%s_%s' % (test_case_prefix, + 'scale_half') + common_data = {'log_filename': result_filename, + 'log_lineno': lineno, + 'result': 'pass' + } + comp_perf = {'test_case_id': '%s_%s' % (test_case_prefix, + 'comp_perf'), + 'units': units, + 'measurement': tmpdata['comp_perf'] + } + comp_perf.update(common_data) + comp_ratio = {'test_case_id': '%s_%s' % (test_case_prefix, + 'comp_ratio'), + 'units': '%', + 'measurement': tmpdata['comp_ratio'] + } + comp_ratio.update(common_data) + dcomp_perf = {'test_case_id': '%s_%s' % (test_case_prefix, + 'dcomp_perf'), + 'units': units, + 'measurement': tmpdata['dcomp_perf'] + } + dcomp_perf.update(common_data) + self.results['test_results'].extend([comp_perf, comp_ratio, + dcomp_perf]) + if self.fixupdict: + self.fixresults(self.fixupdict) + if self.appendall: + self.appendtoall(self.appendall) + self.fixmeasurements() + self.fixids(test_name=test_name) + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_host_pre=INSTALL_STEPS_HOST_PRE, + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=RUN_STEPS_ADB_SHELL) +parser = TjbenchTestParser() +testobj = lava_android_test.testdef.AndroidTest(testname="tjbench", + installer=inst, + runner=run, + parser=parser) diff --git a/lava_android_test/test_definitions/usbhardware.py b/lava_android_test/test_definitions/usbhardware.py new file mode 100644 index 0000000..8a2a796 --- /dev/null +++ b/lava_android_test/test_definitions/usbhardware.py @@ -0,0 +1,56 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Ensures USB is enabled on the device by checking /sys entries + +**URL:** None + +**Default options:** None +""" + +import os +import lava_android_test.testdef +from lava_android_test.config import get_config + +test_name = 'usbhardware' +config = get_config() +curdir = os.path.realpath(os.path.dirname(__file__)) +test_sh_name = 'usbhardware.sh' +test_sh_path = os.path.join(curdir, test_name, test_sh_name) +test_sh_android_path = os.path.join(config.installdir_android, + test_name, test_sh_name) + +INSTALL_STEPS_ADB_PRE = ['push %s %s ' % (test_sh_path, + test_sh_android_path), + 'shell chmod 777 %s' % test_sh_android_path] + +ADB_SHELL_STEPS = [test_sh_android_path] +PATTERN = "^\s*(?P<test_case_id>\w+)=(?P<result>\w+)\s*$" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/lava_android_test/test_definitions/usbhardware/usbhardware.sh b/lava_android_test/test_definitions/usbhardware/usbhardware.sh new file mode 100755 index 0000000..d7e8f7d --- /dev/null +++ b/lava_android_test/test_definitions/usbhardware/usbhardware.sh @@ -0,0 +1,13 @@ +#!/system/bin/sh + +test_func(){ + if [ ! -f /sys/class/android_usb/android0/state ]; then + echo "usbhardware=fail" + exit + fi + + cat /sys/class/android_usb/android0/state + echo "usbhardware=pass" +} + +test_func diff --git a/lava_android_test/test_definitions/v8.py b/lava_android_test/test_definitions/v8.py new file mode 100644 index 0000000..e017f00 --- /dev/null +++ b/lava_android_test/test_definitions/v8.py @@ -0,0 +1,53 @@ +# Copyright (c) 2012 Linaro + +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Performs the v8 benchmark on Android and returns the metrics + +**URL:** http://v8.googlecode.com/svn/data/benchmarks/v5/run.html + +**Default options:** None +""" + + +import lava_android_test.config +import lava_android_test.testdef + +test_name = 'v8' + +INSTALL_STEPS_ADB_PRE = [] +adb_shell = ('"' + 'cd /data/benchmark/v8;' + 'if which v8shell 2>/dev/null 1>/dev/null;' + 'then v8shell run.js; ' + 'else d8 run.js; fi' + '"') +ADB_SHELL_STEPS = [adb_shell] +PATTERN = "^(?P<test_case_id>.*?):\s+(?P<measurement>[\d.]+)\s*$" + +inst = lava_android_test.testdef.AndroidTestInstaller( + steps_adb_pre=INSTALL_STEPS_ADB_PRE) +run = lava_android_test.testdef.AndroidTestRunner( + adbshell_steps=ADB_SHELL_STEPS) +parser = lava_android_test.testdef.AndroidTestParser(PATTERN) +testobj = lava_android_test.testdef.AndroidTest(testname=test_name, + installer=inst, + runner=run, + parser=parser) diff --git a/lava_android_test/testdef.py b/lava_android_test/testdef.py new file mode 100644 index 0000000..0cb97aa --- /dev/null +++ b/lava_android_test/testdef.py @@ -0,0 +1,771 @@ +# Copyright (C) 2010-2012 Linaro Limited +# +# Author: Linaro Validation Team <linaro-dev@lists.linaro.org> +# +# This file is part of LAVA Android Test. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import base64 +import hashlib +import logging +import os +import re +import string +import time +import tempfile +import decimal +import zipfile + +from datetime import datetime +from uuid import uuid4 + +from lava_android_test.adb import ADB +from lava_android_test.api import ITest +from lava_android_test.config import get_config +from lava_android_test.utils import write_file, geturl +from lava_android_test import hwprofile, swprofile +from linaro_dashboard_bundle.io import DocumentIO + + +class Attachment(object): + + def __init__(self, pathname=None, mime_type=None): + self.pathname = pathname + self.mime_type = mime_type + + def copy_to_result_dir(self, adb=None, resultsdir=None): + """ + Copy the file specified by the pathname to result + directory of this time test, beacuse some test will + generate the result to the same path file. + And Please Note that pathname must be the absolute + path in the device. + """ + if (not self.pathname) or (not self.pathname.startswith('/')): + return + if not resultsdir: + return + if not adb: + adb = ADB() + if not adb.exists(resultsdir): + adb.makedirs(resultsdir) + ret_code = adb.copy(self.pathname, os.path.join(resultsdir, + os.path.basename(self.pathname))) + if ret_code != 0: + raise RuntimeError( + "Failed to copy file '%s' to '%s' on device(%s)" % + (self.pathname, resultsdir, adb.get_serial())) + + def generate_bundle(self, adb=None, resultsdir=None): + data_bundle = {} + if not self.pathname: + return data_bundle + if not adb: + adb = ADB() + config = get_config() + basename = os.path.basename(self.pathname) + android_path = os.path.join(resultsdir, basename) + if adb.exists(android_path): + tmp_path = os.path.join(config.tempdir_host, basename) + adb.pull(android_path, tmp_path) + with open(tmp_path, 'rb') as stream: + data = stream.read() + if data: + data_bundle = {"pathname": basename, + "mime_type": self.mime_type, + "content": base64.standard_b64encode(data)} + os.unlink(tmp_path) + return data_bundle + + +class AndroidTest(ITest): + """Base class for defining tests. + + This can be used by test definition files to create an object that + contains the building blocks for installing tests, running them, + and parsing the results. + + testname - name of the test or test suite + version - version of the test or test suite + installer - AbrekInstaller instance to use + runner - AbrekRunner instance to use + parser - AbrekParser instance to use + """ + adb = ADB() + default_attachments = [ + Attachment(pathname="stderr.log", mime_type="text/plain"), + Attachment(pathname="stdout.log", mime_type="text/plain"), + Attachment(pathname="screencap.png", mime_type="image/png"), + Attachment(pathname="tombstones.zip", mime_type="application/zip") + ] + + def setadb(self, adb=None): + self.adb = adb + + def getadb(self): + return self.adb + + def __init__(self, testname, version="", installer=None, runner=None, + parser=None, default_options=None, + org_ouput_file='stdout.log', + attachments=[]): + self.testname = testname + self.version = version + self.installer = installer + self.runner = runner + self.parser = parser + self.default_options = default_options + self.org_ouput_file = org_ouput_file + self.origdir = os.path.abspath(os.curdir) + self.attachments = self.default_attachments + if self.org_ouput_file and (self.org_ouput_file != "stdout.log"): + self.attachments.append( + Attachment(pathname=self.org_ouput_file, + mime_type="text/plain")) + if attachments: + self.attachments.extend(attachments) + + def set_runner(self, runner=None): + self.runner = runner + + def set_parser(self, parser=None): + self.parser = parser + + def install(self, install_options=None): + """Install the test suite. + + This creates an install directory under the user's XDG_DATA_HOME + directory to mark that the test is installed. The installer's + install() method is then called from this directory to complete any + test specific install that may be needed. + """ + if not self.installer: + raise RuntimeError("no installer defined for '%s'" % + self.testname) + self.installer.setadb(self.adb) + config = get_config() + if not os.path.exists(config.tempdir_host): + os.makedirs(config.tempdir_host) + os.chdir(config.tempdir_host) + installdir = os.path.join(config.installdir_android, self.testname) + if self.adb.exists(installdir): + raise RuntimeError("%s is already installed" % self.testname) + ret_code = self.adb.makedirs(installdir) + if ret_code != 0: + raise RuntimeError( + "Failed to create directory(%s) for test(%s)" % + (installdir, self.testname)) + + if install_options is not None: + self.adb.shell('echo "%s" > %s/install_options' % + (install_options, installdir)) + try: + self.installer.install(install_options) + except Exception as e: + self.uninstall() + raise RuntimeError( + "Failed to install test(%s):%s" % (self.testname, e)) + finally: + os.chdir(self.origdir) + + def uninstall(self): + """Uninstall the test suite. + + Uninstalling just recursively removes the test specific directory + under the user's XDG_DATA_HOME directory. This will both mark + the test as removed, and clean up any files that were downloaded + or installed under that directory. Dependencies are intentionally + not removed by this. And others installed files won't be removed too. + """ + config = get_config() + path = os.path.join(config.installdir_android, self.testname) + if self.adb.exists(path): + self.adb.rmtree(path) + + def _add_install_options(self, bundle, config): + optionfile = "%s/%s/install_options" % (config.installdir_android, + self.testname) + if self.adb.exists(optionfile): + output = self.adb.run_adb_cmd('shell cat %s' % optionfile)[1] + bundle['test_runs'][0]['attributes']['install_options'] = output[0] + + def _savetestdata(self, analyzer_assigned_uuid, run_options=""): + config = get_config() + TIMEFORMAT = '%Y-%m-%dT%H:%M:%SZ' + bundle = { + 'format': config.bundle_format, + 'test_runs': [ + { + 'analyzer_assigned_uuid': analyzer_assigned_uuid, + 'analyzer_assigned_date': + self.runner.starttime.strftime(TIMEFORMAT), + 'time_check_performed': False, + 'attributes':{}, + 'test_id': self.testname, + 'test_results':[], + 'attachments':[], + 'hardware_context': hwprofile.get_hardware_context(self.adb), + 'software_context': swprofile.get_software_context(self.adb) + } + ] + } + if run_options: + bundle['test_runs'][0]['attributes']['run_options'] = run_options + self._add_install_options(bundle, config) + filename_host = os.path.join(config.tempdir_host, 'testdata.json') + write_file(DocumentIO.dumps(bundle), filename_host) + filename_target = os.path.join(self.resultsdir, 'testdata.json') + self.adb.push(filename_host, filename_target) + + def run(self, quiet=False, run_options=None): + if not self.runner: + raise RuntimeError("no test runner defined for '%s'" % + self.testname) + if not run_options: + run_options = self.default_options + + self.runner.setadb(self.adb) + config = get_config() + if not os.path.exists(config.tempdir_host): + os.mkdir(config.tempdir_host) + os.chdir(config.tempdir_host) + resultname = (self.testname + + str(time.mktime(datetime.utcnow().timetuple()))) + self.resultsdir = os.path.join(config.resultsdir_android, resultname) + self.adb.makedirs(self.resultsdir) + self.runner.run(self.resultsdir, run_options=run_options) + self._gather_tombstones(self.resultsdir) + self._copyattachments(self.resultsdir) + self._screencap(self.resultsdir) + self._savetestdata(str(uuid4()), run_options=run_options) + result_id = os.path.basename(self.resultsdir) + print("ANDROID TEST RUN COMPLETE: Result id is '%s'" % result_id) + os.chdir(self.origdir) + return result_id + + def _screencap(self, resultsdir): + target_path = '/system/bin/screenshot' + self.adb.shell('%s %s' % (target_path, os.path.join(resultsdir, + 'screencap.png'))) + + def _gather_tombstones(self, resultsdir): + """ + Extension of the generate bundle function. + Grabs the tombstones and appends them to the bundle. + """ + config = get_config() + tombstone_path = '/data/tombstones' + tombstone_zip = os.path.join(config.tempdir_host, 'tombstones.zip') + if self.adb.exists(tombstone_path): + tmp_path = os.path.join(config.tempdir_host, 'tombstones') + self.adb.pull(tombstone_path, tmp_path) + self.adb.shell("rm -R " + tombstone_path) + zipf = zipfile.ZipFile(tombstone_zip, mode='w') + for rootdir, dirs, files in os.walk(tmp_path): + for f in files: + zipf.write(os.path.join(rootdir, f), arcname=f) + zipf.close() + self.adb.push(tombstone_zip, os.path.join(resultsdir, + 'tombstones.zip')) + os.unlink(tombstone_zip) + + def _copyattachments(self, resultsdir): + for attachment in self.attachments: + attachment.copy_to_result_dir(adb=self.adb, resultsdir=resultsdir) + + def parse(self, resultname): + if not self.parser: + raise RuntimeError("no test parser defined for '%s'" % + self.testname) + output_filename = os.path.basename(self.org_ouput_file) + config = get_config() + os.chdir(config.tempdir_host) + resultsdir_android = os.path.join(config.resultsdir_android, + resultname) + result_filename_android = os.path.join(resultsdir_android, + output_filename) + result_filename_host_temp = tempfile.mkstemp(prefix=output_filename, + dir=config.tempdir_host)[1] + self.adb.pull(result_filename_android, result_filename_host_temp) + self.parser.parse(output_filename, + output_filename=result_filename_host_temp, + test_name=self.testname) + os.remove(result_filename_host_temp) + os.chdir(self.origdir) + + +class AndroidTestInstaller(object): + + adb = ADB() + + """Base class for defining an installer object. + + This class can be used as-is for simple installers, or extended for more + advanced funcionality. + + steps_host - list of steps to be executed on host + steps_android - list of steps to be executed on android + url - location from which the test suite should be downloaded + md5 - md5sum to check the integrety of the download + """ + def __init__(self, steps_host_pre=[], steps_adb_pre=[], apks=[], + steps_adb_post=[], steps_host_post=[], + url=None, md5=None, **kwargs): + self.steps_host_pre = steps_host_pre + self.steps_adb_pre = steps_adb_pre + self.apks = apks + self.steps_adb_post = steps_adb_post + self.steps_host_post = steps_host_post + self.url = url + self.md5 = md5 + + def _download(self): + """Download the file specified by the url and check the md5. + Returns the path and filename if successful, otherwise return None + """ + if not self.url: + return 0 + config = get_config() + filename = geturl(self.url, config.tempdir_host) + #If the file does not exist, then the download was not successful + if not os.path.exists(filename): + return None + if self.md5: + checkmd5 = hashlib.md5() + with open(filename, 'rb') as fd: + data = fd.read(0x10000) + while data: + checkmd5.update(data) + data = fd.read(0x10000) + if checkmd5.hexdigest() != self.md5: + raise RuntimeError("Unexpected md5sum downloading %s" % + filename) + return None + return filename + + def _installapk(self): + for apk in self.apks: + rc = self.adb.installapk(apk) + if rc: + raise RuntimeError( + "Failed to install apk '%s' failed. %d" % (apk, rc)) + + def install(self, install_options=None): + self._download() + _run_steps_host(self.steps_host_pre, self.adb.serial, install_options) + _run_steps_adb(self.steps_adb_pre, self.adb.serial, install_options) + self._installapk() + _run_steps_adb(self.steps_adb_post, self.adb.serial, install_options) + _run_steps_host(self.steps_host_post, self.adb.serial, install_options) + + def setadb(self, adb=None): + self.adb = adb + + +class AndroidTestRunner(object): + + adb = ADB() + """Base class for defining an test runner object. + + This class can be used as-is for simple execution with the expectation + that the run() method will be called from the directory where the test + was installed. Steps, if used, should handle changing directories from + there to the directory where the test was extracted if necessary. + This class can also be extended for more advanced funcionality. + + steps - list of steps to be executed in a shell + """ + def __init__(self, steps_host_pre=[], steps_adb_pre=[], + adbshell_steps=[], steps_adb_post=[], steps_host_post=[]): + self.steps_host_pre = steps_host_pre + self.steps_adb_pre = steps_adb_pre + self.adbshell_steps = adbshell_steps + self.steps_adb_post = steps_adb_post + self.steps_host_post = steps_host_post + self.testoutput = [] + + def _run_steps_adbshell(self, resultsdir, option=None): + stdoutlog = os.path.join(resultsdir, 'stdout.log') + stderrlog = os.path.join(resultsdir, 'stderr.log') + try: + for cmd in self.adbshell_steps: + if option is not None: + cmd = cmd.replace('$(OPTIONS)', option) + else: + cmd = cmd.replace('$(OPTIONS)', '') + if resultsdir is not None: + cmd = cmd.replace('$(RESULTDIR)', resultsdir) + else: + cmd = cmd.replace('$(RESULTDIR)', '') + cmd = cmd.strip() + ret_code = self.adb.run_adb_shell_for_test(cmd, + stdoutlog, + stderrlog) + if ret_code != 0: + raise Exception( + "Failed to execute command(%s):ret_code=%d" % (cmd, + ret_code)) + except: + raise + finally: + self.adb.shell('getprop', + os.path.join(resultsdir, 'propoutput.log')) + self.adb.shell('cat /proc/cpuinfo', + os.path.join(resultsdir, 'cpuinfo.log')) + self.adb.shell('cat /proc/meminfo', + os.path.join(resultsdir, 'meminfo.log')) + + def run(self, resultsdir, run_options=None): + self.starttime = datetime.utcnow() + _run_steps_host(self.steps_host_pre, self.adb.serial, + option=run_options, resultsdir=resultsdir) + _run_steps_adb(self.steps_adb_pre, self.adb.serial, + option=run_options, resultsdir=resultsdir) + self._run_steps_adbshell(resultsdir, option=run_options) + _run_steps_adb(self.steps_adb_post, self.adb.serial, + option=run_options, resultsdir=resultsdir) + _run_steps_host(self.steps_host_post, self.adb.serial, + option=run_options, resultsdir=resultsdir) + self.endtime = datetime.utcnow() + + def setadb(self, adb=None): + self.adb = adb + + +class AndroidTestParser(object): + adb = ADB() + PASS_PATS = ['PASS', 'OK', 'TRUE', 'DONE'] + FAIL_PATS = ['FAIL', 'NG', 'FALSE'] + SKIP_PATS = ['SKIP'] + + """Base class for defining a test parser + + This class can be used as-is for simple results parsers, but will + likely need to be extended slightly for many. If used as it is, + the parse() method should be called while already in the results + directory and assumes that a file for test output will exist called + testoutput.log. + + pattern - regexp pattern to identify important elements of test output + For example: If your testoutput had lines that look like: + "test01: PASS", then you could use a pattern like this: + "^(?P<testid>\w+):\W+(?P<result>\w+)" + This would result in identifying "test01" as testid and + "PASS" as result. Once parse() has been called, + self.results.test_results[] contains a list of dicts of all the + key,value pairs found for each test result + fixupdict - dict of strings to convert test results to standard strings + For example: if you want to standardize on having pass/fail results + in lower case, but your test outputs them in upper case, you could + use a fixupdict of something like: {'PASS':'pass','FAIL':'fail'} + appendall - Append a dict to the test_results entry for each result. + For example: if you would like to add units="MB/s" to each result: + appendall={'units':'MB/s'} + failure_patterns - regexp pattern to identify whether the test is failed + or success + If there is a string match one pattern in failure_patterns, + then this test will be deal as failed. + """ + def __init__(self, pattern=None, fixupdict=None, appendall={}, + failure_patterns=[]): + self.pattern = pattern + self.fixupdict = fixupdict + self.results = {'test_results': []} + self.appendall = appendall + self.failure_patterns = failure_patterns + + def _find_testid(self, test_id): + for x in self.results['test_results']: + if x['testid'] == test_id: + return self.results['test_results'].index(x) + + def parse(self, result_filename='stdout.log', + output_filename='stdout.log', test_name=''): + """Parse test output to gather results + + Use the pattern specified when the class was instantiated to look + through the results line-by-line and find lines that match it. + Results are then stored in self.results. If a fixupdict was supplied + it is used to convert test result strings to a standard format. + """ + + self.real_parse(result_filename=result_filename, + output_filename=output_filename, test_name=test_name) + + self.fixresults(self.fixupdict) + if self.appendall: + self.appendtoall(self.appendall) + self.fixmeasurements() + self.fixids(test_name=test_name) + + def real_parse(self, result_filename='stdout.log', + output_filename='stdout.log', test_name=''): + """Using the pattern to do the real parse operation + + generate the test_results elements from the result file by parsing + with the pattern specified. + """ + if not self.pattern: + return + + try: + pat = re.compile(self.pattern) + except Exception as strerror: + raise RuntimeError( + "AndroidTestParser - Invalid regular expression '%s' - %s" % ( + self.pattern, strerror)) + + failure_pats = [] + for failure_pattern in self.failure_patterns: + try: + failure_pat = re.compile(failure_pattern) + except Exception as strerror: + raise RuntimeError( + "AndroidTestParser - Invalid regular expression '%s' - %s" % ( + failure_pattern, strerror)) + failure_pats.append(failure_pat) + test_ok = True + + with open(output_filename, 'r') as stream: + for lineno, line in enumerate(stream, 1): + if test_ok == True: + for failure_pat in failure_pats: + failure_match = failure_pat.search(line) + if failure_match: + test_ok = False + + match = pat.search(line) + if not match: + continue + data = match.groupdict() + data["log_filename"] = result_filename + data["log_lineno"] = lineno + if data.get('result') is None: + data['result'] = test_ok and 'pass' or 'fail' + self.results['test_results'].append(data) + + def append(self, testid, entry): + """Appends a dict to the test_results entry for a specified testid + + This lets you add a dict to the entry for a specific testid + entry should be a dict, updates it in place + """ + index = self._find_testid(testid) + self.results['test_results'][index].update(entry) + + def appendtoall(self, entry): + """Append entry to each item in the test_results. + + entry - dict of key,value pairs to add to each item in the + test_results + """ + for t in self.results['test_results']: + t.update(entry) + + def fixresults(self, fixupdict): + """Convert results to a known, standard format + + pass it a dict of keys/values to replace + For instance: + {"TPASS":"pass", "TFAIL":"fail"} + This is really only used for qualitative tests + """ + for t in self.results['test_results']: + if "result" in t: + if not fixupdict: + if self.is_result_match(t['result'], self.PASS_PATS): + t['result'] = 'pass' + elif self.is_result_match(t['result'], self.FAIL_PATS): + t['result'] = 'fail' + elif self.is_result_match(t['result'], self.SKIP_PATS): + t['result'] = 'skip' + else: + t['result'] = 'unknown' + elif t['result'] in fixupdict: + t['result'] = fixupdict[t['result']] + else: + t['result'] = 'unknown' + + def is_result_match(self, result, patterns=[]): + cap_result = string.upper(result) + for pattern in patterns: + cap_pattern = string.upper(pattern) + pat_index = string.find(cap_result, cap_pattern) + if pat_index > -1: + return True + + return False + + def fixmeasurements(self): + """Measurements are often read as strings, but need to be + decimal.Decimal as per dashboard bundle format JSON schema. + """ + for test_case in self.results['test_results']: + if 'measurement' in test_case: + try: + test_case['measurement'] = decimal.Decimal( + test_case['measurement']) + except decimal.InvalidOperation: + logging.warning("Invalid measurement %s" % ( + test_case['measurement'])) + del test_case['measurement'] + + def fixids(self, test_name=''): + """ + Convert spaces to _ in test_case_id and remove illegal characters + """ + badchars = "[^a-zA-Z0-9\._-]" + for test_case in self.results['test_results']: + if 'test_case_id' in test_case: + test_case['test_case_id'] = test_case[ + 'test_case_id'].replace(" ", "_") + test_case['test_case_id'] = re.sub(badchars, "", + test_case['test_case_id']) + else: + test_case['test_case_id'] = test_name + + def setadb(self, adb=None): + self.adb = adb + + def set_result_patterns(self, pass_pat=[], fail_pat=[], skip_pat=[]): + if pass_pat: + self.PASS_PATS = pass_pat + if fail_pat: + self.FAIL_PATS = fail_pat + if skip_pat: + self.SKIP_PATS = skip_pat + + +class AndroidInstrumentTestParser(AndroidTestParser): + + def parse(self, result_filename='stdout.log', output_filename='stdout.log', + test_name=''): + """Parser for Instrument test that run with the -r option + """ + pat_test = re.compile( + r'^\s*INSTRUMENTATION_STATUS:\s*test=(?P<test_case_id>.+)\s*$') + pat_status_code = re.compile( + r'^\s*INSTRUMENTATION_STATUS_CODE:\s*(?P<status_code>[\d-]+)\s*$') + data = {} + with open(output_filename, 'r') as stream: + for lineno, line in enumerate(stream, 1): + match = pat_test.search(line) + if match: + data['test_case_id'] = match.group('test_case_id') + continue + + match = pat_status_code.search(line) + if match: + status_code = match.group('status_code') + if status_code == '1': + # test case started + data = {} + elif data['test_case_id']: + if status_code == '0': + data['result'] = 'pass' + else: + data['result'] = 'fail' + data["log_filename"] = result_filename + data["log_lineno"] = lineno + self.results['test_results'].append(data) + data = {} + continue + + if self.fixupdict: + self.fixresults(self.fixupdict) + if self.appendall: + self.appendtoall(self.appendall) + self.fixmeasurements() + self.fixids() + + +class AndroidSimpleTestParser(AndroidTestParser): + + def real_parse(self, result_filename='stdout.log', + output_filename='stdout.log', test_name=''): + self.res_pattern = ("^\s*(?P<test_case_id>.+?)\s*=" + "\s*(?P<result>(pass|fail|ok|ng|true|false|skip|done))\s*$") + self.measurement_pattern = ("^\s*(?P<test_case_id>.+?)\s*=" + "\s*(?P<measurement>[\.\d]+)\s*$") + self.measurement_units_pattern = ("^\s*(?P<test_case_id>.+?)\s*=" + "\s*(?P<measurement>[\.\d]+)\s+(?P<units>\S+)\s*$") + + res_pat = re.compile(self.res_pattern) + measurement_pat = re.compile(self.measurement_pattern) + measurement_units_pat = re.compile(self.measurement_units_pattern) + + with open(output_filename, 'r') as stream: + for lineno, line in enumerate(stream, 1): + match = res_pat.search(line) + if not match: + match = measurement_pat.search(line) + if not match: + match = measurement_units_pat.search(line) + if not match: + continue + data = match.groupdict() + data["log_filename"] = result_filename + data["log_lineno"] = lineno + if data.get('result') is None: + data['result'] = 'pass' + + self.results['test_results'].append(data) + + +def _run_steps_host(steps=[], serial=None, option=None, resultsdir=None): + adb = ADB(serial) + for cmd in steps: + if serial is not None: + cmd = cmd.replace('$(SERIAL)', serial) + else: + cmd = cmd.replace('$(SERIAL)', '') + if option is not None: + cmd = cmd.replace('$(OPTIONS)', option) + else: + cmd = cmd.replace('$(OPTIONS)', '') + if resultsdir is not None: + cmd = cmd.replace('$(RESULTDIR)', resultsdir) + else: + cmd = cmd.replace('$(RESULTDIR)', '') + + cmd = cmd.strip() + rc, output = adb.run_cmd_host(cmd, quiet=False) + if rc: + raise RuntimeError( + "Run step '%s' failed. %d : %s" % (cmd, rc, output)) + if resultsdir is not None: + stdoutlog = os.path.join(resultsdir, 'stdout.log') + adb.push_stream_to_device(output, stdoutlog) + + +def _run_steps_adb(steps=[], serial=None, option=None, resultsdir=None): + adb = ADB(serial) + for cmd in steps: + if option is not None: + cmd = cmd.replace('$(OPTIONS)', option) + else: + cmd = cmd.replace('$(OPTIONS)', '') + if resultsdir is not None: + cmd = cmd.replace('$(RESULTDIR)', resultsdir) + else: + cmd = cmd.replace('$(RESULTDIR)', '') + cmd = cmd.strip() + rc, output = adb.run_adb_cmd(cmd, quiet=False) + if rc: + raise RuntimeError( + "Run step '%s' failed. %d : %s" % (cmd, rc, output)) + if resultsdir is not None: + stdoutlog = os.path.join(resultsdir, 'stdout.log') + adb.push_stream_to_device(output, stdoutlog) diff --git a/lava_android_test/utils.py b/lava_android_test/utils.py new file mode 100644 index 0000000..75290d2 --- /dev/null +++ b/lava_android_test/utils.py @@ -0,0 +1,202 @@ +# Copyright (c) 2010-2012 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +import re +import os +import pexpect +import shutil +import subprocess +import sys +import time +import urllib2 +import urlparse + +_fake_files = None +_fake_paths = None +_fake_machine = None + + +class Tee(file): + """ A file-like object that optionally mimics tee functionality. + + By default, output will go to both stdout and the file specified. + Optionally, quiet=True can be used to mute the output to stdout. + """ + def __init__(self, *args, **kwargs): + try: + self.quiet = kwargs.pop('quiet') + except KeyError: + self.quiet = False + super(Tee, self).__init__(*args, **kwargs) + + def write(self, data): + super(Tee, self).write(data) + if self.quiet is False: + sys.stdout.write(data) + + +def geturl(url, path=""): + urlpath = urlparse.urlsplit(url).path + filename = os.path.basename(urlpath) + if path: + filename = os.path.join(path, filename) + fd = open(filename, "w") + try: + response = urllib2.urlopen(urllib2.quote(url, safe=":/")) + fd = open(filename, 'wb') + shutil.copyfileobj(response, fd, 0x10000) + fd.close() + response.close() + except: + raise RuntimeError("Could not retrieve %s" % url) + return filename + + +def write_file(data, path): + with open(path, "w") as fd: + fd.write(data) + + +def read_file(path): + global _fake_files + global _fake_paths + if _fake_files is not None: + if path in _fake_files: + return _fake_files[path] + if _fake_paths is not None: + if path in _fake_paths: + path = _fake_paths[path] + with open(path) as fd: + data = fd.read() + return data + + +def fake_file(path, data=None, newpath=None): + """ + Set up a fake file to be read with read_file() in testing + If data is specified, the string passed as data will be returned instead + if newpath is specified, the file attempted to be read will be replaced + by newfile + """ + global _fake_files + global _fake_paths + if data is not None: + if _fake_files is None: + _fake_files = {} + _fake_files[path] = data + if newpath is not None: + if _fake_paths is None: + _fake_paths = {} + _fake_paths[path] = newpath + + +def fake_machine(type): + """ + Set up a fake machine type for testing + """ + global _fake_machine + _fake_machine = type + + +def clear_fakes(): + global _fake_files + global _fake_paths + _fake_files = {} + _fake_paths = {} + + +def clear_fake_machine(): + global _fake_machine + _fake_machine = None + + +def run_and_log(cmd, fd, quiet=False): + """ + Run a command and log the output to fd + """ + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, shell=True) + while proc.returncode == None: + proc.poll() + data = proc.stdout.readline() + fd.write(data) + if quiet is False: + sys.stdout.write(data) + return proc.returncode + + +def get_machine_type(): + """ + Return the machine type + """ + global _fake_machine + if _fake_machine is None: + return os.uname()[-1] + return _fake_machine + + +def get_local_name(url): + url = url.strip() + url = re.sub('[\/]+$', '', url) + rest = urllib2.splittype(url)[1] + host, rest = urllib2.splithost(rest) + if rest is None or rest == '': + return host + return os.path.basename(rest) + + +def check_command_exist(command): + rc = subprocess.call(["which", command], stdout=open('/dev/null', 'w')) + return rc == 0 + + +def find_files(target_dir, ext): + file_list = [] + for rootdir, dirs, files in os.walk(target_dir): + for f in files: + if f.upper().endswith(ext.upper()): + file_list.append(os.path.join(rootdir, f)) + + file_list.sort() + return file_list + + +def delete_files(flist=[]): + for f in flist: + if os.path.exists(f): + os.unlink(f) + + +def stop_at_pattern(command=None, pattern=None, timeout=-1): + if not command: + return + + if not pattern: + response = [pexpect.EOF] + else: + response = [pattern, pexpect.EOF] + + result = True + proc = pexpect.spawn(command, logfile=sys.stdout) + try: + match_id = proc.expect(response, timeout=timeout) + if match_id == 0: + time.sleep(5) + except pexpect.TIMEOUT: + result = False + finally: + proc.sendcontrol('C') + proc.sendline('') + + return result diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..58e0e0c --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[upload] +sign=True diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..bdfdf87 --- /dev/null +++ b/setup.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python + +# Copyright (c) 2010, 2011 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from setuptools import setup, find_packages + + +setup( + name='lava-android-test', + version=":versiontools:lava_android_test:", + author='Linaro Validation Team', + author_email='linaro-dev@lists.linaro.org', + url='https://launchpad.net/lava-android-test', + description='LAVA android test execution framework', + long_description=open("README").read(), + packages=find_packages(exclude=['tests']), + license="GNU GPLv3", + test_suite='tests.test_suite', + entry_points=""" + [console_scripts] + lava-android-test=lava_android_test.main:main + [lava_android_test.commands] + version=lava_android_test.commands:version + list-devices=lava_android_test.commands:list_devices + list-tests=lava_android_test.commands:list_tests + list-installed=lava_android_test.commands:list_installed + list-results=lava_android_test.commands:list_results + install=lava_android_test.commands:install + uninstall=lava_android_test.commands:uninstall + run=lava_android_test.commands:run + run-custom=lava_android_test.commands:run_custom + run-monkeyrunner=lava_android_test.commands:run_monkeyrunner + parse=lava_android_test.commands:parse + parse-custom=lava_android_test.commands:parse_custom + show=lava_android_test.commands:show + rename=lava_android_test.commands:rename + remove=lava_android_test.commands:remove + extract-attachments=lava_android_test.commands:extract_attachments + """, + classifiers=[ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: GNU General Public License (GPL)", + "Operating System :: OS Independent", + "Programming Language :: Python :: 2.6", + "Topic :: Software Development :: Testing", + ], + install_requires=[ + 'lava-tool >= 0.2', + 'lava-dispatcher', + 'pexpect', + 'versiontools >= 1.4', + ], + setup_requires=[ + 'versiontools >= 1.4' + ], + zip_safe=False, + include_package_data=True) @@ -0,0 +1,5 @@ +#!/system/bin/sh + +/data/local/tmp/disablesuspend.sh +monkey -s 1 --pct-touch 10 --pct-motion 20 --pct-nav 20 --pct-majornav 30 --pct-appswitch 20 --throttle 500 --pkg-blacklist-file /data/local/tmp/juice_package_black_list 30000 + diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..b898536 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,30 @@ +# Copyright (c) 2010, 2011 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import unittest + + +def test_suite(): + module_names = [ + 'tests.test_lavaandroidtest_commands', + 'tests.test_lavaandroidtest_test', + 'tests.test_lavaandroidtest_testinstaller', + 'tests.test_lavaandroidtest_testparser', + 'tests.test_lavaandroidtest_testrunner', + 'tests.test_swprofile', + 'tests.test_hwprofile'] + loader = unittest.TestLoader() + suite = loader.loadTestsFromNames(module_names) + return suite diff --git a/tests/fixtures.py b/tests/fixtures.py new file mode 100644 index 0000000..ba75b61 --- /dev/null +++ b/tests/fixtures.py @@ -0,0 +1,37 @@ +# Copyright (c) 2010, 2011 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import unittest + + +class TestCaseWithFixtures(unittest.TestCase): + """TestCase extended to allow adding fixtures + + Fixtures added should contain at least a setUp() method, and + optionally a tearDown method as well + """ + + def add_fixture(self, fixture): + if not hasattr(self, "_fixtures"): + self._fixtures = [] + fixture.setUp() + if hasattr(self, "tearDown"): + self._fixtures.append(fixture) + return fixture + + def tearDown(self): + for fixture in self._fixtures: + fixture.tearDown() + self._fixtures = [] diff --git a/tests/imposters.py b/tests/imposters.py new file mode 100644 index 0000000..ef28ad3 --- /dev/null +++ b/tests/imposters.py @@ -0,0 +1,83 @@ +# Copyright (c) 2010, 2011 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import shutil +import sys +import tempfile +import StringIO + + +class OutputImposter(object): + def setUp(self): + self.origstdout = sys.stdout + self.origstderr = sys.stderr + sys.stdout = sys.stderr = self.fakestdout = StringIO.StringIO() + + def tearDown(self): + sys.stdout = self.origstdout + sys.stderr = self.origstderr + + def getvalue(self): + return self.fakestdout.getvalue() + + +class ConfigImposter(object): + def setUp(self): + class fakeconfig: + def __init__(self, basedir): + self.configdir = os.path.join(basedir, "config") + self.installdir = os.path.join(basedir, "install") + self.resultsdir = os.path.join(basedir, "results") + self.registry = { + "format": "LAVA Test Test Registry 1.0", + "providers": [ + { + "entry_point": + "lava_test.core.providers:BuiltInProvider" + }, + { + "entry_point": + "lava_test.core.providers:PkgResourcesProvider", + "config": + {"namespace": "lava_test.test_definitions"} + }, + { + "entry_point": + "lava_test.core.providers:RegistryProvider", + "config": { + "entries": [] + } + } + ] + } + + self.tmpdir = tempfile.mkdtemp() + self.config = fakeconfig(self.tmpdir) + + def tearDown(self): + shutil.rmtree(self.tmpdir) + + @property + def configdir(self): + return self.config.configdir + + @property + def installdir(self): + return self.config.installdir + + @property + def resultsdir(self): + return self.config.resultsdir diff --git a/tests/test_hwprofile.py b/tests/test_hwprofile.py new file mode 100755 index 0000000..fc5ee15 --- /dev/null +++ b/tests/test_hwprofile.py @@ -0,0 +1,180 @@ +#!/usr/bin/env python +# Copyright (c) 2011 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import unittest + +import lava_android_test.hwprofile +from tests.tests_util import fake_adb, clear_fake + +from tests.imposters import OutputImposter +from tests.fixtures import TestCaseWithFixtures + +FAKE_BOARDNAME_FILE = "XXXXXXX" +FAKE_BOARDVENDOR_FILE = "YYYYYYY" +FAKE_BOARDVERSION_FILE = "ZZZZZZZ" + +panda_cpu_info = '''Processor : ARMv7 Processor rev 2 (v7l) +processor : 0 +BogoMIPS : 1576.53 + +processor : 1 +BogoMIPS : 1539.77 + +Features : swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls +CPU implementer : 0x41 +CPU architecture: 7 +CPU variant : 0x1 +CPU part : 0xc09 +CPU revision : 2 + +Hardware : OMAP4 Panda board +Revision : 0020 +Serial : 0000000000000000 +''' + +panda_mem_info = '''MemTotal: 921832 kB +MemFree: 545032 kB +Buffers: 488 kB +Cached: 183964 kB +SwapCached: 0 kB +Active: 212628 kB +Inactive: 125480 kB +Active(anon): 153680 kB +Inactive(anon): 60744 kB +Active(file): 58948 kB +Inactive(file): 64736 kB +Unevictable: 0 kB +Mlocked: 0 kB +HighTotal: 211968 kB +HighFree: 408 kB +LowTotal: 709864 kB +LowFree: 544624 kB +SwapTotal: 0 kB +SwapFree: 0 kB +Dirty: 0 kB +Writeback: 0 kB +AnonPages: 153640 kB +Mapped: 105236 kB +Shmem: 60768 kB +Slab: 10728 kB +SReclaimable: 4760 kB +SUnreclaim: 5968 kB +KernelStack: 3272 kB +PageTables: 5528 kB +NFS_Unstable: 0 kB +Bounce: 0 kB +WritebackTmp: 0 kB +CommitLimit: 460916 kB +Committed_AS: 4237400 kB +VmallocTotal: 122880 kB +VmallocUsed: 75536 kB +VmallocChunk: 36868 kB +''' + + +class HwprofileTests(unittest.TestCase): + maxDiff = None + + def test_get_cpu_devs(self): + fake_adb(output_str=panda_cpu_info) + devs = lava_android_test.hwprofile.get_cpu_devs() + clear_fake() + cpuinfo = { + 'attributes': { + 'processor': '1', + 'cpu_features': + 'swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls', + 'cpu_variant': 1, + 'cpu_architecture': 7, + 'BogoMIPS': '1539.77', + 'Hardware': 'OMAP4 Panda board', + 'cpu_implementer': 65, + 'cpu_part': 3081, + 'cpu_revision': 2, + 'Serial': '0000000000000000', + 'Revision': '0020'}, + 'description': 'Processor #1', + 'device_type': 'device.cpu'} + self.assertEqual(cpuinfo, devs[1]) + cpuinfo = { + 'attributes': { + 'processor': '0', + 'cpu_model_name': 'ARMv7 Processor rev 2 (v7l)', + 'BogoMIPS': '1576.53'}, + 'description': 'Processor #0', + 'device_type': 'device.cpu'} + self.assertEqual(cpuinfo, devs[0]) + + def test_get_board_devs(self): + fake_adb(output_str=panda_cpu_info) + devs = lava_android_test.hwprofile.get_board_devs() + clear_fake() + boardinfo = { + 'description': 'OMAP4 Panda board', + 'device_type': 'device.board'} + self.assertEqual(boardinfo, devs[0]) + + def test_get_mem_devs(self): + fake_adb(output_str=panda_mem_info) + devs = lava_android_test.hwprofile.get_mem_devs() + clear_fake() + + meminfo = { + 'attributes': { + 'kind': 'RAM', + 'capacity': '943955968'}, + 'description': '900MiB of RAM', + 'device_type': 'device.mem'} + self.assertEqual(meminfo, devs[0]) + + +class MissingFiles(TestCaseWithFixtures): + """ + These are tests for situations where certain files used for gathering + hardware profile information may be missing + """ + def setUp(self): + super(MissingFiles, self).setUp() + clear_fake() + self.out = self.add_fixture(OutputImposter()) + + def test_bad_cpuinfo(self): + errmsg = 'WARNING: Could not read cpu information\n' + fake_adb(output_str='', ret_code=255) + devs = lava_android_test.hwprofile.get_cpu_devs() + clear_fake() + self.assertEqual([], devs) + self.assertEqual(errmsg, self.out.getvalue()) + + def test_bad_boardinfo(self): + errmsg = 'WARNING: Could not read board information\n' + fake_adb(output_str='', ret_code=255) + devs = lava_android_test.hwprofile.get_board_devs() + clear_fake() + self.assertEqual([], devs) + self.assertEqual(errmsg, self.out.getvalue()) + + def test_bad_meminfo(self): + errmsg = 'WARNING: Could not read memory information\n' + fake_adb(output_str='', ret_code=255) + devs = lava_android_test.hwprofile.get_mem_devs() + clear_fake() + self.assertEqual([], devs) + self.assertEqual(errmsg, self.out.getvalue()) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_lavaandroidtest_commands.py b/tests/test_lavaandroidtest_commands.py new file mode 100644 index 0000000..83e1615 --- /dev/null +++ b/tests/test_lavaandroidtest_commands.py @@ -0,0 +1,106 @@ +# Copyright (c) 2011 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import re +from tests.tests_util import fake_adb, clear_fake + +from tests.imposters import ConfigImposter, OutputImposter +from tests.fixtures import TestCaseWithFixtures +from lava_android_test.main import LAVAAndroidTestDispatcher + + +class LavaTestCommandTestCase(TestCaseWithFixtures): + def setUp(self): + self.config = self.add_fixture(ConfigImposter()) + self.out = self.add_fixture(OutputImposter()) + clear_fake() + + def tearDown(self): + clear_fake() + + def _runLavaTest(self, cmds): + LAVAAndroidTestDispatcher().dispatch(cmds) + + +class BadCommand(LavaTestCommandTestCase): + def test_bad_cmd(self): + # Running an unknown command that does not exist of a command that does + # gives a nice error message. + errmsg = "invalid choice: 'results'" + + self.assertRaises(SystemExit, LAVAAndroidTestDispatcher().dispatch, + ['results', 'foo']) + self.assertNotEqual(None, re.search(errmsg, self.out.getvalue()), + re.MULTILINE) + self.assertTrue(errmsg in self.out.getvalue()) + + +class ListKnown(LavaTestCommandTestCase): + def test_list_tests(self): + self._runLavaTest(['list-tests']) + self.assertTrue("monkey" in self.out.getvalue()) + +dir_list_info = '''monkey +0xbench +RET_CODE=0''' + + +class ListInstalled(LavaTestCommandTestCase): + def test_list_installed(self): + # test_name must be in the BuiltInProvider._builtin_tests + fake_adb(output_str=dir_list_info) + test_name = "monkey" + self._runLavaTest(['list-installed']) + self.assertTrue(test_name in self.out.getvalue()) + clear_fake() + +devices_list_info = '''List of devices attached +192.168.1.109:5555 device +''' + + +class ListDevices(LavaTestCommandTestCase): + def test_list_devices(self): + # test_name must be in the BuiltInProvider._builtin_tests + fake_adb(output_str=devices_list_info) + self._runLavaTest(['list-devices']) + self.assertTrue('192.168.1.109:5555 device' in self.out.getvalue()) + clear_fake() + + +class RunTest(LavaTestCommandTestCase): + def test_run_command_test_not_install(self): + errmsg = 'ERROR: The test (monkey) has not been installed yet.' + fake_adb(output_str='RET_CODE=1') + ret_code = LAVAAndroidTestDispatcher().dispatch(['run', 'monkey']) + self.assertEqual(1, ret_code) + self.assertTrue(errmsg in self.out.getvalue()) + clear_fake() + + def test_run_command_test_not_exist(self): + errmsg = "unknown test 'abc'" + fake_adb(output_str='RET_CODE=0') + self.assertRaises(SystemExit, LAVAAndroidTestDispatcher().dispatch, + ['run', 'abc']) + self.assertNotEqual(None, re.search(errmsg, self.out.getvalue()), + re.MULTILINE) + self.assertTrue(errmsg in self.out.getvalue()) + + +class TestHelp(LavaTestCommandTestCase): + def test_command_help(self): + self.assertRaises(SystemExit, LAVAAndroidTestDispatcher().dispatch, + ['--help']) + self.assertTrue("--help" in self.out.getvalue()) diff --git a/tests/test_lavaandroidtest_test.py b/tests/test_lavaandroidtest_test.py new file mode 100644 index 0000000..a7d6575 --- /dev/null +++ b/tests/test_lavaandroidtest_test.py @@ -0,0 +1,96 @@ +# Copyright (c) 2011 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import re +import os +import subprocess +from lava_android_test.config import get_config +from lava_android_test.adb import ADB +from tests.imposters import ConfigImposter, OutputImposter +from tests.fixtures import TestCaseWithFixtures +from tests.tests_util import maketest, makerunner, test_tmp, clear_fake, \ + fake_adb + + +class FakeAdb(ADB): + def __init__(self): + super(FakeAdb, self).__init__() + self.tmp_dir = test_tmp + if not os.path.exists(test_tmp): + os.makedirs(test_tmp) + + def shell(self, command=None, stdout=None, stderr=None): + if command.startswith('mkdir'): + dir_path = command[len('mkdir '):] + try: + os.mkdir('%s/%s' % (test_tmp, dir_path)) + except: + return 1 + return 0 + elif command.startswith('ls'): + dir_path = command[len('ls '):] + real_path = '%s/%s' % (test_tmp, dir_path) + if os.path.exists(real_path): + return 0 + else: + return 1 + elif command.startswith('rm -r'): + dir_path = command[len('rm -r '):] + proc = subprocess.Popen('rm -fr %s/%s' % (test_tmp, dir_path), + shell=True) + return proc.wait() + else: + return 0 + +fake_output_str = \ +'''[ro.build.display.id]: [sdk-eng 4.0.1 ICS_MR0 202595 test-keys] +RET_CODE=0''' + + +class TestAndroidTest(TestCaseWithFixtures): + def setUp(self): + super(TestAndroidTest, self).setUp() + self.config = self.add_fixture(ConfigImposter()) + self.out = self.add_fixture(OutputImposter()) + clear_fake() + + def tearDown(self): + clear_fake() + + def test_run(self): + config = get_config() + test_name = 'foo' + clear_fake() + testrunner = makerunner(steps_host_pre=["echo foo"]) + test = maketest(name=test_name, runner=testrunner) + real_installed_path = '%s/%s/%s' % (test_tmp, + config.installdir_android, + test_name) + test.setadb(FakeAdb()) + self.assertFalse(os.path.exists(real_installed_path)) + test.install() + self.assertTrue(os.path.exists(real_installed_path)) + + fake_adb(output_str=fake_output_str) + result_id = test.run() + self.assertTrue("LAVA: (stdout) foo" in self.out.getvalue()) + + result_id_pattern = "foo\d+\.\d+" + self.assertTrue(re.match(result_id_pattern, result_id)) + self.assertTrue("LAVA: (stdout) foo" in self.out.getvalue()) + + test.uninstall() + + self.assertFalse(os.path.exists(real_installed_path)) diff --git a/tests/test_lavaandroidtest_testinstaller.py b/tests/test_lavaandroidtest_testinstaller.py new file mode 100644 index 0000000..7111868 --- /dev/null +++ b/tests/test_lavaandroidtest_testinstaller.py @@ -0,0 +1,58 @@ +# Copyright (c) 2010, 2011 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import hashlib +import os +import shutil +import tempfile +import unittest +from tests.tests_util import makeinstaller + + +class testTestInstaller(unittest.TestCase): + def setUp(self): + self.origdir = os.path.abspath(os.curdir) + self.tmpdir = tempfile.mkdtemp() + self.filename = os.path.abspath(__file__) + os.chdir(self.tmpdir) + + def tearDown(self): + os.chdir(self.origdir) + shutil.rmtree(self.tmpdir) + + def test_bad_download(self): + url = "file:///xxxyyyzzz" + installer = makeinstaller(url=url) + self.assertRaises(RuntimeError, installer._download) + + def test_bad_md5(self): + url = "file://%s" % self.filename + installer = makeinstaller(url=url, md5='foo') + self.assertRaises(RuntimeError, installer._download) + + def test_good_md5(self): + url = "file://%s" % self.filename + md5 = hashlib.md5(file(self.filename).read()).hexdigest() + installer = makeinstaller(url=url, md5=md5) + location = installer._download() + self.assertTrue(os.path.exists(location)) + + def test_steps_host_pre(self): + self.assertFalse(os.path.exists("./foo")) + steps_host_pre = ["echo test > foo"] + installer = makeinstaller(steps_host_pre=steps_host_pre) + installer.install('./') + self.assertTrue(os.path.exists("./foo")) + self.assertTrue("test" in open("./foo").read()) diff --git a/tests/test_lavaandroidtest_testparser.py b/tests/test_lavaandroidtest_testparser.py new file mode 100644 index 0000000..f08f9d5 --- /dev/null +++ b/tests/test_lavaandroidtest_testparser.py @@ -0,0 +1,57 @@ +# Copyright (c) 2010, 2011 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os + +from tests.fixtures import TestCaseWithFixtures +from tests.tests_util import makeparser + + +class testTestParser(TestCaseWithFixtures): + + def setUp(self): + self.test_id = "ABC" + + def tearDown(self): + os.unlink('stdout.log') + + def writeoutputlog(self, output_str): + with open("stdout.log", "w") as fd: + fd.write(output_str) + + def test_parse(self): + pattern = "^(?P<testid>\w+):\W+(?P<result>\w+)" + self.writeoutputlog("test001: pass") + parser = makeparser(pattern) + parser.parse() + self.assertTrue( + parser.results["test_results"][0]["testid"] == "test001" and + parser.results["test_results"][0]["result"] == "pass") + + def test_fixupdict(self): + pattern = "^(?P<testid>\w+):\W+(?P<result>\w+)" + fixup = {"pass": "PASS"} + self.writeoutputlog("test001: pass") + parser = makeparser(pattern, fixupdict=fixup) + parser.parse() + self.assertEquals("PASS", parser.results["test_results"][0]["result"]) + + def test_appendall(self): + pattern = "^(?P<testid>\w+):\W+(?P<result>\w+)" + append = {"units": "foo/s"} + self.writeoutputlog("test001: pass") + parser = makeparser(pattern, appendall=append) + parser.parse() + self.assertEqual("foo/s", parser.results["test_results"][0]["units"]) diff --git a/tests/test_lavaandroidtest_testrunner.py b/tests/test_lavaandroidtest_testrunner.py new file mode 100644 index 0000000..0d0cd7d --- /dev/null +++ b/tests/test_lavaandroidtest_testrunner.py @@ -0,0 +1,65 @@ +# Copyright (c) 2010, 2011 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import shutil +import tempfile +from datetime import datetime +from tests.tests_util import makerunner +from tests.imposters import OutputImposter, ConfigImposter +from tests.fixtures import TestCaseWithFixtures + + +class testTestRunner(TestCaseWithFixtures): + def setUp(self): + self.config = self.add_fixture(ConfigImposter()) + self.out = self.add_fixture(OutputImposter()) + self.origdir = os.path.abspath(os.curdir) + self.tmpdir = tempfile.mkdtemp() + self.filename = os.path.abspath(__file__) + os.chdir(self.tmpdir) + self.test_id = "ABC" + + def tearDown(self): + os.chdir(self.origdir) + shutil.rmtree(self.tmpdir) + + def test_starttime(self): + runner = makerunner() + runner.run('./') + self.assertTrue(isinstance(runner.starttime, datetime)) + + def test_endtime(self): + runner = makerunner() + runner.run('./') + self.assertTrue(isinstance(runner.endtime, datetime)) + + def test_timediff(self): + steps = ['sleep 2'] + runner = makerunner(steps_host_pre=steps) + runner.run('./') + self.assertNotEqual(runner.starttime, runner.endtime) + + def test_runsteps(self): + steps = ["echo test > foo"] + runner = makerunner(steps_host_pre=steps) + runner.run('./') + self.assertTrue(os.path.exists("./foo")) + + def test_logoutput(self): + steps = ["echo test"] + runner = makerunner(steps_host_pre=steps) + runner.run('./') + self.assertTrue('test' in self.out.getvalue()) diff --git a/tests/test_swprofile.py b/tests/test_swprofile.py new file mode 100644 index 0000000..4e937be --- /dev/null +++ b/tests/test_swprofile.py @@ -0,0 +1,87 @@ +# Copyright (c) 2011 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import unittest + +from lava_android_test import swprofile +from tests.tests_util import fake_adb, clear_fake + +package_list_info = '''package:android:4.0.1.2.3.4.5.6.7.8.9-3 (#14) +package:com.android.musicvis:4.0.1.2.3.4.5.6.7.8.9-3 (#14) +package:com.android.videoeditor:1.1 (#11) +package:com.android.vpndialogs:4.0.1.2.3.4.5.6.7.8.9-3 (#14) +package:com.android.wallpaper:4.0.1.2.3.4.5.6.7.8.9-3 (#14) +package:com.android.wallpaper.livepicker:4.0.1.2.3.4.5.6.7.8.9-3 (#14) +package:com.svox.pico:1.0 (#1)''' + +getprop_info = '''[dalvik.vm.heapsize]: [24m] +[dalvik.vm.stack-trace-file]: [/data/anr/traces.txt] +[dev.bootcomplete]: [1] +[gsm.current.phone-type]: [1] +[ro.build.date]: [Wed Oct 12 12:35:47 PDT 2011] +[ro.build.description]: [sdk-eng 4.0.1 ICS_MR0 202595 test-keys] +[ro.build.display.id]: [sdk-eng 4.0.1 ICS_MR0 202595 test-keys] +[ro.build.host]: [android-test-37.mtv.corp.google.com] +[ro.build.id]: [ICS_MR0] +[ro.build.product]: [generic] +[ro.build.tags]: [test-keys] +[ro.build.type]: [eng] +[ro.build.version.sdk]: [14]''' + + +class SwprofileTests(unittest.TestCase): + maxDiff = None + + def test_getimage_name_from_properties(self): + fake_adb(output_str=getprop_info) + image_name = swprofile.get_image_name_from_properties() + clear_fake() + self.assertEqual('sdk-eng 4.0.1 ICS_MR0 202595 test-keys', image_name) + + def test_get_properties(self): + fake_adb(output_str=getprop_info) + result = swprofile.get_properties() + clear_fake() + properties = {'dalvik.vm.heapsize': '24m', + 'dalvik.vm.stack-trace-file': '/data/anr/traces.txt', + 'dev.bootcomplete': '1', + 'gsm.current.phone-type': '1', + 'ro.build.date': 'Wed Oct 12 12:35:47 PDT 2011', + 'ro.build.description': 'sdk-eng 4.0.1 ICS_MR0 202595 test-keys', + 'ro.build.display.id': 'sdk-eng 4.0.1 ICS_MR0 202595 test-keys', + 'ro.build.host': 'android-test-37.mtv.corp.google.com', + 'ro.build.id': 'ICS_MR0', + 'ro.build.product': 'generic', + 'ro.build.tags': 'test-keys', + 'ro.build.type': 'eng', + 'ro.build.version.sdk': '14'} + self.assertEqual(properties, result) + + def test_get_package_info(self): + fake_adb(output_str=package_list_info) + result = swprofile.get_package_info() + clear_fake() + packages = {'android': '4.0.1.2.3.4.5.6.7.8.9-3 (#14)', + 'com.android.musicvis': '4.0.1.2.3.4.5.6.7.8.9-3 (#14)', + 'com.android.videoeditor': '1.1 (#11)', + 'com.android.vpndialogs': '4.0.1.2.3.4.5.6.7.8.9-3 (#14)', + 'com.android.wallpaper': '4.0.1.2.3.4.5.6.7.8.9-3 (#14)', + 'com.android.wallpaper.livepicker': '4.0.1.2.3.4.5.6.7.8.9-3 (#14)', + 'com.svox.pico': '1.0 (#1)'} + result_hash = {} + for package in result: + result_hash[package.get('name')] = package.get('version') + + self.assertEqual(packages, result_hash) diff --git a/tests/tests_util.py b/tests/tests_util.py new file mode 100755 index 0000000..0876b9b --- /dev/null +++ b/tests/tests_util.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python +# +# Copyright (c) 2011 Linaro +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +import os +import stat +import subprocess +from lava_android_test.testdef import AndroidTest, \ + AndroidTestInstaller, \ + AndroidTestRunner, \ + AndroidTestParser + + +def maketest(name="foo", version="", installer=None, runner=None, parser=None): + if installer is None: + installer = makeinstaller() + return AndroidTest(name, version, installer, runner, parser) + + +def makerunner(**kwargs): + return AndroidTestRunner(**kwargs) + + +def makeinstaller(**kwargs): + return AndroidTestInstaller(**kwargs) + + +def makeparser(*args, **kwargs): + return AndroidTestParser(*args, **kwargs) + +test_tmp = '/tmp/lava-android-test-tmp' + + +def fake_adb(output_str='', target_path=test_tmp, ret_code=0): + if not os.path.exists(target_path): + os.makedirs(target_path) + fake_adb_path = os.path.join(target_path, 'adb') + adb_file = open(fake_adb_path, 'w') + adb_file.write('#!/bin/bash\n') + adb_file.write('if [ "$2" == "chmod" ]; then\n') + adb_file.write('\texit 0\n') + adb_file.write('fi\n') + if output_str is None or output_str == '': + pass + else: + adb_file.write('echo \'\n') + adb_file.write(output_str) + adb_file.write('\'\n') + adb_file.write('exit %s\n' % ret_code) + adb_file.close() + os.chmod(fake_adb_path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) + os.chmod(target_path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) + os.environ['PATH'] = target_path + ':' + os.environ['PATH'] + + +def clear_fake(target_path=test_tmp): + if not os.path.exists(target_path): + return + if os.path.isdir(target_path): + for sub_path in os.listdir(target_path): + clear_fake(os.path.join(target_path, sub_path)) + os.rmdir(target_path) + else: + os.unlink(target_path) + + +def main(): + fake_adb('hello, \ntest') + cmd = 'adb shell ls' + p = subprocess.Popen(cmd, shell=True) + p.wait() + clear_fake() + + +if __name__ == '__main__': + main() |