perform-tests: Create large files in /var/tmp
[patchq.git] / perform-tests.py
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3
4 # This task takes patch series messages off one of the ‘patchq_test_*’
5 # queues and tests the patch series.
6 #
7 # If you run it without arguments, it will pick up patches from each
8 # test queue in turn and test them (but not in parallel).  You can
9 # also list one or more tests on the command line, in which case only
10 # that test or tests are considered.
11 #
12 # This script does not perform tests in parallel, but doesn't care if
13 # other instances of the script are running (even across machines).
14 # Because of the message broker each patch series is only tested once.
15
16 import email
17 import json
18 import mailbox
19 import os
20 import pika
21 import shutil
22 import subprocess
23 import sys
24 import tempfile
25
26 import config
27
28 connection = pika.BlockingConnection(pika.ConnectionParameters(
29     host = config.mq_server))
30 channel = connection.channel()
31
32 def ack(method):
33     channel.basic_ack(delivery_tag = method.delivery_tag)
34
35 # Which tests to run?
36 if len(sys.argv) <= 1:
37     tests = config.tests
38 else:
39     tests = []
40     for arg in sys.argv[1:]:
41         if arg not in config.tests:
42             sys.exit("%s is not listed in config.tests" % arg)
43         tests.append(arg)
44
45 pwd = os.getcwd()
46
47 for t in tests:
48     qname = "patchq_test_%s" % t
49     while True:
50         method, _, body = channel.basic_get(queue = qname, no_ack = False)
51         if not method: break
52
53         # Parse the ordered list of messages forming the patch series.
54         msgs = json.loads(body)
55         msgs = [email.message_from_string(m) for m in msgs]
56
57         # This should never happen, but the rest of the code
58         # below assumes number of msgs > 0, so ...
59         if len(msgs) == 0:
60             ack(method)
61             continue
62
63         print ("%s: Running test:" % t)
64
65         # Save them to a temporary directory.
66         # Create large files in /var/tmp
67         tempfile.tempdir = "/var/tmp"
68         dir = tempfile.mkdtemp()
69         os.chdir(dir)
70
71         # Save the patches to files.
72         i = 0
73         args = []
74         args.append("%s/%s.sh" % (pwd, t))
75         last_msg = None
76         for m in msgs:
77             i = i+1
78             filename = ("%05d" % i)
79             args.append(filename)
80             print ("%05d %s" % (i, m['Subject']))
81             with open(filename, "w") as file:
82                 file.write(m.as_string())
83             last_msg = m
84
85         # Run the test.
86         with open("output", "w") as out:
87             r = subprocess.call(args, stdout=out, stderr=out)
88
89         if r == 77:
90             print ("%s: Test skipped" % t)
91         else:
92             # Do a "group reply" to the last email.
93             tos = last_msg.get_all('to', [])
94             ccs = last_msg.get_all('cc', [])
95             from_ = last_msg['From']
96             to = email.utils.getaddresses(tos + ccs + [from_])
97             ref = last_msg['Message-Id']
98             if r == 0:
99                 status = "success"
100             else:
101                 status = "FAILED"
102             subject = "%s %s (was: Re: %s)" % (t, status, last_msg['Subject'])
103             with open("output", "r") as file:
104                 content = file.read()
105
106             body = json.dumps((to, subject, ref, content))
107             channel.basic_publish(exchange = 'patchq_reports',
108                                   routing_key = '',
109                                   body = body)
110
111         # Ack the input message since we have processed it.
112         ack(method)
113
114         shutil.rmtree(dir, ignore_errors = True)