10969: Add docker_image_formats server config, and corresponding check in `arv keep...
[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
17
18 class StopTest(Exception):
19     pass
20
21
22 class ArvKeepdockerTestCase(unittest.TestCase):
23     def run_arv_keepdocker(self, args):
24         sys.argv = ['arv-keepdocker'] + args
25         return arv_keepdocker.main()
26
27     def test_unsupported_arg(self):
28         with self.assertRaises(SystemExit):
29             self.run_arv_keepdocker(['-x=unknown'])
30
31     def test_version_argument(self):
32         err = io.BytesIO()
33         out = io.BytesIO()
34         with tutil.redirected_streams(stdout=out, stderr=err):
35             with self.assertRaises(SystemExit):
36                 self.run_arv_keepdocker(['--version'])
37         self.assertEqual(out.getvalue(), '')
38         self.assertRegexpMatches(err.getvalue(), "[0-9]+\.[0-9]+\.[0-9]+")
39
40     @mock.patch('arvados.commands.keepdocker.find_image_hashes',
41                 return_value=['abc123'])
42     @mock.patch('arvados.commands.keepdocker.find_one_image_hash',
43                 return_value='abc123')
44     def test_image_format_compatibility(self, _1, _2):
45         old_id = hashlib.sha256('old').hexdigest()
46         new_id = 'sha256:'+hashlib.sha256('new').hexdigest()
47         for supported, img_id, expect_ok in [
48                 (['v1'], old_id, True),
49                 (['v1'], new_id, False),
50                 (None, old_id, True),
51                 ([], old_id, True),
52                 ([], new_id, True),
53                 (['v1', 'v2'], new_id, True),
54                 (['v1'], new_id, False),
55                 (['v2'], new_id, True)]:
56
57             fakeDD = arvados.api('v1')._rootDesc
58             if supported is None:
59                 del fakeDD['dockerImageFormats']
60             else:
61                 fakeDD['dockerImageFormats'] = supported
62
63             err = io.BytesIO()
64             out = io.BytesIO()
65
66             with tutil.redirected_streams(stdout=out, stderr=err), \
67                  mock.patch('arvados.api') as api, \
68                  mock.patch('arvados.commands.keepdocker.popen_docker',
69                             return_value=subprocess.Popen(
70                                 ['echo', img_id],
71                                 stdout=subprocess.PIPE)), \
72                  mock.patch('arvados.commands.keepdocker.prep_image_file',
73                             side_effect=StopTest), \
74                  self.assertRaises(StopTest if expect_ok else SystemExit):
75
76                 api()._rootDesc = fakeDD
77                 self.run_arv_keepdocker(['--force', 'testimage'])
78
79             self.assertEqual(out.getvalue(), '')
80             if expect_ok:
81                 self.assertNotRegexpMatches(
82                     err.getvalue(), "refusing to store",
83                     msg=repr((supported, img_id)))
84             else:
85                 self.assertRegexpMatches(
86                     err.getvalue(), "refusing to store",
87                     msg=repr((supported, img_id)))
88             if not supported:
89                 self.assertRegexpMatches(
90                     err.getvalue(),
91                     "server does not specify supported image formats",
92                     msg=repr((supported, img_id)))
93
94         fakeDD = arvados.api('v1')._rootDesc
95         fakeDD['dockerImageFormats'] = ['v1']
96         err = io.BytesIO()
97         out = io.BytesIO()
98         with tutil.redirected_streams(stdout=out, stderr=err), \
99              mock.patch('arvados.api') as api, \
100              mock.patch('arvados.commands.keepdocker.popen_docker',
101                         return_value=subprocess.Popen(
102                             ['echo', new_id],
103                             stdout=subprocess.PIPE)), \
104              mock.patch('arvados.commands.keepdocker.prep_image_file',
105                         side_effect=StopTest), \
106              self.assertRaises(StopTest):
107             api()._rootDesc = fakeDD
108             self.run_arv_keepdocker(
109                 ['--force', '--force-image-format', 'testimage'])
110         self.assertRegexpMatches(err.getvalue(), "forcing incompatible image")