def test_package_building(self, repository=None, overrides={}, contents={}): """Test building of Debian binary packages.""" with Context() as finalizers: build_directory = finalizers.mkdtemp() control_fields = merge_control_fields(TEST_PACKAGE_FIELDS, overrides) # Create the package template. os.mkdir(os.path.join(build_directory, 'DEBIAN')) with open(os.path.join(build_directory, 'DEBIAN', 'control'), 'wb') as handle: control_fields.dump(handle) if contents: for filename, data in contents.items(): filename = os.path.join(build_directory, filename) directory = os.path.dirname(filename) makedirs(directory) with open(filename, 'w') as handle: handle.write(data) else: with open(os.path.join(build_directory, 'DEBIAN', 'conffiles'), 'wb') as handle: handle.write(b'/etc/file1\n') handle.write(b'/etc/file2\n') # Create the directory with configuration files. os.mkdir(os.path.join(build_directory, 'etc')) touch(os.path.join(build_directory, 'etc', 'file1')) touch(os.path.join(build_directory, 'etc', 'file3')) # Create a directory that should be cleaned up by clean_package_tree(). makedirs(os.path.join(build_directory, 'tmp', '.git')) # Create a file that should be cleaned up by clean_package_tree(). with open(os.path.join(build_directory, 'tmp', '.gitignore'), 'w') as handle: handle.write('\n') # Build the package (without any contents :-). returncode, output = run_cli(main, '--build', build_directory) assert returncode == 0 package_file = os.path.join(tempfile.gettempdir(), '%s_%s_%s.deb' % (control_fields['Package'], control_fields['Version'], control_fields['Architecture'])) assert os.path.isfile(package_file) if repository: shutil.move(package_file, repository) return os.path.join(repository, os.path.basename(package_file)) else: finalizers.register(os.unlink, package_file) # Verify the package metadata. fields, contents = inspect_package(package_file) for name in TEST_PACKAGE_FIELDS: assert fields[name] == TEST_PACKAGE_FIELDS[name] # Verify that the package contains the `/' and `/tmp' # directories (since it doesn't contain any actual files). assert contents['/'].permissions[0] == 'd' assert contents['/'].permissions[1:] == 'rwxr-xr-x' assert contents['/'].owner == 'root' assert contents['/'].group == 'root' assert contents['/tmp/'].permissions[0] == 'd' assert contents['/tmp/'].owner == 'root' assert contents['/tmp/'].group == 'root' # Verify that clean_package_tree() cleaned up properly # (`/tmp/.git' and `/tmp/.gitignore' have been cleaned up). assert '/tmp/.git/' not in contents assert '/tmp/.gitignore' not in contents return package_file
def test_no_matching_password_error(self): """Test the NoMatchingPasswordError exception.""" with TemporaryDirectory() as directory: touch(os.path.join(directory, 'Whatever.gpg')) program = PasswordStore(directory=directory) self.assertRaises(NoMatchingPasswordError, program.smart_search, 'x')
def test_bytecode_generation(self): """ Test byte code generation and cleanup. This tests the :func:`~py2deb.hooks.generate_bytecode_files()` and :func:`~py2deb.hooks.cleanup_bytecode_files()` functions. """ with TemporaryDirectory() as directory: # Generate a Python file. python_file = os.path.join(directory, 'test.py') with open(python_file, 'w') as handle: handle.write('print(42)\n') # Generate the byte code file. generate_bytecode_files('bytecode-test', [python_file]) # Make sure a byte code file was generated. bytecode_files = list(find_bytecode_files(python_file)) assert len(bytecode_files) > 0 and all(os.path.isfile(fn) for fn in bytecode_files), \ "Failed to generate Python byte code file!" # Sneak a random file into the __pycache__ directory to test the # error handling in cleanup_bytecode_files(). cache_directory = os.path.join(directory, '__pycache__') random_file = os.path.join(cache_directory, 'random-file') if HAS_PEP_3147: touch(random_file) # Cleanup the byte code file. cleanup_bytecode_files('bytecode-test', [python_file]) assert len(bytecode_files) > 0 and all(not os.path.isfile(fn) for fn in bytecode_files), \ "Failed to cleanup Python byte code file!" if HAS_PEP_3147: assert os.path.isfile(random_file), \ "Byte code cleanup removed unrelated file!" os.unlink(random_file) cleanup_bytecode_files('test-package', [python_file]) assert not os.path.isdir(cache_directory), \ "Failed to clean up __pycache__ directory!"
def test_show_entry(self): """Test showing of an entry on the terminal.""" password = random_string() # Some voodoo to mock methods in classes that # have yet to be instantiated follows :-). mocked_class = type( 'TestPasswordEntry', (PasswordEntry, ), dict(text=password), ) with PatchedAttribute(qpass, 'PasswordEntry', mocked_class): with TemporaryDirectory() as directory: name = 'some/random/password' touch(os.path.join(directory, '%s.gpg' % name)) returncode, output = run_cli( main, '--password-store=%s' % directory, '--no-clipboard', name, ) assert returncode == 0 assert dedent(output) == dedent( """ {title} Password: {password} """, title=name.replace('/', ' / '), password=password, )
def test_cli_quiet(self): """Test copying of a password without echoing the entry's text.""" # Generate a password and some additional text for a dummy password store entry. a_password = random_string() additional_text = random_string() raw_entry = a_password + "\n\n" + additional_text # Prepare a mock method to test that the password is copied, # but without actually invoking the `pass' program. copy_password_method = MagicMock() # Some voodoo to mock methods in classes that # have yet to be instantiated follows :-). mocked_class = type("TestPasswordEntry", (PasswordEntry, ), dict(text=raw_entry)) setattr(mocked_class, "copy_password", copy_password_method) with PatchedAttribute(qpass, "PasswordEntry", mocked_class): with PatchedAttribute(cli, "is_clipboard_supported", lambda: True): with TemporaryDirectory() as directory: touch(os.path.join(directory, "foo.gpg")) returncode, output = run_cli( main, "--password-store=%s" % directory, "--quiet", "foo") # Make sure the command succeeded. assert returncode == 0 # Make sure the password was copied to the clipboard. assert copy_password_method.called # Make sure no output was generated. assert not output.strip()
def test_cli_defaults(self): """Test default password store discovery in command line interface.""" with MockedHomeDirectory() as home: touch(os.path.join(home, '.password-store', 'the-only-entry.gpg')) returncode, output = run_cli(main, '-l') assert returncode == 0 entries = output.splitlines(False) assert entries == ['the-only-entry']
def test_file_copying(self): """Test that file copying using hard links actually works.""" with Context() as finalizers: source_directory = finalizers.mkdtemp() target_directory = finalizers.mkdtemp() touch(os.path.join(source_directory, '42')) copy_package_files(source_directory, target_directory, hard_links=True) assert os.stat(os.path.join(source_directory, '42')).st_ino == \ os.stat(os.path.join(target_directory, '42')).st_ino
def test_invalid_dates(self): """Make sure filenames with invalid dates don't cause an exception.""" with TemporaryDirectory(prefix='rotate-backups-', suffix='-test-suite') as root: file_with_valid_date = os.path.join(root, 'snapshot-201808030034.tar.gz') file_with_invalid_date = os.path.join(root, 'snapshot-180731150101.tar.gz') for filename in file_with_valid_date, file_with_invalid_date: touch(filename) program = RotateBackups(rotation_scheme=dict(monthly='always')) backups = program.collect_backups(root) assert len(backups) == 1 assert backups[0].pathname == file_with_valid_date
def test_touch(self): """Test :func:`humanfriendly.testing.touch()`.""" with TemporaryDirectory() as directory: # Create a file in the temporary directory. filename = os.path.join(directory, random_string()) assert not os.path.isfile(filename) touch(filename) assert os.path.isfile(filename) # Create a file in a subdirectory. filename = os.path.join(directory, random_string(), random_string()) assert not os.path.isfile(filename) touch(filename) assert os.path.isfile(filename)
def test_invalid_dates(self): """Make sure filenames with invalid dates don't cause an exception.""" with TemporaryDirectory(prefix='rotate-backups-', suffix='-test-suite') as root: file_with_valid_date = os.path.join( root, 'snapshot-201808030034.tar.gz') file_with_invalid_date = os.path.join( root, 'snapshot-180731150101.tar.gz') for filename in file_with_valid_date, file_with_invalid_date: touch(filename) program = RotateBackups(rotation_scheme=dict(monthly='always')) backups = program.collect_backups(root) assert len(backups) == 1 assert backups[0].pathname == file_with_valid_date
def test_gpg_key_error_handling(self): """Test explicit error handling of GPG key generation.""" from deb_pkg_tools import gpg with PatchedAttribute(gpg, 'have_updated_gnupg', lambda: False): with Context() as finalizers: directory = finalizers.mkdtemp() options = dict( key_id='12345', public_key_file=os.path.join(directory, 'test.pub'), secret_key_file=os.path.join(directory, 'test.sec'), ) touch(options['public_key_file']) self.assertRaises(EnvironmentError, GPGKey, **options) os.unlink(options['public_key_file']) touch(options['secret_key_file']) self.assertRaises(EnvironmentError, GPGKey, **options)
def test_find_package_archives(self): """Test searching for package archives.""" with Context() as finalizers: directory = finalizers.mkdtemp() for filename in 'some-random-file', 'regular-package_1.0_all.deb', 'micro-package_1.5_all.udeb': touch(os.path.join(directory, filename)) matches = find_package_archives(directory) assert len(matches) == 2 assert any(p.name == 'regular-package' and p.version == '1.0' and p.architecture == 'all' for p in matches) assert any(p.name == 'micro-package' and p.version == '1.5' and p.architecture == 'all' for p in matches)
def test_edit_entry(self): """Test editing of an entry on the command line.""" # Create a fake password store that we can test against. with TemporaryDirectory() as directory: touch(os.path.join(directory, "Personal", "Zabbix.gpg")) touch(os.path.join(directory, "Work", "Zabbix.gpg")) # Make sure we're not running the real `pass' program because its # intended purpose is user interaction, which has no place in an # automated test suite :-). with MockedProgram("pass"): returncode, output = run_cli(main, "--password-store=%s" % directory, "--edit", "p/z", merged=True) assert returncode == 0 assert "Matched one entry: Personal/Zabbix" in output
def test_password_discovery(self): """Test password discovery.""" with TemporaryDirectory() as directory: touch(os.path.join(directory, 'foo.gpg')) touch(os.path.join(directory, 'foo/bar.gpg')) touch(os.path.join(directory, 'foo/bar/baz.gpg')) touch(os.path.join(directory, 'Also with spaces.gpg')) program = PasswordStore(directory=directory) assert len(program.entries) == 4 assert program.entries[0].name == 'Also with spaces' assert program.entries[1].name == 'foo' assert program.entries[2].name == 'foo/bar' assert program.entries[3].name == 'foo/bar/baz'
def test_cli_filter(self): """Test filtering of entry text.""" # Generate a password and some additional text for a dummy password store entry. a_password = random_string() additional_text = random_string() sensitive_detail = "password: %s" % random_string() raw_entry = a_password + "\n\n" + additional_text + "\n" + sensitive_detail # Some voodoo to mock methods in classes that # have yet to be instantiated follows :-). mocked_class = type("TestPasswordEntry", (PasswordEntry, ), dict(copy_password=MagicMock(), text=raw_entry)) with PatchedAttribute(qpass, "PasswordEntry", mocked_class): with TemporaryDirectory() as directory: touch(os.path.join(directory, "foo.gpg")) returncode, output = run_cli(main, "--password-store=%s" % directory, "--filter=^password:"******"foo") # Make sure the command succeeded. assert returncode == 0 # Make sure the expected output was generated. assert additional_text in output assert sensitive_detail not in output
def test_select_entry(self): """Test password selection.""" with TemporaryDirectory() as directory: touch(os.path.join(directory, "foo.gpg")) touch(os.path.join(directory, "bar.gpg")) touch(os.path.join(directory, "baz.gpg")) program = PasswordStore(directory=directory) # Substring search. entry = program.select_entry("fo") assert entry.name == "foo" # Fuzzy search. entry = program.select_entry("bz") assert entry.name == "baz"
def test_select_entry_interactive(self): """Test interactive password selection.""" with TemporaryDirectory() as directory: touch(os.path.join(directory, 'foo.gpg')) touch(os.path.join(directory, 'bar.gpg')) touch(os.path.join(directory, 'baz.gpg')) # Select entries using the command line filter 'a' and then use # interactive selection to narrow the choice down to 'baz' by # specifying the unique substring 'z'. program = PasswordStore(directory=directory) with CaptureOutput(input='z'): entry = program.select_entry('a') assert entry.name == 'baz'
def test_select_entry(self): """Test password selection.""" with TemporaryDirectory() as directory: touch(os.path.join(directory, 'foo.gpg')) touch(os.path.join(directory, 'bar.gpg')) touch(os.path.join(directory, 'baz.gpg')) program = PasswordStore(directory=directory) # Substring search. entry = program.select_entry('fo') assert entry.name == 'foo' # Fuzzy search. entry = program.select_entry('bz') assert entry.name == 'baz'
def test_cli_list(self): """Test the output of ``qpass --list``.""" with TemporaryDirectory() as directory: touch(os.path.join(directory, 'foo.gpg')) touch(os.path.join(directory, 'foo/bar.gpg')) touch(os.path.join(directory, 'Also with spaces.gpg')) returncode, output = run_cli(main, '--password-store=%s' % directory, '--list') assert returncode == 0 entries = output.splitlines() assert 'foo' in entries assert 'foo/bar' in entries assert 'Also with spaces' in entries
def test_cli_exclude(self): """Test the output of ``qpass --exclude=... --list``.""" with TemporaryDirectory() as directory: touch(os.path.join(directory, "foo.gpg")) touch(os.path.join(directory, "foo/bar.gpg")) touch(os.path.join(directory, "Also with spaces.gpg")) returncode, output = run_cli(main, "--password-store=%s" % directory, "--exclude=*bar*", "--list") assert returncode == 0 entries = output.splitlines() assert "foo" in entries assert "foo/bar" not in entries assert "Also with spaces" in entries
def test_smart_search(self): """Test smart searching.""" with TemporaryDirectory() as directory: touch(os.path.join(directory, 'abcdef.gpg')) touch(os.path.join(directory, 'aabbccddeeff.gpg')) touch(os.path.join(directory, 'Google.gpg')) program = PasswordStore(directory=directory) # Test a substring match that avoids fuzzy matching. matches = program.smart_search('abc') assert len(matches) == 1 assert matches[0].name == 'abcdef' # Test a fuzzy match to confirm that the fall back works. matches = program.smart_search('gg') assert len(matches) == 1 assert matches[0].name == 'Google'
def test_simple_search(self): """Test simple substring searching.""" with TemporaryDirectory() as directory: touch(os.path.join(directory, 'foo.gpg')) touch(os.path.join(directory, 'bar.gpg')) touch(os.path.join(directory, 'baz.gpg')) program = PasswordStore(directory=directory) matches = program.simple_search('fo') assert len(matches) == 1 assert matches[0].name == 'foo' matches = program.simple_search('a') assert len(matches) == 2 assert matches[0].name == 'bar' assert matches[1].name == 'baz' matches = program.simple_search('b', 'z') assert len(matches) == 1 assert matches[0].name == 'baz'
def test_simple_search(self): """Test simple substring searching.""" with TemporaryDirectory() as directory: touch(os.path.join(directory, "foo.gpg")) touch(os.path.join(directory, "bar.gpg")) touch(os.path.join(directory, "baz.gpg")) program = PasswordStore(directory=directory) matches = program.simple_search("fo") assert len(matches) == 1 assert matches[0].name == "foo" matches = program.simple_search("a") assert len(matches) == 2 assert matches[0].name == "bar" assert matches[1].name == "baz" matches = program.simple_search("b", "z") assert len(matches) == 1 assert matches[0].name == "baz"
def test_fuzzy_search(self): """Test fuzzy searching.""" with TemporaryDirectory() as directory: touch(os.path.join(directory, 'Personal/Zabbix.gpg')) touch(os.path.join(directory, 'Work/Zabbix.gpg')) touch(os.path.join(directory, 'Something else.gpg')) program = PasswordStore(directory=directory) # Test a fuzzy search with multiple matches. matches = program.fuzzy_search('zbx') assert len(matches) == 2 assert any(entry.name == 'Personal/Zabbix' for entry in matches) assert any(entry.name == 'Work/Zabbix' for entry in matches) # Test a fuzzy search with a single match. matches = program.fuzzy_search('p/z') assert len(matches) == 1 assert matches[0].name == 'Personal/Zabbix' # Test a fuzzy search with `the other' match. matches = program.fuzzy_search('w/z') assert len(matches) == 1 assert matches[0].name == 'Work/Zabbix'