xref: /aosp_15_r20/tools/asuite/atest/integration_tests/snapshot_unittest.py (revision c2e18aaa1096c836b086f94603d04f4eb9cf37f5)
1*c2e18aaaSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*c2e18aaaSAndroid Build Coastguard Worker#
3*c2e18aaaSAndroid Build Coastguard Worker# Copyright 2024, The Android Open Source Project
4*c2e18aaaSAndroid Build Coastguard Worker#
5*c2e18aaaSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*c2e18aaaSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*c2e18aaaSAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*c2e18aaaSAndroid Build Coastguard Worker#
9*c2e18aaaSAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
10*c2e18aaaSAndroid Build Coastguard Worker#
11*c2e18aaaSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*c2e18aaaSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*c2e18aaaSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*c2e18aaaSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*c2e18aaaSAndroid Build Coastguard Worker# limitations under the License.
16*c2e18aaaSAndroid Build Coastguard Worker
17*c2e18aaaSAndroid Build Coastguard Worker"""Unit test for the Snapshot module."""
18*c2e18aaaSAndroid Build Coastguard Worker
19*c2e18aaaSAndroid Build Coastguard Workerimport json
20*c2e18aaaSAndroid Build Coastguard Workerimport os
21*c2e18aaaSAndroid Build Coastguard Workerimport pathlib
22*c2e18aaaSAndroid Build Coastguard Workerimport shutil
23*c2e18aaaSAndroid Build Coastguard Workerimport tempfile
24*c2e18aaaSAndroid Build Coastguard Workerimport unittest
25*c2e18aaaSAndroid Build Coastguard Worker
26*c2e18aaaSAndroid Build Coastguard Workerfrom atest.integration_tests.snapshot import Snapshot
27*c2e18aaaSAndroid Build Coastguard Worker# Disable pylint here because it conflicts with google format
28*c2e18aaaSAndroid Build Coastguard Worker# pylint: disable=wrong-import-order
29*c2e18aaaSAndroid Build Coastguard Workerfrom pyfakefs import fake_filesystem_unittest
30*c2e18aaaSAndroid Build Coastguard Worker
31*c2e18aaaSAndroid Build Coastguard Worker
32*c2e18aaaSAndroid Build Coastguard Workerclass SnapshotTest(fake_filesystem_unittest.TestCase):
33*c2e18aaaSAndroid Build Coastguard Worker  """Snapshot test class unit test."""
34*c2e18aaaSAndroid Build Coastguard Worker
35*c2e18aaaSAndroid Build Coastguard Worker  def setUp(self):
36*c2e18aaaSAndroid Build Coastguard Worker    self.setUpPyfakefs()
37*c2e18aaaSAndroid Build Coastguard Worker    self.temp_dir = pathlib.Path(tempfile.mkdtemp())
38*c2e18aaaSAndroid Build Coastguard Worker    super().setUp()
39*c2e18aaaSAndroid Build Coastguard Worker
40*c2e18aaaSAndroid Build Coastguard Worker  def tearDown(self):
41*c2e18aaaSAndroid Build Coastguard Worker    shutil.rmtree(self.temp_dir)
42*c2e18aaaSAndroid Build Coastguard Worker    super().tearDown()
43*c2e18aaaSAndroid Build Coastguard Worker
44*c2e18aaaSAndroid Build Coastguard Worker  def test_restore_dir_and_env_and_obj_from_snapshot(self):
45*c2e18aaaSAndroid Build Coastguard Worker    """Test take and restore directory, environ, and objects together."""
46*c2e18aaaSAndroid Build Coastguard Worker    workspace = self.temp_dir / 'workspace'
47*c2e18aaaSAndroid Build Coastguard Worker    restore_dst_workspace = self.temp_dir / 'workspace2'
48*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace)
49*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace.joinpath('dir1'))
50*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_file(workspace.joinpath('dir1', 'file1'), contents='test')
51*c2e18aaaSAndroid Build Coastguard Worker    env_key = 'env_name'
52*c2e18aaaSAndroid Build Coastguard Worker    env_val = 'value'
53*c2e18aaaSAndroid Build Coastguard Worker    obj_key = 'obj_name'
54*c2e18aaaSAndroid Build Coastguard Worker    obj_val = 123
55*c2e18aaaSAndroid Build Coastguard Worker    os.environ[env_key] = env_val
56*c2e18aaaSAndroid Build Coastguard Worker    snapshot = Snapshot(self.temp_dir / 'db')
57*c2e18aaaSAndroid Build Coastguard Worker    snapshot_name = 'a_snapshot_name'
58*c2e18aaaSAndroid Build Coastguard Worker    snapshot.take_snapshot(
59*c2e18aaaSAndroid Build Coastguard Worker        snapshot_name,
60*c2e18aaaSAndroid Build Coastguard Worker        workspace,
61*c2e18aaaSAndroid Build Coastguard Worker        ['*'],
62*c2e18aaaSAndroid Build Coastguard Worker        env_keys=[env_key],
63*c2e18aaaSAndroid Build Coastguard Worker        objs={obj_key: obj_val},
64*c2e18aaaSAndroid Build Coastguard Worker    )
65*c2e18aaaSAndroid Build Coastguard Worker
66*c2e18aaaSAndroid Build Coastguard Worker    environ, objs = snapshot.restore_snapshot(
67*c2e18aaaSAndroid Build Coastguard Worker        snapshot_name, restore_dst_workspace.as_posix()
68*c2e18aaaSAndroid Build Coastguard Worker    )
69*c2e18aaaSAndroid Build Coastguard Worker
70*c2e18aaaSAndroid Build Coastguard Worker    self.assertTrue(restore_dst_workspace.joinpath('dir1', 'file1').exists())
71*c2e18aaaSAndroid Build Coastguard Worker    self.assertEqual(environ[env_key], env_val)
72*c2e18aaaSAndroid Build Coastguard Worker    self.assertEqual(objs[obj_key], obj_val)
73*c2e18aaaSAndroid Build Coastguard Worker
74*c2e18aaaSAndroid Build Coastguard Worker  def test_restore_objects_from_snapshot(self):
75*c2e18aaaSAndroid Build Coastguard Worker    """Test objects is restored from a snapshot."""
76*c2e18aaaSAndroid Build Coastguard Worker    workspace = self.temp_dir / 'workspace'
77*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace)
78*c2e18aaaSAndroid Build Coastguard Worker    snapshot = Snapshot(self.temp_dir / 'db')
79*c2e18aaaSAndroid Build Coastguard Worker    snapshot_name = 'a_snapshot_name'
80*c2e18aaaSAndroid Build Coastguard Worker    objs = {'a': {'b': False}}
81*c2e18aaaSAndroid Build Coastguard Worker    snapshot.take_snapshot('a_snapshot_name', workspace, ['*'], objs=objs)
82*c2e18aaaSAndroid Build Coastguard Worker
83*c2e18aaaSAndroid Build Coastguard Worker    _, actual_objs = snapshot.restore_snapshot(
84*c2e18aaaSAndroid Build Coastguard Worker        snapshot_name, workspace.as_posix()
85*c2e18aaaSAndroid Build Coastguard Worker    )
86*c2e18aaaSAndroid Build Coastguard Worker
87*c2e18aaaSAndroid Build Coastguard Worker    self.assertEqual(objs, actual_objs)
88*c2e18aaaSAndroid Build Coastguard Worker
89*c2e18aaaSAndroid Build Coastguard Worker  def test_take_snapshot_empty_dir_snapshot_is_created(self):
90*c2e18aaaSAndroid Build Coastguard Worker    """Test taking a snapshot of an empty directory."""
91*c2e18aaaSAndroid Build Coastguard Worker    workspace = self.temp_dir / 'workspace'
92*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace)
93*c2e18aaaSAndroid Build Coastguard Worker    snapshot = Snapshot(self.temp_dir / 'db')
94*c2e18aaaSAndroid Build Coastguard Worker    snapshot_name = 'a_snapshot_name'
95*c2e18aaaSAndroid Build Coastguard Worker
96*c2e18aaaSAndroid Build Coastguard Worker    snapshot.take_snapshot(snapshot_name, workspace, ['*'])
97*c2e18aaaSAndroid Build Coastguard Worker
98*c2e18aaaSAndroid Build Coastguard Worker    self.assertTrue(
99*c2e18aaaSAndroid Build Coastguard Worker        self.temp_dir.joinpath(f'db/{snapshot_name}_metadata.json').exists()
100*c2e18aaaSAndroid Build Coastguard Worker    )
101*c2e18aaaSAndroid Build Coastguard Worker
102*c2e18aaaSAndroid Build Coastguard Worker  def test_take_snapshot_with_files_files_are_recorded(self):
103*c2e18aaaSAndroid Build Coastguard Worker    """Test taking a snapshot of a directory with files."""
104*c2e18aaaSAndroid Build Coastguard Worker    workspace = self.temp_dir / 'workspace'
105*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace)
106*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace.joinpath('dir1'))
107*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_file(workspace.joinpath('dir1', 'file1'), contents='test')
108*c2e18aaaSAndroid Build Coastguard Worker    snapshot = Snapshot(self.temp_dir / 'db')
109*c2e18aaaSAndroid Build Coastguard Worker    snapshot_name = 'a_snapshot_name'
110*c2e18aaaSAndroid Build Coastguard Worker
111*c2e18aaaSAndroid Build Coastguard Worker    snapshot.take_snapshot('a_snapshot_name', workspace, ['*'])
112*c2e18aaaSAndroid Build Coastguard Worker
113*c2e18aaaSAndroid Build Coastguard Worker    with open(
114*c2e18aaaSAndroid Build Coastguard Worker        self.temp_dir / 'db' / f'{snapshot_name}_metadata.json',
115*c2e18aaaSAndroid Build Coastguard Worker        encoding='utf-8',
116*c2e18aaaSAndroid Build Coastguard Worker    ) as f:
117*c2e18aaaSAndroid Build Coastguard Worker      file_infos = json.load(f)
118*c2e18aaaSAndroid Build Coastguard Worker    self.assertEqual(len(file_infos), 2)
119*c2e18aaaSAndroid Build Coastguard Worker    self.assertIn('dir1/file1', file_infos)
120*c2e18aaaSAndroid Build Coastguard Worker    self.assertIn('dir1', file_infos)
121*c2e18aaaSAndroid Build Coastguard Worker
122*c2e18aaaSAndroid Build Coastguard Worker  def test_take_snapshot_with_include_paths(self):
123*c2e18aaaSAndroid Build Coastguard Worker    """Test taking a snapshot with include paths."""
124*c2e18aaaSAndroid Build Coastguard Worker    workspace = self.temp_dir / 'workspace'
125*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace)
126*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace.joinpath('dir1'))
127*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_file(workspace.joinpath('dir1', 'file1'), contents='test')
128*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace.joinpath('dir2'))
129*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_file(workspace.joinpath('dir2', 'file2'), contents='test')
130*c2e18aaaSAndroid Build Coastguard Worker    snapshot = Snapshot(self.temp_dir / 'db')
131*c2e18aaaSAndroid Build Coastguard Worker    snapshot_name = 'a_snapshot_name'
132*c2e18aaaSAndroid Build Coastguard Worker
133*c2e18aaaSAndroid Build Coastguard Worker    snapshot.take_snapshot('a_snapshot_name', workspace, include_paths=['dir2'])
134*c2e18aaaSAndroid Build Coastguard Worker
135*c2e18aaaSAndroid Build Coastguard Worker    with open(
136*c2e18aaaSAndroid Build Coastguard Worker        self.temp_dir / 'db' / f'{snapshot_name}_metadata.json',
137*c2e18aaaSAndroid Build Coastguard Worker        encoding='utf-8',
138*c2e18aaaSAndroid Build Coastguard Worker    ) as f:
139*c2e18aaaSAndroid Build Coastguard Worker      file_infos = json.load(f)
140*c2e18aaaSAndroid Build Coastguard Worker    self.assertEqual(len(file_infos), 2)
141*c2e18aaaSAndroid Build Coastguard Worker    self.assertIn('dir2', file_infos)
142*c2e18aaaSAndroid Build Coastguard Worker    self.assertIn('dir2/file2', file_infos)
143*c2e18aaaSAndroid Build Coastguard Worker
144*c2e18aaaSAndroid Build Coastguard Worker  def test_take_snapshot_with_exclude_paths(self):
145*c2e18aaaSAndroid Build Coastguard Worker    """Test taking a snapshot with exclude paths."""
146*c2e18aaaSAndroid Build Coastguard Worker    workspace = self.temp_dir / 'workspace'
147*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace)
148*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace.joinpath('dir1'))
149*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_file(workspace.joinpath('dir1', 'file1'), contents='test')
150*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace.joinpath('dir2'))
151*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_file(workspace.joinpath('dir2', 'file2'), contents='test')
152*c2e18aaaSAndroid Build Coastguard Worker    snapshot = Snapshot(self.temp_dir / 'db')
153*c2e18aaaSAndroid Build Coastguard Worker    snapshot_name = 'a_snapshot_name'
154*c2e18aaaSAndroid Build Coastguard Worker
155*c2e18aaaSAndroid Build Coastguard Worker    snapshot.take_snapshot(
156*c2e18aaaSAndroid Build Coastguard Worker        'a_snapshot_name', workspace, ['*'], exclude_paths=['dir1']
157*c2e18aaaSAndroid Build Coastguard Worker    )
158*c2e18aaaSAndroid Build Coastguard Worker
159*c2e18aaaSAndroid Build Coastguard Worker    with open(
160*c2e18aaaSAndroid Build Coastguard Worker        self.temp_dir / 'db' / f'{snapshot_name}_metadata.json',
161*c2e18aaaSAndroid Build Coastguard Worker        encoding='utf-8',
162*c2e18aaaSAndroid Build Coastguard Worker    ) as f:
163*c2e18aaaSAndroid Build Coastguard Worker      file_infos = json.load(f)
164*c2e18aaaSAndroid Build Coastguard Worker    self.assertEqual(len(file_infos), 2)
165*c2e18aaaSAndroid Build Coastguard Worker    self.assertIn('dir2', file_infos)
166*c2e18aaaSAndroid Build Coastguard Worker    self.assertIn('dir2/file2', file_infos)
167*c2e18aaaSAndroid Build Coastguard Worker
168*c2e18aaaSAndroid Build Coastguard Worker  def test_take_snapshot_with_include_and_exclude_paths(self):
169*c2e18aaaSAndroid Build Coastguard Worker    """Test taking a snapshot with include and exclude paths."""
170*c2e18aaaSAndroid Build Coastguard Worker    workspace = self.temp_dir / 'workspace'
171*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace)
172*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace.joinpath('dir1'))
173*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_file(workspace.joinpath('dir1', 'file1'), contents='test')
174*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace.joinpath('dir2'))
175*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_file(workspace.joinpath('dir2', 'file2'), contents='test')
176*c2e18aaaSAndroid Build Coastguard Worker    snapshot = Snapshot(self.temp_dir / 'db')
177*c2e18aaaSAndroid Build Coastguard Worker    snapshot_name = 'a_snapshot_name'
178*c2e18aaaSAndroid Build Coastguard Worker
179*c2e18aaaSAndroid Build Coastguard Worker    snapshot.take_snapshot(
180*c2e18aaaSAndroid Build Coastguard Worker        snapshot_name,
181*c2e18aaaSAndroid Build Coastguard Worker        workspace,
182*c2e18aaaSAndroid Build Coastguard Worker        include_paths=['dir1'],
183*c2e18aaaSAndroid Build Coastguard Worker        exclude_paths=['dir1/file1'],
184*c2e18aaaSAndroid Build Coastguard Worker    )
185*c2e18aaaSAndroid Build Coastguard Worker
186*c2e18aaaSAndroid Build Coastguard Worker    with open(
187*c2e18aaaSAndroid Build Coastguard Worker        self.temp_dir / 'db' / f'{snapshot_name}_metadata.json',
188*c2e18aaaSAndroid Build Coastguard Worker        encoding='utf-8',
189*c2e18aaaSAndroid Build Coastguard Worker    ) as f:
190*c2e18aaaSAndroid Build Coastguard Worker      file_infos = json.load(f)
191*c2e18aaaSAndroid Build Coastguard Worker    self.assertEqual(len(file_infos), 1)
192*c2e18aaaSAndroid Build Coastguard Worker    self.assertIn('dir1', file_infos)
193*c2e18aaaSAndroid Build Coastguard Worker
194*c2e18aaaSAndroid Build Coastguard Worker  def test_restore_snapshot_preserve_dangling_relative_links(self):
195*c2e18aaaSAndroid Build Coastguard Worker    """Test restoring a dangling link relative to the workspace."""
196*c2e18aaaSAndroid Build Coastguard Worker    workspace = self.temp_dir / 'workspace'
197*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace)
198*c2e18aaaSAndroid Build Coastguard Worker    snapshot = Snapshot(self.temp_dir / 'db')
199*c2e18aaaSAndroid Build Coastguard Worker    snapshot_name = 'a_snapshot_name'
200*c2e18aaaSAndroid Build Coastguard Worker    restore_dir = self.temp_dir / 'restore'
201*c2e18aaaSAndroid Build Coastguard Worker    link_file_name = 'link'
202*c2e18aaaSAndroid Build Coastguard Worker    target_file_name = pathlib.Path('non-existent-path')
203*c2e18aaaSAndroid Build Coastguard Worker    workspace.joinpath(link_file_name).symlink_to(target_file_name)
204*c2e18aaaSAndroid Build Coastguard Worker    snapshot.take_snapshot(snapshot_name, workspace, ['*'])
205*c2e18aaaSAndroid Build Coastguard Worker
206*c2e18aaaSAndroid Build Coastguard Worker    snapshot.restore_snapshot(snapshot_name, restore_dir)
207*c2e18aaaSAndroid Build Coastguard Worker
208*c2e18aaaSAndroid Build Coastguard Worker    self.assertEqual(
209*c2e18aaaSAndroid Build Coastguard Worker        restore_dir.joinpath(link_file_name).readlink(),
210*c2e18aaaSAndroid Build Coastguard Worker        target_file_name,
211*c2e18aaaSAndroid Build Coastguard Worker    )
212*c2e18aaaSAndroid Build Coastguard Worker
213*c2e18aaaSAndroid Build Coastguard Worker  def test_restore_snapshot_preserve_dangling_absolute_links(self):
214*c2e18aaaSAndroid Build Coastguard Worker    """Test restoring a dangling absolute link within workspace."""
215*c2e18aaaSAndroid Build Coastguard Worker    workspace = self.temp_dir / 'workspace'
216*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace)
217*c2e18aaaSAndroid Build Coastguard Worker    snapshot = Snapshot(self.temp_dir / 'db')
218*c2e18aaaSAndroid Build Coastguard Worker    snapshot_name = 'a_snapshot_name'
219*c2e18aaaSAndroid Build Coastguard Worker    restore_dir = self.temp_dir / 'restore'
220*c2e18aaaSAndroid Build Coastguard Worker    link_file_name = 'link'
221*c2e18aaaSAndroid Build Coastguard Worker    target_file_name = 'non-existent-path'
222*c2e18aaaSAndroid Build Coastguard Worker    internal_dangling_target = workspace / target_file_name
223*c2e18aaaSAndroid Build Coastguard Worker    workspace.joinpath(link_file_name).symlink_to(internal_dangling_target)
224*c2e18aaaSAndroid Build Coastguard Worker    snapshot.take_snapshot(snapshot_name, workspace, ['*'])
225*c2e18aaaSAndroid Build Coastguard Worker
226*c2e18aaaSAndroid Build Coastguard Worker    snapshot.restore_snapshot(snapshot_name, restore_dir)
227*c2e18aaaSAndroid Build Coastguard Worker
228*c2e18aaaSAndroid Build Coastguard Worker    self.assertEqual(
229*c2e18aaaSAndroid Build Coastguard Worker        restore_dir.joinpath(link_file_name).resolve(),
230*c2e18aaaSAndroid Build Coastguard Worker        restore_dir / target_file_name,
231*c2e18aaaSAndroid Build Coastguard Worker    )
232*c2e18aaaSAndroid Build Coastguard Worker
233*c2e18aaaSAndroid Build Coastguard Worker  def test_restore_snapshot_preserve_dangling_external_links(self):
234*c2e18aaaSAndroid Build Coastguard Worker    """Test restoring a dangling link pointing to outside the workspace."""
235*c2e18aaaSAndroid Build Coastguard Worker    workspace = self.temp_dir / 'workspace'
236*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace)
237*c2e18aaaSAndroid Build Coastguard Worker    snapshot = Snapshot(self.temp_dir / 'db')
238*c2e18aaaSAndroid Build Coastguard Worker    snapshot_name = 'a_snapshot_name'
239*c2e18aaaSAndroid Build Coastguard Worker    restore_dir = self.temp_dir / 'restore'
240*c2e18aaaSAndroid Build Coastguard Worker    link_file_name = 'link'
241*c2e18aaaSAndroid Build Coastguard Worker    external_dangling_target = pathlib.Path('/external/non-existent-path')
242*c2e18aaaSAndroid Build Coastguard Worker    workspace.joinpath(link_file_name).symlink_to(external_dangling_target)
243*c2e18aaaSAndroid Build Coastguard Worker    snapshot.take_snapshot(snapshot_name, workspace, ['*'])
244*c2e18aaaSAndroid Build Coastguard Worker
245*c2e18aaaSAndroid Build Coastguard Worker    snapshot.restore_snapshot(snapshot_name, restore_dir)
246*c2e18aaaSAndroid Build Coastguard Worker
247*c2e18aaaSAndroid Build Coastguard Worker    self.assertEqual(
248*c2e18aaaSAndroid Build Coastguard Worker        restore_dir.joinpath(link_file_name).resolve(), external_dangling_target
249*c2e18aaaSAndroid Build Coastguard Worker    )
250*c2e18aaaSAndroid Build Coastguard Worker
251*c2e18aaaSAndroid Build Coastguard Worker  def test_restore_snapshot_empty_dir(self):
252*c2e18aaaSAndroid Build Coastguard Worker    """Test restoring a snapshot of an empty directory."""
253*c2e18aaaSAndroid Build Coastguard Worker    workspace = self.temp_dir / 'workspace'
254*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace)
255*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace.joinpath('dir1'))
256*c2e18aaaSAndroid Build Coastguard Worker    snapshot = Snapshot(self.temp_dir / 'db')
257*c2e18aaaSAndroid Build Coastguard Worker    snapshot_name = 'a_snapshot_name'
258*c2e18aaaSAndroid Build Coastguard Worker    snapshot.take_snapshot(snapshot_name, workspace, ['*'])
259*c2e18aaaSAndroid Build Coastguard Worker    restore_dir = self.temp_dir / 'restore'
260*c2e18aaaSAndroid Build Coastguard Worker
261*c2e18aaaSAndroid Build Coastguard Worker    snapshot.restore_snapshot(snapshot_name, restore_dir)
262*c2e18aaaSAndroid Build Coastguard Worker
263*c2e18aaaSAndroid Build Coastguard Worker    self.assertTrue(restore_dir.joinpath('dir1').exists())
264*c2e18aaaSAndroid Build Coastguard Worker
265*c2e18aaaSAndroid Build Coastguard Worker  def test_restore_snapshot_with_deleted_files(self):
266*c2e18aaaSAndroid Build Coastguard Worker    """Test restoring a snapshot with deleted files."""
267*c2e18aaaSAndroid Build Coastguard Worker    workspace = self.temp_dir / 'workspace'
268*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace)
269*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace.joinpath('dir1'))
270*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_file(workspace.joinpath('dir1', 'file1'), contents='test')
271*c2e18aaaSAndroid Build Coastguard Worker    snapshot = Snapshot(self.temp_dir / 'db')
272*c2e18aaaSAndroid Build Coastguard Worker    snapshot_name = 'a_snapshot_name'
273*c2e18aaaSAndroid Build Coastguard Worker    snapshot.take_snapshot(snapshot_name, workspace, ['*'])
274*c2e18aaaSAndroid Build Coastguard Worker    self.fs.remove(workspace.joinpath('dir1', 'file1'))
275*c2e18aaaSAndroid Build Coastguard Worker
276*c2e18aaaSAndroid Build Coastguard Worker    snapshot.restore_snapshot(snapshot_name, workspace.as_posix())
277*c2e18aaaSAndroid Build Coastguard Worker
278*c2e18aaaSAndroid Build Coastguard Worker    self.assertTrue(workspace.joinpath('dir1', 'file1').exists())
279*c2e18aaaSAndroid Build Coastguard Worker
280*c2e18aaaSAndroid Build Coastguard Worker  def test_restore_snapshot_with_extra_files(self):
281*c2e18aaaSAndroid Build Coastguard Worker    """Test restoring a snapshot with extra files."""
282*c2e18aaaSAndroid Build Coastguard Worker    workspace = self.temp_dir / 'workspace'
283*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace)
284*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace.joinpath('dir1'))
285*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_file(workspace.joinpath('dir1', 'file1'), contents='test')
286*c2e18aaaSAndroid Build Coastguard Worker    snapshot = Snapshot(self.temp_dir / 'db')
287*c2e18aaaSAndroid Build Coastguard Worker    snapshot_name = 'a_snapshot_name'
288*c2e18aaaSAndroid Build Coastguard Worker    snapshot.take_snapshot('a_snapshot_name', workspace, ['*'])
289*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_file(workspace.joinpath('dir1', 'file2'), contents='test')
290*c2e18aaaSAndroid Build Coastguard Worker
291*c2e18aaaSAndroid Build Coastguard Worker    snapshot.restore_snapshot(snapshot_name, workspace.as_posix())
292*c2e18aaaSAndroid Build Coastguard Worker
293*c2e18aaaSAndroid Build Coastguard Worker    self.assertTrue(workspace.joinpath('dir1', 'file1').exists())
294*c2e18aaaSAndroid Build Coastguard Worker    self.assertFalse(workspace.joinpath('dir1', 'file2').exists())
295*c2e18aaaSAndroid Build Coastguard Worker
296*c2e18aaaSAndroid Build Coastguard Worker  def test_restore_snapshot_with_modified_files(self):
297*c2e18aaaSAndroid Build Coastguard Worker    """Test restoring a snapshot with modified files."""
298*c2e18aaaSAndroid Build Coastguard Worker    workspace = self.temp_dir / 'workspace'
299*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace)
300*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_dir(workspace.joinpath('dir1'))
301*c2e18aaaSAndroid Build Coastguard Worker    file_path = workspace.joinpath('dir1', 'file1')
302*c2e18aaaSAndroid Build Coastguard Worker    self.fs.create_file(file_path, contents='test1')
303*c2e18aaaSAndroid Build Coastguard Worker    snapshot = Snapshot(self.temp_dir / 'db')
304*c2e18aaaSAndroid Build Coastguard Worker    snapshot_name = 'a_snapshot_name'
305*c2e18aaaSAndroid Build Coastguard Worker    snapshot.take_snapshot(snapshot_name, workspace, ['*'])
306*c2e18aaaSAndroid Build Coastguard Worker    file_path.write_text('test2', encoding='utf-8')
307*c2e18aaaSAndroid Build Coastguard Worker    # Increment file's modified time by 10 milliseconds
308*c2e18aaaSAndroid Build Coastguard Worker    mtime = os.path.getmtime(file_path)
309*c2e18aaaSAndroid Build Coastguard Worker    os.utime(file_path, (mtime, mtime + 0.01))
310*c2e18aaaSAndroid Build Coastguard Worker
311*c2e18aaaSAndroid Build Coastguard Worker    snapshot.restore_snapshot(snapshot_name, workspace.as_posix())
312*c2e18aaaSAndroid Build Coastguard Worker
313*c2e18aaaSAndroid Build Coastguard Worker    self.assertEqual(
314*c2e18aaaSAndroid Build Coastguard Worker        workspace.joinpath('dir1', 'file1').read_text('utf-8'), 'test1'
315*c2e18aaaSAndroid Build Coastguard Worker    )
316*c2e18aaaSAndroid Build Coastguard Worker
317*c2e18aaaSAndroid Build Coastguard Worker
318*c2e18aaaSAndroid Build Coastguard Workerif __name__ == '__main__':
319*c2e18aaaSAndroid Build Coastguard Worker  unittest.main()
320