1# Copyright 2020 Google LLC 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# https://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"""Test overlay.""" 16 17from __future__ import absolute_import 18from __future__ import division 19from __future__ import print_function 20 21import os 22import shutil 23import subprocess 24import tempfile 25import unittest 26from . import overlay 27import re 28 29 30class BindOverlayTest(unittest.TestCase): 31 32 def setUp(self): 33 self.source_dir = tempfile.mkdtemp() 34 self.destination_dir = tempfile.mkdtemp() 35 os.mkdir(os.path.join(self.source_dir, 'base_dir')) 36 os.mkdir(os.path.join(self.source_dir, 'base_dir', 'base_project')) 37 os.mkdir(os.path.join(self.source_dir, 'base_dir', 'base_project', '.git')) 38 os.mkdir(os.path.join(self.source_dir, 'overlays')) 39 os.mkdir(os.path.join(self.source_dir, 40 'overlays', 'unittest1')) 41 os.mkdir(os.path.join(self.source_dir, 42 'overlays', 'unittest1', 'from_dir')) 43 os.mkdir(os.path.join(self.source_dir, 44 'overlays', 'unittest1', 'from_dir', '.git')) 45 os.mkdir(os.path.join(self.source_dir, 46 'overlays', 'unittest1', 'upper_subdir')) 47 os.mkdir(os.path.join(self.source_dir, 48 'overlays', 'unittest1', 'upper_subdir', 49 'lower_subdir')) 50 os.mkdir(os.path.join(self.source_dir, 51 'overlays', 'unittest1', 'upper_subdir', 52 'lower_subdir', 'from_unittest1')) 53 os.mkdir(os.path.join(self.source_dir, 54 'overlays', 'unittest1', 'upper_subdir', 55 'lower_subdir', 'from_unittest1', '.git')) 56 os.symlink( 57 os.path.join(self.source_dir, 'overlays', 'unittest1', 58 'upper_subdir', 'lower_subdir'), 59 os.path.join(self.source_dir, 'overlays', 'unittest1', 60 'upper_subdir', 'subdir_symlink') 61 ) 62 open(os.path.join(self.source_dir, 63 'overlays', 'unittest1', 'from_file'), 'a').close() 64 os.mkdir(os.path.join(self.source_dir, 65 'overlays', 'unittest2')) 66 os.mkdir(os.path.join(self.source_dir, 67 'overlays', 'unittest2', 'upper_subdir')) 68 os.mkdir(os.path.join(self.source_dir, 69 'overlays', 'unittest2', 'upper_subdir', 70 'lower_subdir')) 71 os.mkdir(os.path.join(self.source_dir, 72 'overlays', 'unittest2', 'upper_subdir', 73 'lower_subdir', 'from_unittest2')) 74 os.mkdir(os.path.join(self.source_dir, 75 'overlays', 'unittest2', 'upper_subdir', 76 'lower_subdir', 'from_unittest2', '.git')) 77 78 def tearDown(self): 79 shutil.rmtree(self.source_dir) 80 81 def testValidTargetOverlayBinds(self): 82 with tempfile.NamedTemporaryFile('w+t') as test_config: 83 test_config.write( 84 '<?xml version="1.0" encoding="UTF-8" ?>' 85 '<config>' 86 ' <target name="unittest">' 87 ' <overlay name="unittest1"/>' 88 ' </target>' 89 '</config>' 90 ) 91 test_config.flush() 92 o = overlay.BindOverlay( 93 config_file=test_config.name, 94 target='unittest', 95 source_dir=self.source_dir) 96 self.assertIsNotNone(o) 97 bind_mounts = o.GetBindMounts() 98 bind_source = os.path.join(self.source_dir, 'overlays/unittest1/from_dir') 99 bind_destination = os.path.join(self.source_dir, 'from_dir') 100 self.assertEqual(bind_mounts[bind_destination], overlay.BindMount(bind_source, False)) 101 102 def testMultipleOverlays(self): 103 with tempfile.NamedTemporaryFile('w+t') as test_config: 104 test_config.write( 105 '<?xml version="1.0" encoding="UTF-8" ?>' 106 '<config>' 107 ' <target name="unittest">' 108 ' <overlay name="unittest1"/>' 109 ' <overlay name="unittest2"/>' 110 ' </target>' 111 '</config>' 112 ) 113 test_config.flush() 114 o = overlay.BindOverlay( 115 config_file=test_config.name, 116 target='unittest', 117 source_dir=self.source_dir) 118 self.assertIsNotNone(o) 119 bind_mounts = o.GetBindMounts() 120 bind_source = os.path.join(self.source_dir, 121 'overlays/unittest1/upper_subdir/lower_subdir/from_unittest1') 122 bind_destination = os.path.join(self.source_dir, 'upper_subdir/lower_subdir/from_unittest1') 123 self.assertEqual(bind_mounts[bind_destination], overlay.BindMount(bind_source, False)) 124 bind_source = os.path.join(self.source_dir, 125 'overlays/unittest2/upper_subdir/lower_subdir/from_unittest2') 126 bind_destination = os.path.join(self.source_dir, 127 'upper_subdir/lower_subdir/from_unittest2') 128 self.assertEqual(bind_mounts[bind_destination], overlay.BindMount(bind_source, False)) 129 130 def testMultipleOverlaysWithWhitelist(self): 131 with tempfile.NamedTemporaryFile('w+t') as test_config: 132 test_config.write( 133 '<?xml version="1.0" encoding="UTF-8" ?>' 134 '<config>' 135 ' <target name="unittest">' 136 ' <overlay name="unittest1"/>' 137 ' <overlay name="unittest2"/>' 138 ' </target>' 139 '</config>' 140 ) 141 test_config.flush() 142 rw_whitelist = set('overlays/unittest1/uppser_subdir/lower_subdir/from_unittest1') 143 o = overlay.BindOverlay( 144 config_file=test_config.name, 145 target='unittest', 146 source_dir=self.source_dir) 147 self.assertIsNotNone(o) 148 bind_mounts = o.GetBindMounts() 149 bind_source = os.path.join(self.source_dir, 150 'overlays/unittest1/upper_subdir/lower_subdir/from_unittest1') 151 bind_destination = os.path.join(self.source_dir, 'upper_subdir/lower_subdir/from_unittest1') 152 self.assertEqual( 153 bind_mounts[bind_destination], 154 overlay.BindMount(source_dir=bind_source, readonly=False)) 155 bind_source = os.path.join(self.source_dir, 156 'overlays/unittest2/upper_subdir/lower_subdir/from_unittest2') 157 bind_destination = os.path.join(self.source_dir, 158 'upper_subdir/lower_subdir/from_unittest2') 159 self.assertEqual(bind_mounts[bind_destination], overlay.BindMount(bind_source, False)) 160 161 def testValidOverlaidDir(self): 162 with tempfile.NamedTemporaryFile('w+t') as test_config: 163 test_config.write( 164 '<?xml version="1.0" encoding="UTF-8" ?>' 165 '<config>' 166 ' <target name="unittest">' 167 ' <overlay name="unittest1"/>' 168 ' </target>' 169 '</config>' 170 ) 171 test_config.flush() 172 o = overlay.BindOverlay( 173 config_file=test_config.name, 174 target='unittest', 175 source_dir=self.source_dir, 176 destination_dir=self.destination_dir) 177 self.assertIsNotNone(o) 178 bind_mounts = o.GetBindMounts() 179 bind_source = os.path.join(self.source_dir, 'overlays/unittest1/from_dir') 180 bind_destination = os.path.join(self.destination_dir, 'from_dir') 181 self.assertEqual(bind_mounts[bind_destination], overlay.BindMount(bind_source, False)) 182 183 def testValidFilesystemViewDirectoryBind(self): 184 with tempfile.NamedTemporaryFile('w+t') as test_config: 185 test_config.write( 186 '<?xml version="1.0" encoding="UTF-8" ?>' 187 '<config>' 188 ' <target name="unittest">' 189 ' <view name="unittestview"/>' 190 ' </target>' 191 ' <view name="unittestview">' 192 ' <path source="overlays/unittest1/from_dir" ' 193 ' destination="to_dir"/>' 194 ' </view>' 195 '</config>' 196 ) 197 test_config.flush() 198 o = overlay.BindOverlay( 199 config_file=test_config.name, 200 target='unittest', 201 source_dir=self.source_dir) 202 self.assertIsNotNone(o) 203 bind_mounts = o.GetBindMounts() 204 bind_source = os.path.join(self.source_dir, 'overlays/unittest1/from_dir') 205 bind_destination = os.path.join(self.source_dir, 'to_dir') 206 self.assertEqual(bind_mounts[bind_destination], overlay.BindMount(bind_source, False)) 207 208 def testValidFilesystemViewFileBind(self): 209 with tempfile.NamedTemporaryFile('w+t') as test_config: 210 test_config.write( 211 '<?xml version="1.0" encoding="UTF-8" ?>' 212 '<config>' 213 ' <target name="unittest">' 214 ' <view name="unittestview"/>' 215 ' </target>' 216 ' <view name="unittestview">' 217 ' <path source="overlays/unittest1/from_file" ' 218 ' destination="to_file"/>' 219 ' </view>' 220 '</config>' 221 ) 222 test_config.flush() 223 o = overlay.BindOverlay( 224 config_file=test_config.name, 225 target='unittest', 226 source_dir=self.source_dir) 227 self.assertIsNotNone(o) 228 bind_mounts = o.GetBindMounts() 229 bind_source = os.path.join(self.source_dir, 'overlays/unittest1/from_file') 230 bind_destination = os.path.join(self.source_dir, 'to_file') 231 self.assertEqual(bind_mounts[bind_destination], overlay.BindMount(bind_source, False)) 232 233 def testInvalidTarget(self): 234 with tempfile.NamedTemporaryFile('w+t') as test_config: 235 test_config.write( 236 '<?xml version="1.0" encoding="UTF-8" ?>' 237 '<config>' 238 ' <target name="unittest">' 239 ' <overlay name="unittest1"/>' 240 ' </target>' 241 '</config>' 242 ) 243 test_config.flush() 244 with self.assertRaises(KeyError): 245 overlay.BindOverlay( 246 config_file=test_config.name, 247 target='unknown', 248 source_dir=self.source_dir) 249 250 251if __name__ == '__main__': 252 unittest.main() 253