Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1200)

Side by Side Diff: appengine/swarming/local_smoke_test.py

Issue 2911193003: Expose named caches as dimensions. (Closed)
Patch Set: . Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2014 The LUCI Authors. All rights reserved. 2 # Copyright 2014 The LUCI Authors. All rights reserved.
3 # Use of this source code is governed under the Apache License, Version 2.0 3 # Use of this source code is governed under the Apache License, Version 2.0
4 # that can be found in the LICENSE file. 4 # that can be found in the LICENSE file.
5 5
6 """Integration test for the Swarming server, Swarming bot and Swarming client. 6 """Integration test for the Swarming server, Swarming bot and Swarming client.
7 7
8 It starts both a Swarming server and a Swarming bot and triggers tasks with the 8 It starts both a Swarming server and a Swarming bot and triggers tasks with the
9 Swarming client to ensure the system works end to end. 9 Swarming client to ensure the system works end to end.
10 """ 10 """
11 11
12 import base64 12 import base64
13 import json 13 import json
14 import logging 14 import logging
15 import os 15 import os
16 import re 16 import re
17 import signal 17 import signal
18 import socket 18 import socket
19 import sys 19 import sys
20 import tempfile 20 import tempfile
21 import textwrap 21 import textwrap
22 import time
22 import unittest 23 import unittest
23 import urllib 24 import urllib
24 25
25 APP_DIR = os.path.dirname(os.path.abspath(__file__)) 26 APP_DIR = os.path.dirname(os.path.abspath(__file__))
26 BOT_DIR = os.path.join(APP_DIR, 'swarming_bot') 27 BOT_DIR = os.path.join(APP_DIR, 'swarming_bot')
27 CLIENT_DIR = os.path.join(APP_DIR, '..', '..', 'client') 28 CLIENT_DIR = os.path.join(APP_DIR, '..', '..', 'client')
28 29
29 from tools import start_bot 30 from tools import start_bot
30 from tools import start_servers 31 from tools import start_servers
31 32
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 os.remove(tmp) 202 os.remove(tmp)
202 203
203 def terminate(self, bot_id): 204 def terminate(self, bot_id):
204 return self._run('terminate', ['--wait', bot_id]) 205 return self._run('terminate', ['--wait', bot_id])
205 206
206 def cleanup(self): 207 def cleanup(self):
207 if self._tmpdir: 208 if self._tmpdir:
208 file_path.rmtree(self._tmpdir) 209 file_path.rmtree(self._tmpdir)
209 self._tmpdir = None 210 self._tmpdir = None
210 211
212 def query_bot(self):
213 """Returns the bot's properties."""
214 data = json.loads(self._capture('query', ['bots/list', '--limit', '10']))
215 if not data.get('items'):
216 return None
217 assert len(data['items']) == 1
218 return data['items'][0]
219
211 def dump_log(self): 220 def dump_log(self):
212 print >> sys.stderr, '-' * 60 221 print >> sys.stderr, '-' * 60
213 print >> sys.stderr, 'Client calls' 222 print >> sys.stderr, 'Client calls'
214 print >> sys.stderr, '-' * 60 223 print >> sys.stderr, '-' * 60
215 for i in xrange(self._index): 224 for i in xrange(self._index):
216 with open(os.path.join(self._tmpdir, 'client_%d.log' % i), 'rb') as f: 225 with open(os.path.join(self._tmpdir, 'client_%d.log' % i), 'rb') as f:
217 log = f.read().strip('\n') 226 log = f.read().strip('\n')
218 for l in log.splitlines(): 227 for l in log.splitlines():
219 sys.stderr.write(' %s\n' % l) 228 sys.stderr.write(' %s\n' % l)
220 229
(...skipping 13 matching lines...) Expand all
234 '--verbose', 243 '--verbose',
235 ] + args 244 ] + args
236 with open(name, 'wb') as f: 245 with open(name, 'wb') as f:
237 f.write('\nRunning: %s\n' % ' '.join(cmd)) 246 f.write('\nRunning: %s\n' % ' '.join(cmd))
238 f.flush() 247 f.flush()
239 p = subprocess42.Popen( 248 p = subprocess42.Popen(
240 cmd, stdout=f, stderr=subprocess42.STDOUT, cwd=CLIENT_DIR) 249 cmd, stdout=f, stderr=subprocess42.STDOUT, cwd=CLIENT_DIR)
241 p.communicate() 250 p.communicate()
242 return p.returncode 251 return p.returncode
243 252
253 def _capture(self, command, args):
254 cmd = [
255 sys.executable, 'swarming.py', command, '-S', self._swarming_server,
256 ] + args
257 p = subprocess42.Popen(cmd, stdout=subprocess42.PIPE, cwd=CLIENT_DIR)
258 return p.communicate()[0]
259
244 260
245 def gen_expected(**kwargs): 261 def gen_expected(**kwargs):
246 expected = { 262 expected = {
247 u'abandoned_ts': None, 263 u'abandoned_ts': None,
248 u'bot_dimensions': None, 264 u'bot_dimensions': None,
249 u'bot_id': unicode(socket.getfqdn().split('.', 1)[0]), 265 u'bot_id': unicode(socket.getfqdn().split('.', 1)[0]),
250 u'children_task_ids': [], 266 u'children_task_ids': [],
251 u'cost_saved_usd': None, 267 u'cost_saved_usd': None,
252 u'deduped_from': None, 268 u'deduped_from': None,
253 u'exit_codes': [0], 269 u'exit_codes': [0],
(...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after
629 self._run_isolated( 645 self._run_isolated(
630 hello_world, 'secret_bytes', 646 hello_world, 'secret_bytes',
631 ['--secret-bytes-path', tmp, '--', '${ISOLATED_OUTDIR}'], 647 ['--secret-bytes-path', tmp, '--', '${ISOLATED_OUTDIR}'],
632 expected_summary, {os.path.join('0', 'sekret'): 'foobar\n'}) 648 expected_summary, {os.path.join('0', 'sekret'): 'foobar\n'})
633 finally: 649 finally:
634 os.remove(tmp) 650 os.remove(tmp)
635 651
636 def test_local_cache(self): 652 def test_local_cache(self):
637 # First task creates the cache, second copy the content to the output 653 # First task creates the cache, second copy the content to the output
638 # directory. Each time it's the exact same script. 654 # directory. Each time it's the exact same script.
655 dimensions = {
656 i['key']: i['value'] for i in self.client.query_bot()['dimensions']}
657 self.assertEqual(set(self.dimensions), set(dimensions))
658 self.assertNotIn(u'cache', set(dimensions))
639 script = '\n'.join(( 659 script = '\n'.join((
640 'import os, shutil, sys', 660 'import os, shutil, sys',
641 'p = "p/b/a.txt"', 661 'p = "p/b/a.txt"',
642 'if not os.path.isfile(p):', 662 'if not os.path.isfile(p):',
643 ' with open(p, "wb") as f:', 663 ' with open(p, "wb") as f:',
644 ' f.write("Yo!")', 664 ' f.write("Yo!")',
645 'else:', 665 'else:',
646 ' shutil.copy(p, sys.argv[1])', 666 ' shutil.copy(p, sys.argv[1])',
647 'print "hi"')) 667 'print "hi"'))
648 sizes = sorted([len(script), 200]) 668 sizes = sorted([len(script), 200])
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
685 u'initial_size': unicode(sum(sizes)), 705 u'initial_size': unicode(sum(sizes)),
686 u'items_cold': [], 706 u'items_cold': [],
687 u'items_hot': sizes, 707 u'items_hot': sizes,
688 }, 708 },
689 u'isolated_upload': { 709 u'isolated_upload': {
690 u'items_cold': [3, 110], 710 u'items_cold': [3, 110],
691 u'items_hot': [], 711 u'items_hot': [],
692 }, 712 },
693 }, 713 },
694 ) 714 )
715 # The previous task caused the bot to have a named cache.
716 expected_summary['bot_dimensions'][u'caches'] = [u'fuu']
695 self._run_isolated( 717 self._run_isolated(
696 script, 'cache_second', 718 script, 'cache_second',
697 ['--named-cache', 'fuu', 'p/b', '--', '${ISOLATED_OUTDIR}/yo'], 719 ['--named-cache', 'fuu', 'p/b', '--', '${ISOLATED_OUTDIR}/yo'],
698 expected_summary, 720 expected_summary,
699 {'0/yo': 'Yo!'}) 721 {'0/yo': 'Yo!'})
700 722
723 # Check that the bot now has a cache dimension by independently querying.
724 expected = set(self.dimensions)
725 expected.add(u'caches')
726 dimensions = {
727 i['key']: i['value'] for i in self.client.query_bot()['dimensions']}
728 self.assertEqual(expected, set(dimensions))
729
701 def _run_isolated(self, hello_world, name, args, expected_summary, 730 def _run_isolated(self, hello_world, name, args, expected_summary,
702 expected_files, deduped=False, isolated_content=None): 731 expected_files, deduped=False, isolated_content=None):
703 """Runs hello_world.py as an isolated file.""" 732 """Runs hello_world.py as an isolated file."""
704 # Shared code for all test_isolated_* test cases. 733 # Shared code for all test_isolated_* test cases.
705 tmpdir = tempfile.mkdtemp(prefix='swarming_smoke') 734 tmpdir = tempfile.mkdtemp(prefix='swarming_smoke')
706 try: 735 try:
707 isolate_path = os.path.join(tmpdir, 'i.isolate') 736 isolate_path = os.path.join(tmpdir, 'i.isolate')
708 isolated_path = os.path.join(tmpdir, 'i.isolated') 737 isolated_path = os.path.join(tmpdir, 'i.isolated')
709 with open(isolate_path, 'wb') as f: 738 with open(isolate_path, 'wb') as f:
710 json.dump(isolated_content or ISOLATE_HELLO_WORLD, f) 739 json.dump(isolated_content or ISOLATE_HELLO_WORLD, f)
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
843 servers.start() 872 servers.start()
844 bot = start_bot.LocalBot(servers.swarming_server.url) 873 bot = start_bot.LocalBot(servers.swarming_server.url)
845 Test.bot = bot 874 Test.bot = bot
846 bot.start() 875 bot.start()
847 client = SwarmingClient( 876 client = SwarmingClient(
848 servers.swarming_server.url, servers.isolate_server.url) 877 servers.swarming_server.url, servers.isolate_server.url)
849 # Test cases only interract with the client; except for test_update_continue 878 # Test cases only interract with the client; except for test_update_continue
850 # which mutates the bot. 879 # which mutates the bot.
851 Test.client = client 880 Test.client = client
852 Test.servers = servers 881 Test.servers = servers
882 while not client.query_bot():
883 # Wait for the bot to come online helps when the unit test cases query the
884 # bot. It may takes a few loop.
885 time.sleep(0.1)
853 failed = not unittest.main(exit=False).result.wasSuccessful() 886 failed = not unittest.main(exit=False).result.wasSuccessful()
854 887
855 # Then try to terminate the bot sanely. After the terminate request 888 # Then try to terminate the bot sanely. After the terminate request
856 # completed, the bot process should have terminated. Give it a few 889 # completed, the bot process should have terminated. Give it a few
857 # seconds due to delay between sending the event that the process is 890 # seconds due to delay between sending the event that the process is
858 # shutting down vs the process is shut down. 891 # shutting down vs the process is shut down.
859 if client.terminate(bot.bot_id) is not 0: 892 if client.terminate(bot.bot_id) is not 0:
860 print >> sys.stderr, 'swarming.py terminate failed' 893 print >> sys.stderr, 'swarming.py terminate failed'
861 failed = True 894 failed = True
862 try: 895 try:
863 bot.wait(10) 896 bot.wait(10)
864 except subprocess42.TimeoutExpired: 897 except subprocess42.TimeoutExpired:
865 print >> sys.stderr, 'Bot is still alive after swarming.py terminate' 898 print >> sys.stderr, 'Bot is still alive after swarming.py terminate'
866 failed = True 899 failed = True
867 except KeyboardInterrupt: 900 except KeyboardInterrupt:
868 print >> sys.stderr, '<Ctrl-C>' 901 print >> sys.stderr, '<Ctrl-C>'
869 failed = True 902 failed = True
870 if bot is not None and bot.poll() is None: 903 if bot is not None and bot.poll() is None:
871 bot.kill() 904 bot.kill()
872 bot.wait() 905 bot.wait()
873 finally: 906 finally:
874 cleanup(bot, client, servers, failed or verbose, leak) 907 cleanup(bot, client, servers, failed or verbose, leak)
875 return int(failed) 908 return int(failed)
876 909
877 910
878 if __name__ == '__main__': 911 if __name__ == '__main__':
879 sys.exit(main()) 912 sys.exit(main())
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698