11002: Merge branch 'master' into 11002-arvput-crash-fix
[arvados.git] / sdk / python / tests / test_arv_keepdocker.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 import arvados
5 import hashlib
6 import io
7 import mock
8 import os
9 import subprocess
10 import sys
11 import tempfile
12 import unittest
13
14 import arvados.commands.keepdocker as arv_keepdocker
15 import arvados_testutil as tutil
16 import run_test_server
17
18
19 class StopTest(Exception):
20     pass
21
22
23 class ArvKeepdockerTestCase(unittest.TestCase):
24     def run_arv_keepdocker(self, args):
25         sys.argv = ['arv-keepdocker'] + args
26         return arv_keepdocker.main()
27
28     def test_unsupported_arg(self):
29         with self.assertRaises(SystemExit):
30             self.run_arv_keepdocker(['-x=unknown'])
31
32     def test_version_argument(self):
33         err = io.BytesIO()
34         out = io.BytesIO()
35         with tutil.redirected_streams(stdout=out, stderr=err):
36             with self.assertRaises(SystemExit):
37                 self.run_arv_keepdocker(['--version'])
38         self.assertEqual(out.getvalue(), '')
39         self.assertRegexpMatches(err.getvalue(), "[0-9]+\.[0-9]+\.[0-9]+")
40
41     def test_migrate19(self):
42         try:
43             sys.argv = ['arv-migrate-docker19']
44
45             added = arv_keepdocker.migrate19()
46             self.assertEqual(len(added), 1)
47             self.assertEqual(added[0]['link_class'], 'docker_image_migration')
48             self.assertEqual(added[0]['name'], 'migrate_1.9_1.10')
49             self.assertEqual(added[0]['tail_uuid'], 'fa3c1a9cb6783f85f2ecda037e07b8c3+167')
50             self.assertEqual(added[0]['head_uuid'], 'd740a57097711e08eb9b2a93518f20ab+174')
51
52             added = arv_keepdocker.migrate19()
53             self.assertEqual(added, [])
54         finally:
55             run_test_server.reset()
56
57     @mock.patch('arvados.commands.keepdocker.find_image_hashes',
58                 return_value=['abc123'])
59     @mock.patch('arvados.commands.keepdocker.find_one_image_hash',
60                 return_value='abc123')
61     def test_image_format_compatibility(self, _1, _2):
62         old_id = hashlib.sha256('old').hexdigest()
63         new_id = 'sha256:'+hashlib.sha256('new').hexdigest()
64         for supported, img_id, expect_ok in [
65                 (['v1'], old_id, True),
66                 (['v1'], new_id, False),
67                 (None, old_id, True),
68                 ([], old_id, True),
69                 ([], new_id, True),
70                 (['v1', 'v2'], new_id, True),
71                 (['v1'], new_id, False),
72                 (['v2'], new_id, True)]:
73
74             fakeDD = arvados.api('v1')._rootDesc
75             if supported is None:
76                 del fakeDD['dockerImageFormats']
77             else:
78                 fakeDD['dockerImageFormats'] = supported
79
80             err = io.BytesIO()
81             out = io.BytesIO()
82
83             with tutil.redirected_streams(stdout=out, stderr=err), \
84                  mock.patch('arvados.api') as api, \
85                  mock.patch('arvados.commands.keepdocker.popen_docker',
86                             return_value=subprocess.Popen(
87                                 ['echo', img_id],
88                                 stdout=subprocess.PIPE)), \
89                  mock.patch('arvados.commands.keepdocker.prep_image_file',
90                             side_effect=StopTest), \
91                  self.assertRaises(StopTest if expect_ok else SystemExit):
92
93                 api()._rootDesc = fakeDD
94                 self.run_arv_keepdocker(['--force', 'testimage'])
95
96             self.assertEqual(out.getvalue(), '')
97             if expect_ok:
98                 self.assertNotRegexpMatches(
99                     err.getvalue(), "refusing to store",
100                     msg=repr((supported, img_id)))
101             else:
102                 self.assertRegexpMatches(
103                     err.getvalue(), "refusing to store",
104                     msg=repr((supported, img_id)))
105             if not supported:
106                 self.assertRegexpMatches(
107                     err.getvalue(),
108                     "server does not specify supported image formats",
109                     msg=repr((supported, img_id)))
110
111         fakeDD = arvados.api('v1')._rootDesc
112         fakeDD['dockerImageFormats'] = ['v1']
113         err = io.BytesIO()
114         out = io.BytesIO()
115         with tutil.redirected_streams(stdout=out, stderr=err), \
116              mock.patch('arvados.api') as api, \
117              mock.patch('arvados.commands.keepdocker.popen_docker',
118                         return_value=subprocess.Popen(
119                             ['echo', new_id],
120                             stdout=subprocess.PIPE)), \
121              mock.patch('arvados.commands.keepdocker.prep_image_file',
122                         side_effect=StopTest), \
123              self.assertRaises(StopTest):
124             api()._rootDesc = fakeDD
125             self.run_arv_keepdocker(
126                 ['--force', '--force-image-format', 'testimage'])
127         self.assertRegexpMatches(err.getvalue(), "forcing incompatible image")