~linaro-validation/lava-test/trunk

« back to all changes in this revision

Viewing changes to abrek/testdef.py

  • Committer: Paul Larson
  • Date: 2010-06-29 21:23:04 UTC
  • mfrom: (8.1.7 abrek-run)
  • Revision ID: paul.larson@canonical.com-20100629212304-78lz9cdytxu6yah1
Add support for running tests, a run command, and an example using this

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
import hashlib
 
2
import json
2
3
import os
3
4
import shutil
4
5
import sys
 
6
import time
5
7
from commands import getstatusoutput
 
8
from datetime import datetime
6
9
 
7
10
import abrek.config
8
 
from abrek.utils import geturl
 
11
from abrek.utils import geturl, write_file
9
12
 
10
13
class AbrekTest(object):
11
 
    """
 
14
    """Base class for defining tests.
 
15
 
12
16
    This can be used by test definition files to create an object that
13
17
    contains the building blocks for installing tests, running them,
14
18
    and parsing the results.
19
23
    runner - AbrekRunner instance to use
20
24
    parser - AbrekParser instance to use
21
25
    """
22
 
 
23
26
    def __init__(self, testname, version="", installer=None, runner=None,
24
27
                 parser=None):
25
28
        self.config = abrek.config.AbrekConfig()
28
31
        self.installer = installer
29
32
        self.runner = runner
30
33
        self.parser = parser
 
34
        self.installdir = os.path.join(self.config.installdir, self.testname)
31
35
        self.origdir = os.path.abspath(os.curdir)
32
36
 
33
37
    def install(self):
34
 
        """
35
 
        Install the test suite.  This creates an install directory under
36
 
        the user's XDG_DATA_HOME directory to mark that the test is installed.
37
 
        The installer's install() method is then called from this directory
38
 
        to complete any test specific install that may be needed.
39
 
        """
40
 
        if self.installer:
41
 
            path = os.path.join(self.config.installdir, self.testname)
42
 
            if os.path.exists(path):
43
 
                raise RuntimeError, "%s is already installed" % self.testname
44
 
            os.makedirs(path)
45
 
            os.chdir(path)
46
 
            rc = self.installer.install()
47
 
            if rc:
48
 
                self.uninstall()
49
 
                raise RuntimeError, "An error was detected during", \
50
 
                                    "installation, cleaning up"
 
38
        """Install the test suite.
 
39
 
 
40
        This creates an install directory under the user's XDG_DATA_HOME
 
41
        directory to mark that the test is installed.  The installer's
 
42
        install() method is then called from this directory to complete any
 
43
        test specific install that may be needed.
 
44
        """
 
45
        if not self.installer:
 
46
            raise RuntimeError("no installer defined for '%s'" %
 
47
                                self.testname)
 
48
        if os.path.exists(self.installdir):
 
49
            raise RuntimeError("%s is already installed" % self.testname)
 
50
        os.makedirs(self.installdir)
 
51
        os.chdir(self.installdir)
 
52
        try:
 
53
            self.installer.install()
 
54
        except Exception as strerror:
 
55
            self.uninstall()
 
56
            raise RuntimeError("An error was detected during",
 
57
                "installation, cleaning up: %s" % strerror)
51
58
 
52
59
    def uninstall(self):
53
 
        """
 
60
        """Uninstall the test suite.
 
61
 
54
62
        Uninstalling just recursively removes the test specific directory
55
63
        under the user's XDG_DATA_HOME directory.  This will both mark
56
64
        the test as removed, and clean up any files that were downloaded
62
70
        if os.path.exists(path):
63
71
            shutil.rmtree(path)
64
72
 
 
73
    def _savetestdata(self):
 
74
        testdata = {}
 
75
        filename = os.path.join(self.resultsdir, 'testdata.json')
 
76
        testdata['testname'] = self.testname
 
77
        testdata['version'] = self.version
 
78
        testdata['starttime'] = time.mktime(self.runner.starttime.timetuple())
 
79
        testdata['endtime'] = time.mktime(self.runner.endtime.timetuple())
 
80
        write_file(json.dumps(testdata), filename)
 
81
 
65
82
    def run(self):
66
 
        if self.runner:
67
 
            return self.runner.run()
 
83
        if not self.runner:
 
84
            raise RuntimeError("no test runner defined for '%s'" %
 
85
                                self.testname)
 
86
        resultname = (self.testname +
 
87
                     str(time.mktime(datetime.utcnow().timetuple())))
 
88
        self.resultsdir = os.path.join(self.config.resultsdir, resultname)
 
89
        os.makedirs(self.resultsdir)
 
90
        os.chdir(self.installdir)
 
91
        self.runner.run(self.resultsdir)
 
92
        self._savetestdata()
68
93
 
69
94
    def parse(self,results):
70
 
        if self.parser:
71
 
            return self.parser.parse(results)
 
95
        if not self.parser:
 
96
            raise RuntimeError("no test parser defined for '%s'" %
 
97
                                self.testname)
 
98
        self.parser.parse(results)
72
99
 
73
100
class AbrekTestInstaller(object):
74
 
    """
75
 
    Base class for defining an installer object.  This class can be used
76
 
    as-is for simple installers, or extended for more advanced funcionality.
 
101
    """Base class for defining an installer object.
 
102
    This class can be used as-is for simple installers, or extended for more
 
103
    advanced funcionality.
77
104
 
78
105
    steps - list of steps to be executed in a shell
79
106
    deps - list of dependencies to apt-get install before running the steps
80
107
    url - location from which the test suite should be downloaded
81
108
    md5 - md5sum to check the integrety of the download
82
109
    """
83
 
 
84
110
    def __init__(self, steps=[], deps=[], url="", md5="", **kwargs):
85
111
        self.steps = steps
86
112
        self.deps = deps
91
117
        if not self.deps:
92
118
            return 0
93
119
        cmd = "sudo apt-get install %s", " ".join(self.deps)
94
 
        rc,output = getstatusoutput(cmd)
 
120
        rc, output = getstatusoutput(cmd)
95
121
        if rc:
96
 
            raise RuntimeError, "Dependency installation failed"
 
122
            raise RuntimeError("Dependency installation failed")
97
123
 
98
124
    def _download(self):
99
 
        """
100
 
        Download the file specified by the url and check the md5.
101
 
        Return the path and filename if successful, otherwise return None
 
125
        """Download the file specified by the url and check the md5.
 
126
 
 
127
        Returns the path and filename if successful, otherwise return None
102
128
        """
103
129
        if not self.url:
104
130
            return 0
112
138
                for data in fd.read(0x10000):
113
139
                    checkmd5.update(data)
114
140
            if checkmd5.hexdigest() != self.md5:
115
 
                raise RuntimeError, "Unexpected md5sum downloading %s" % \
116
 
                                    filename
 
141
                raise RuntimeError("Unexpected md5sum downloading %s" %
 
142
                                    filename)
117
143
                return None
118
144
        return filename
119
145
 
120
146
    def _runsteps(self):
121
147
        for cmd in self.steps:
122
 
            rc,output = getstatusoutput(cmd)
 
148
            rc, output = getstatusoutput(cmd)
123
149
 
124
150
    def install(self):
125
151
        self._installdeps()
126
152
        self._download()
127
153
        self._runsteps()
128
154
 
 
155
class AbrekTestRunner(object):
 
156
    """Base class for defining an test runner object.
 
157
 
 
158
    This class can be used as-is for simple execution with the expectation
 
159
    that the run() method will be called from the directory where the test
 
160
    was installed.  Steps, if used, should handle changing directories from
 
161
    there to the directory where the test was extracted if necessary.
 
162
    This class can also be extended for more advanced funcionality.
 
163
 
 
164
    steps - list of steps to be executed in a shell
 
165
    """
 
166
    def __init__(self, steps=[]):
 
167
        self.steps = steps
 
168
        self.testoutput = []
 
169
 
 
170
    def _runsteps(self, resultsdir):
 
171
        outputlog = os.path.join(resultsdir, 'testoutput.log')
 
172
        with open(outputlog, 'a') as fd:
 
173
            for cmd in self.steps:
 
174
                rc, output = getstatusoutput(cmd)
 
175
                fd.write(output)
 
176
 
 
177
    def run(self, resultsdir):
 
178
        self.starttime = datetime.utcnow()
 
179
        self._runsteps(resultsdir)
 
180
        self.endtime = datetime.utcnow()
 
181
 
129
182
def testloader(testname):
130
183
    """
131
184
    Load the test definition, which can be either an individual