Skip to content
This repository was archived by the owner on Jun 4, 2021. It is now read-only.

Commit 7733899

Browse files
committed
Add failing regression test for opaque whiteout handling in flattener
1 parent 6404e32 commit 7733899

File tree

2 files changed

+129
-0
lines changed

2 files changed

+129
-0
lines changed

BUILD.bazel

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,14 @@ sh_test(
120120
":pusher.par",
121121
],
122122
)
123+
124+
125+
py_test(
126+
name = "client_v2_2_unit_tests",
127+
size = "large",
128+
srcs = [
129+
"client_v2_2_unit_tests.py",
130+
":containerregistry",
131+
],
132+
main = "client_v2_2_unit_tests.py",
133+
)

client_v2_2_unit_tests.py

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# Copyright 2018 Google Inc. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from collections import OrderedDict
16+
import io
17+
import tarfile
18+
import unittest
19+
20+
from containerregistry.client.v2_2 import docker_image as v2_2_image
21+
22+
23+
class MockImage(object):
24+
def __init__(self):
25+
self._fs_layers = OrderedDict()
26+
27+
def add_layer(self, filenames):
28+
buf = io.BytesIO()
29+
with tarfile.open(mode='w:', fileobj=buf) as tf:
30+
for name in filenames:
31+
tarinfo = tarfile.TarInfo(name)
32+
if name.endswith("/"):
33+
tarinfo.type = tarfile.DIRTYPE
34+
tf.addfile(tarinfo)
35+
buf.seek(0)
36+
new_layer_id = str(len(self._fs_layers))
37+
self._fs_layers[new_layer_id] = buf.getvalue()
38+
39+
def diff_ids(self):
40+
return reversed(self._fs_layers.keys())
41+
42+
def uncompressed_layer(self, layer_id):
43+
return self._fs_layers[layer_id]
44+
45+
46+
class TestExtract(unittest.TestCase):
47+
48+
def _test_flatten(self, layer_filenames, expected_output_filenames):
49+
img = MockImage()
50+
for filenames in layer_filenames:
51+
img.add_layer(filenames)
52+
buf = io.BytesIO()
53+
with tarfile.open(mode='w:', fileobj=buf) as tar:
54+
v2_2_image.extract(img, tar)
55+
buf.seek(0)
56+
output_filenames = []
57+
with tarfile.open(mode='r', fileobj=buf) as tar:
58+
for tarinfo in tar:
59+
if tarinfo.isdir():
60+
output_filenames.append(tarinfo.name + "/")
61+
else:
62+
output_filenames.append(tarinfo.name)
63+
self.assertEqual(output_filenames, expected_output_filenames)
64+
65+
def test_single_layer(self):
66+
self._test_flatten(
67+
[["/directory/", "/file"]],
68+
["/directory/", "/file"]
69+
)
70+
71+
def test_purely_additive_layers(self):
72+
self._test_flatten(
73+
[
74+
["dir/", "dir/file1", "file"],
75+
["dir/file2", "file2"]
76+
],
77+
["dir/file2", "file2", "dir/", "dir/file1", "file"]
78+
)
79+
80+
def test_single_file_whiteout(self):
81+
self._test_flatten(
82+
[
83+
["/foo"],
84+
["/.wh.foo"]
85+
],
86+
[]
87+
)
88+
89+
def test_parent_directory_whiteout(self):
90+
self._test_flatten(
91+
[
92+
["/x/a/", "/x/b/", "/x/b/1"],
93+
["/x/.wh.b"]
94+
],
95+
["/x/a/"]
96+
)
97+
98+
def test_opaque_whiteout(self):
99+
# Examples from https://github.com/opencontainers/image-spec/blob/master/layer.md#whiteouts
100+
self._test_flatten(
101+
[
102+
["a/", "a/b/", "a/b/c/", "a/b/c/bar"],
103+
["a/", "a/.wh..wh..opq", "a/b/", "a/b/c/", "a/b/c/foo"],
104+
],
105+
["a/", "a/b/", "a/b/c/", "a/b/c/foo"],
106+
)
107+
108+
self._test_flatten(
109+
[
110+
["a/", "a/b/", "a/b/c/", "a/b/c/bar"],
111+
["a/", "a/b/", "a/b/c/", "a/b/c/foo", "a/.wh..wh..opq"],
112+
],
113+
["a/", "a/b/", "a/b/c/", "a/b/c/foo"],
114+
)
115+
116+
117+
if __name__ == "__main__":
118+
unittest.main(verbosity=2)

0 commit comments

Comments
 (0)