#!/usr/bin/env python # # Copyright 2016 Google Inc. # # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Tests for asset_utils.""" import asset_utils import os import shutil import subprocess import sys import tempfile import unittest import uuid FILE_DIR = os.path.dirname(os.path.abspath(__file__)) INFRA_BOTS_DIR = os.path.realpath(os.path.join(FILE_DIR, os.pardir)) sys.path.insert(0, INFRA_BOTS_DIR) import test_utils import utils CIPD_DEV_SERVICE_URL = 'https://chrome-infra-packages-dev.appspot.com' GS_BUCKET = 'skia-infra-testdata' def _fake_prompt(result): """Make a function that pretends to prompt for input and returns a result.""" return lambda s: result def _write_stuff(target_dir): """Write some files and directories into target_dir.""" fw = test_utils.FileWriter(target_dir) fw.mkdir('mydir') fw.mkdir('anotherdir', 0666) fw.mkdir('dir3', 0600) fw.mkdir('subdir') fw.write('a.txt', 0777) fw.write('b.txt', 0751) fw.write('c.txt', 0640) fw.write(os.path.join('subdir', 'd.txt'), 0640) class _LocalStore(object): """Local store used for testing.""" def __init__(self): self.dir = tempfile.mkdtemp() def get_available_versions(self, name): target = os.path.join(self.dir, name) if not os.path.isdir(target): return [] contents = os.listdir(os.path.join(self.dir, name)) return sorted([int(d) for d in contents]) def upload(self, name, version, target_dir, extra_tags=None): shutil.copytree(target_dir, os.path.join(self.dir, name, str(version))) def download(self, name, version, target_dir): shutil.copytree(os.path.join(self.dir, name, str(version)), target_dir) def delete_contents(self, name): try: shutil.rmtree(self.dir) except OSError: if os.path.exists(self.dir): raise class StoreTest(unittest.TestCase): """Superclass used for testing one of the stores.""" def setUp(self): self.asset_name = str(uuid.uuid4()) def tearDown(self): pass def _test_upload_download(self, store): with utils.tmp_dir(): # Create input files and directories. input_dir = os.path.join(os.getcwd(), 'input') _write_stuff(input_dir) # Upload a version, download it again. store.upload(self.asset_name, 0, input_dir) output_dir = os.path.join(os.getcwd(), 'output') store.download(self.asset_name, 0, output_dir) # Compare. test_utils.compare_trees(self, input_dir, output_dir) def _test_versions(self, store): with utils.tmp_dir(): # Create input files and directories. input_dir = os.path.join(os.getcwd(), 'input') _write_stuff(input_dir) self.assertEqual(store.get_available_versions(self.asset_name), []) store.upload(self.asset_name, 0, input_dir) self.assertEqual(store.get_available_versions(self.asset_name), [0]) store.upload(self.asset_name, 1, input_dir) self.assertEqual(store.get_available_versions(self.asset_name), [0, 1]) store.delete_contents(self.asset_name) self.assertEqual(store.get_available_versions(self.asset_name), []) class LocalStoreTest(StoreTest): """Test the local store.""" def setUp(self): super(LocalStoreTest, self).setUp() self._store = _LocalStore() def tearDown(self): self._store.delete_contents(self.asset_name) super(LocalStoreTest, self).tearDown() def test_upload_download(self): self._test_upload_download(self._store) def test_versions(self): self._test_versions(self._store) # This test is disabled due to permissions issues with CIPD. #class CIPDStoreTest(StoreTest): # """Test the CIPD store.""" # def setUp(self): # super(CIPDStoreTest, self).setUp() # self._store = asset_utils.CIPDStore(cipd_url=CIPD_DEV_SERVICE_URL) # # def tearDown(self): # self._store.delete_contents(self.asset_name) # super(CIPDStoreTest, self).tearDown() # # def test_upload_download(self): # self._test_upload_download(self._store) # # def test_versions(self): # self._test_versions(self._store) # This test is disabled because the interactions with GS can be flaky. #class GSStoreTest(StoreTest): # """Test the GS store.""" # def setUp(self): # super(GSStoreTest, self).setUp() # self._store = asset_utils.GSStore(gsutil=None, bucket=GS_BUCKET) # # def tearDown(self): # self._store.delete_contents(self.asset_name) # super(GSStoreTest, self).tearDown() # # def test_upload_download(self): # self._test_upload_download(self._store) # # def test_versions(self): # self._test_versions(self._store) class AssetTest(unittest.TestCase): """Test Asset operations using a local store.""" def setUp(self): self.asset_name = str(uuid.uuid4()) self.old_prompt = asset_utils._prompt asset_utils._prompt = _fake_prompt('y') self._store = _LocalStore() self.a = asset_utils.Asset.add(self.asset_name, self._store) def tearDown(self): if self.a: self.a.remove(remove_in_store=True) asset_utils._prompt = self.old_prompt gs_path = 'gs://%s/assets/%s' % (GS_BUCKET, self.asset_name) gsutil = asset_utils.GSStore()._gsutil attempt_delete = True try: subprocess.check_call(gsutil + ['ls', gs_path]) except subprocess.CalledProcessError: attempt_delete = False if attempt_delete: subprocess.check_call(gsutil + ['rm', '-rf', gs_path]) def test_add_remove(self): # Ensure that we can't create an asset twice. with self.assertRaises(Exception): asset_utils.Asset.add(self.asset_name, self._store) # Ensure that the asset dir exists. asset_dir = os.path.join(FILE_DIR, self.asset_name) self.assertTrue(os.path.isdir(asset_dir)) # Remove the asset, ensure that it's gone. self.a.remove() self.a = None self.assertFalse(os.path.exists(asset_dir)) def test_upload_download(self): with utils.tmp_dir(): # Create input files and directories. input_dir = os.path.join(os.getcwd(), 'input') _write_stuff(input_dir) # Upload a version, download it again. self.a.upload_new_version(input_dir) output_dir = os.path.join(os.getcwd(), 'output') self.a.download_current_version(output_dir) # Compare. test_utils.compare_trees(self, input_dir, output_dir) def test_versions(self): with utils.tmp_dir(): # Create input files and directories. input_dir = os.path.join(os.getcwd(), 'input') _write_stuff(input_dir) self.assertEqual(self.a.get_current_version(), -1) self.assertEqual(self.a.get_available_versions(), []) self.assertEqual(self.a.get_next_version(), 0) self.a.upload_new_version(input_dir) self.assertEqual(self.a.get_current_version(), 0) self.assertEqual(self.a.get_available_versions(), [0]) self.assertEqual(self.a.get_next_version(), 1) self.a.upload_new_version(input_dir) self.assertEqual(self.a.get_current_version(), 1) self.assertEqual(self.a.get_available_versions(), [0, 1]) self.assertEqual(self.a.get_next_version(), 2) if __name__ == '__main__': unittest.main()