class VCSProjectTests(TestCase): def setUp(self): # Force the checkout path to point to a test directory to make # resource file loading pass during tests. checkout_path_patch = patch.object( Project, 'checkout_path', new_callable=PropertyMock, return_value=os.path.join(TEST_CHECKOUT_PATH, 'no_resources_test') ) self.mock_checkout_path = checkout_path_patch.start() self.addCleanup(checkout_path_patch.stop) self.project = ProjectFactory.create() self.vcs_project = VCSProject(self.project) def test_relative_resource_paths(self): with patch.object( VCSProject, 'source_directory_path', new_callable=PropertyMock, return_value='/root/' ): self.vcs_project.resource_paths_without_config = Mock(return_value=[ '/root/foo.po', '/root/meh/bar.po' ]) assert_equal( list(self.vcs_project.relative_resource_paths()), ['foo.po', 'meh/bar.po'] ) def test_relative_resource_paths_pot(self): """ If a resource ends in .pot, replace the extension with .po since relative paths are used within non-source locales that do not have .pot files. """ with patch.object( VCSProject, 'source_directory_path', new_callable=PropertyMock, return_value='/root/' ): self.vcs_project.resource_paths_without_config = Mock(return_value=[ '/root/foo.pot', '/root/meh/bar.pot' ]) assert_equal( list(self.vcs_project.relative_resource_paths()), ['foo.po', 'meh/bar.po'] ) def test_source_directory_pc(self): """ If project configuration provided, use source repository checkout path as source directory path. """ self.vcs_project.configuration = Mock(return_value=[True]) assert_equal( self.vcs_project.source_directory_path, self.vcs_project.db_project.source_repository.checkout_path ) def test_source_directory_path_no_resource(self): """ When searching for source directories, do not match directories that do not contain resource files. """ checkout_path = os.path.join(TEST_CHECKOUT_PATH, 'no_resources_test') self.mock_checkout_path.return_value = checkout_path assert_equal( self.vcs_project.source_directory_path, os.path.join(checkout_path, 'real_resources', 'templates') ) def test_source_directory_scoring_templates(self): """ When searching for source directories, prefer directories named `templates` over all others. """ checkout_path = os.path.join(TEST_CHECKOUT_PATH, 'scoring_templates_test') self.mock_checkout_path.return_value = checkout_path assert_equal( self.vcs_project.source_directory_path, os.path.join(checkout_path, 'templates') ) def test_source_directory_scoring_en_US(self): """ When searching for source directories, prefer directories named `en-US` over others besides `templates`. """ checkout_path = os.path.join(TEST_CHECKOUT_PATH, 'scoring_en_US_test') self.mock_checkout_path.return_value = checkout_path assert_equal( self.vcs_project.source_directory_path, os.path.join(checkout_path, 'en-US') ) def test_source_directory_scoring_source_files(self): """ When searching for source directories, prefer directories with source-only formats over all others. """ checkout_path = os.path.join(TEST_CHECKOUT_PATH, 'scoring_source_files_test') self.mock_checkout_path.return_value = checkout_path assert_equal( self.vcs_project.source_directory_path, os.path.join(checkout_path, 'en') # en has pot files in it ) def test_resources_parse_error(self): """ If VCSResource() raises a ParseError while loading, log an error and skip the resource. """ self.vcs_project.relative_resource_paths = Mock(return_value=['failure', 'success']) # Fail only if the path is failure so we can test the ignore. def vcs_resource_constructor(project, path, locales=None): if path == 'failure': raise ParseError('error message') else: return 'successful resource' changed_vcs_resources = {'success': [], 'failure': []} with patch('pontoon.sync.vcs.models.VCSResource') as MockVCSResource, \ patch('pontoon.sync.vcs.models.log') as mock_log, \ patch.object( VCSProject, 'changed_files', new_callable=PropertyMock, return_value=changed_vcs_resources ): MockVCSResource.side_effect = vcs_resource_constructor assert_equal(self.vcs_project.resources, {'success': 'successful resource'}) mock_log.error.assert_called_with(CONTAINS('failure', 'error message')) @patch.object(Repository, 'checkout_path', new_callable=PropertyMock) def test_resource_paths_with_config(self, checkout_path_mock): """ If project configuration provided, use it to collect absolute paths to all source resources within the source repository checkout path. """ checkout_path_mock.return_value = PROJECT_CONFIG_CHECKOUT_PATH self.vcs_project.db_project.configuration_file = 'l10n.toml' self.vcs_project.configuration = VCSConfiguration(self.vcs_project) assert_equal( sorted(list( self.vcs_project.resource_paths_with_config() )), sorted([ os.path.join(PROJECT_CONFIG_CHECKOUT_PATH, 'values/strings.properties'), os.path.join(PROJECT_CONFIG_CHECKOUT_PATH, 'values/strings_reality.properties'), ]) ) @patch.object(VCSProject, 'source_directory_path', new_callable=PropertyMock) def test_resource_paths_without_config_region_properties(self, source_directory_path_mock): """ If a project has a repository_url in pontoon.base.MOZILLA_REPOS, resource_paths_without_config should ignore files named "region.properties". """ source_directory_path_mock.return_value = '/root' url = 'https://moz.example.com' self.project.repositories.all().delete() self.project.repositories.add(RepositoryFactory.create(url=url)) with patch('pontoon.sync.vcs.models.scandir', wraps=scandir) as mock_scandir, \ patch( 'pontoon.sync.vcs.models.MOZILLA_REPOS', [url] ): mock_scandir.walk.return_value = [ ('/root', [], ['foo.pot', 'region.properties']) ] assert_equal( list(self.vcs_project.resource_paths_without_config()), [os.path.join('/root', 'foo.pot')] ) @patch.object(VCSProject, 'source_directory_path', new_callable=PropertyMock) def test_resource_paths_without_config_exclude_hidden(self, source_directory_path_mock): """ We should filter out resources that are contained in the hidden paths. """ source_directory_path_mock.return_value = '/root' hidden_paths = ( ('/root/.hidden_folder/templates', [], ('bar.pot',)), ('/root/templates', [], ('foo.pot',)), ) with patch( 'pontoon.sync.vcs.models.scandir.walk', wraps=scandir, return_value=hidden_paths ): assert_equal( list(self.vcs_project.resource_paths_without_config()), ['/root/templates/foo.pot'] )