# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Test overlay."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import shutil
import subprocess
import tempfile
import unittest
from . import config
from . import overlay
import re
class BindOverlayTest(unittest.TestCase):
def setUp(self):
self.source_dir = tempfile.mkdtemp()
self.destination_dir = tempfile.mkdtemp()
#
# base_dir/
# base_project/
# .git
# no_git_dir/
# no_git_subdir1/
# no_git_file1
# no_git_subdir2/
# no_git_file2
# overlays/
# unittest1/
# from_dir/
# .git/
# upper_subdir/
# lower_subdir/
# from_unittest1/
# .git/
# from_file
# unittest2/
# upper_subdir/
# lower_subdir/
# from_unittest2/
# .git/
# no_git_dir2/
# no_git_subdir1/
# no_git_subdir2/
# .bindmount
#
os.mkdir(os.path.join(self.source_dir, 'base_dir'))
os.mkdir(os.path.join(self.source_dir, 'base_dir', 'base_project'))
os.mkdir(os.path.join(self.source_dir, 'base_dir', 'base_project', '.git'))
os.mkdir(os.path.join(self.source_dir, 'no_git_dir'))
os.mkdir(os.path.join(self.source_dir, 'no_git_dir', 'no_git_subdir1'))
open(os.path.join(self.source_dir,
'no_git_dir', 'no_git_subdir1', 'no_git_file1'), 'a').close()
os.mkdir(os.path.join(self.source_dir, 'no_git_dir', 'no_git_subdir2'))
open(os.path.join(self.source_dir,
'no_git_dir', 'no_git_subdir2', 'no_git_file2'), 'a').close()
os.mkdir(os.path.join(self.source_dir, 'overlays'))
os.mkdir(os.path.join(self.source_dir,
'overlays', 'unittest1'))
os.mkdir(os.path.join(self.source_dir,
'overlays', 'unittest1', 'from_dir'))
os.mkdir(os.path.join(self.source_dir,
'overlays', 'unittest1', 'from_dir', '.git'))
os.mkdir(os.path.join(self.source_dir,
'overlays', 'unittest1', 'upper_subdir'))
os.mkdir(os.path.join(self.source_dir,
'overlays', 'unittest1', 'upper_subdir',
'lower_subdir'))
os.mkdir(os.path.join(self.source_dir,
'overlays', 'unittest1', 'upper_subdir',
'lower_subdir', 'from_unittest1'))
os.mkdir(os.path.join(self.source_dir,
'overlays', 'unittest1', 'upper_subdir',
'lower_subdir', 'from_unittest1', '.git'))
os.symlink(
os.path.join(self.source_dir, 'overlays', 'unittest1',
'upper_subdir', 'lower_subdir'),
os.path.join(self.source_dir, 'overlays', 'unittest1',
'upper_subdir', 'subdir_symlink')
)
open(os.path.join(self.source_dir,
'overlays', 'unittest1', 'from_file'), 'a').close()
os.mkdir(os.path.join(self.source_dir,
'overlays', 'unittest2'))
os.mkdir(os.path.join(self.source_dir,
'overlays', 'unittest2', 'upper_subdir'))
os.mkdir(os.path.join(self.source_dir,
'overlays', 'unittest2', 'upper_subdir',
'lower_subdir'))
os.mkdir(os.path.join(self.source_dir,
'overlays', 'unittest2', 'upper_subdir',
'lower_subdir', 'from_unittest2'))
os.mkdir(os.path.join(self.source_dir,
'overlays', 'unittest2', 'upper_subdir',
'lower_subdir', 'from_unittest2', '.git'))
os.mkdir(os.path.join(self.source_dir, 'overlays', 'no_git_dir2'))
os.mkdir(os.path.join(self.source_dir,
'overlays', 'no_git_dir2', 'no_git_subdir1'))
os.mkdir(os.path.join(self.source_dir,
'overlays', 'no_git_dir2', 'no_git_subdir2'))
open(os.path.join(self.source_dir,
'overlays', 'no_git_dir2', 'no_git_subdir2', '.bindmount'),
'a').close()
def tearDown(self):
shutil.rmtree(self.source_dir)
def testValidTargetOverlayBinds(self):
with tempfile.NamedTemporaryFile('w+t') as test_config:
test_config.write(
''
''
' '
' '
' '
' '
' '
' '
''
)
test_config.flush()
o = overlay.BindOverlay(
cfg=config.factory(test_config.name),
build_target='unittest',
source_dir=self.source_dir)
self.assertIsNotNone(o)
bind_mounts = o.GetBindMounts()
bind_source = os.path.join(self.source_dir, 'overlays/unittest1/from_dir')
bind_destination = os.path.join(self.source_dir, 'from_dir')
self.assertEqual(bind_mounts[bind_destination], overlay.BindMount(bind_source, True, False))
self.assertIn(os.path.join(self.source_dir, 'base_dir', 'base_project'), bind_mounts)
def testValidTargetOverlayBindsAllowedProjects(self):
with tempfile.NamedTemporaryFile('w+t') as test_config, \
tempfile.NamedTemporaryFile('w+t') as test_allowed_projects:
test_config.write(
''
''
' '
' '
' '
' '
' '
' '
'' % test_allowed_projects.name
)
test_config.flush()
test_allowed_projects.write(
''
''
' '
''
)
test_allowed_projects.flush()
o = overlay.BindOverlay(
cfg=config.factory(test_config.name),
build_target='unittest',
source_dir=self.source_dir)
self.assertIsNotNone(o)
bind_mounts = o.GetBindMounts()
self.assertIn(os.path.join(self.source_dir, 'from_dir'), bind_mounts)
self.assertNotIn(os.path.join(self.source_dir, 'base_dir', 'base_project'), bind_mounts)
def testMultipleOverlays(self):
with tempfile.NamedTemporaryFile('w+t') as test_config:
test_config.write(
''
''
' '
' '
' '
' '
' '
' '
' '
''
)
test_config.flush()
o = overlay.BindOverlay(
cfg=config.factory(test_config.name),
build_target='unittest',
source_dir=self.source_dir)
self.assertIsNotNone(o)
bind_mounts = o.GetBindMounts()
bind_source = os.path.join(self.source_dir,
'overlays/unittest1/upper_subdir/lower_subdir/from_unittest1')
bind_destination = os.path.join(self.source_dir, 'upper_subdir/lower_subdir/from_unittest1')
self.assertEqual(bind_mounts[bind_destination], overlay.BindMount(bind_source, True, False))
bind_source = os.path.join(self.source_dir,
'overlays/unittest2/upper_subdir/lower_subdir/from_unittest2')
bind_destination = os.path.join(self.source_dir,
'upper_subdir/lower_subdir/from_unittest2')
self.assertEqual(bind_mounts[bind_destination], overlay.BindMount(bind_source, True, False))
def testMultipleOverlaysWithAllowlist(self):
with tempfile.NamedTemporaryFile('w+t') as test_config:
test_config.write(
''
''
' '
' '
' '
' '
' '
' '
' '
' '
''
)
test_config.flush()
o = overlay.BindOverlay(
cfg=config.factory(test_config.name),
build_target='unittest',
source_dir=self.source_dir)
self.assertIsNotNone(o)
bind_mounts = o.GetBindMounts()
bind_source = os.path.join(self.source_dir,
'overlays/unittest1/upper_subdir/lower_subdir/from_unittest1')
bind_destination = os.path.join(self.source_dir, 'upper_subdir/lower_subdir/from_unittest1')
self.assertEqual(
bind_mounts[bind_destination],
overlay.BindMount(source_dir=bind_source, readonly=False, allows_replacement=False))
bind_source = os.path.join(self.source_dir,
'overlays/unittest2/upper_subdir/lower_subdir/from_unittest2')
bind_destination = os.path.join(self.source_dir,
'upper_subdir/lower_subdir/from_unittest2')
self.assertEqual(bind_mounts[bind_destination], overlay.BindMount(bind_source, True, False))
def testAllowReadWriteNoGitDir(self):
with tempfile.NamedTemporaryFile('w+t') as test_config:
test_config.write(
''
''
' '
' '
' '
' '
' '
' '
' '
' '
''
)
test_config.flush()
o = overlay.BindOverlay(
cfg=config.factory(test_config.name),
build_target='unittest',
source_dir=self.source_dir)
self.assertIsNotNone(o)
bind_mounts = o.GetBindMounts()
bind_source = os.path.join(self.source_dir,
'no_git_dir/no_git_subdir1')
bind_destination = os.path.join(self.source_dir, 'no_git_dir/no_git_subdir1')
self.assertIn(bind_destination, bind_mounts)
self.assertEqual(
bind_mounts[bind_destination],
overlay.BindMount(source_dir=bind_source, readonly=False, allows_replacement=False))
bind_source = os.path.join(self.source_dir,
'no_git_dir/no_git_subdir2')
bind_destination = os.path.join(self.source_dir,
'no_git_dir/no_git_subdir2')
self.assertIn(bind_destination, bind_mounts)
self.assertEqual(bind_mounts[bind_destination], overlay.BindMount(bind_source, True, False))
def testValidOverlaidDir(self):
with tempfile.NamedTemporaryFile('w+t') as test_config:
test_config.write(
''
''
' '
' '
' '
' '
' '
' '
''
)
test_config.flush()
o = overlay.BindOverlay(
cfg=config.factory(test_config.name),
build_target='unittest',
source_dir=self.source_dir,
destination_dir=self.destination_dir)
self.assertIsNotNone(o)
bind_mounts = o.GetBindMounts()
bind_source = os.path.join(self.source_dir, 'overlays/unittest1/from_dir')
bind_destination = os.path.join(self.destination_dir, 'from_dir')
self.assertEqual(bind_mounts[bind_destination], overlay.BindMount(bind_source, True, False))
def testValidFilesystemViewDirectoryBind(self):
with tempfile.NamedTemporaryFile('w+t') as test_config:
test_config.write(
''
''
' '
' '
' '
' '
' '
' '
' '
' '
' '
''
)
test_config.flush()
o = overlay.BindOverlay(
cfg=config.factory(test_config.name),
build_target='unittest',
source_dir=self.source_dir)
self.assertIsNotNone(o)
bind_mounts = o.GetBindMounts()
bind_source = os.path.join(self.source_dir, 'overlays/unittest1/from_dir')
bind_destination = os.path.join(self.source_dir, 'to_dir')
self.assertEqual(bind_mounts[bind_destination], overlay.BindMount(bind_source, True, False))
def testValidFilesystemViewFileBind(self):
with tempfile.NamedTemporaryFile('w+t') as test_config:
test_config.write(
''
''
' '
' '
' '
' '
' '
' '
' '
' '
' '
''
)
test_config.flush()
o = overlay.BindOverlay(
cfg=config.factory(test_config.name),
build_target='unittest',
source_dir=self.source_dir)
self.assertIsNotNone(o)
bind_mounts = o.GetBindMounts()
bind_source = os.path.join(self.source_dir, 'overlays/unittest1/from_file')
bind_destination = os.path.join(self.source_dir, 'to_file')
self.assertEqual(bind_mounts[bind_destination], overlay.BindMount(bind_source, True, False))
def testInvalidTarget(self):
with tempfile.NamedTemporaryFile('w+t') as test_config:
test_config.write(
''
''
' '
' '
' '
' '
' '
' '
''
)
test_config.flush()
with self.assertRaises(KeyError):
overlay.BindOverlay(
cfg=config.factory(test_config.name),
build_target='unknown',
source_dir=self.source_dir)
def testExplicitBindMount(self):
with tempfile.NamedTemporaryFile('w+t') as test_config:
test_config.write(
''
''
' '
' '
' '
' '
' '
' '
''
)
test_config.flush()
o = overlay.BindOverlay(
cfg=config.factory(test_config.name),
build_target='target_name',
source_dir=self.source_dir)
self.assertIsNotNone(o)
bind_mounts = o.GetBindMounts()
bind_source = os.path.join(self.source_dir, 'overlays/no_git_dir2/no_git_subdir1')
bind_destination = os.path.join(self.source_dir, 'no_git_subdir1')
self.assertEqual(bind_mounts[bind_destination], overlay.BindMount(bind_source, True, False))
bind_source = os.path.join(self.source_dir, 'overlays/no_git_dir2/no_git_subdir2')
bind_destination = os.path.join(self.source_dir, 'no_git_subdir2')
self.assertEqual(bind_mounts[bind_destination], overlay.BindMount(bind_source, True, False))
def testReplacementPath(self):
with tempfile.NamedTemporaryFile('w+t') as test_config:
test_config.write(
''
''
' '
' '
' '
' '
' '
' '
' '
' '
''
)
test_config.flush()
o = overlay.BindOverlay(
cfg=config.factory(test_config.name),
build_target='unittest',
source_dir=self.source_dir)
self.assertIsNotNone(o)
bind_mounts = o.GetBindMounts()
bind_source = os.path.join(self.source_dir, 'overlays/unittest1/from_dir')
bind_destination = os.path.join(self.source_dir, 'from_dir')
self.assertEqual(bind_mounts[bind_destination],
overlay.BindMount(bind_source, True, True))
if __name__ == '__main__':
unittest.main()