def test_export(self): """Test exporting of revisions.""" with TemporaryDirectory() as directory: # Change the current working directory to our temporary directory # so that we can give a relative pathname to export(). This is a # regression test for a bug that was fixed in vcs-repo-mgr 4.1.3. os.chdir(directory) # Initialize a repository object of the parametrized type. repository = self.get_instance(bare=False, local=os.path.join(directory, 'repo')) repository.create() # Commit a file to the repository. versioned_filename = random_string(10) versioned_contents = random_string(250) self.commit_file( repository=repository, filename=versioned_filename, contents=versioned_contents, message="Initial commit", ) # Export the initial revision. export_directory_relative = 'export' export_directory_absolute = os.path.join(directory, export_directory_relative) returncode, output = run_cli( main, '--repository=%s' % repository.local, '--export=%s' % export_directory_relative, ) self.assertEquals(returncode, 0) # Check that the file we committed was exported. exported_file = os.path.join(export_directory_absolute, versioned_filename) self.assertTrue(os.path.isfile(exported_file)) with codecs.open(exported_file, 'r', 'UTF-8') as handle: self.assertEquals(handle.read(), versioned_contents) # Reset the working directory. os.chdir(tempfile.gettempdir())
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_unmerged_capture(self): """Test that standard output and error can be captured separately.""" expected_stdout = random_string() expected_stderr = random_string() with CaptureOutput(merged=False) as capturer: sys.stdout.write(expected_stdout + "\n") sys.stderr.write(expected_stderr + "\n") assert expected_stdout in capturer.stdout.get_lines() assert expected_stderr in capturer.stderr.get_lines()
def test_combined_capture_same_process(self): """Test combined standard output and error capturing from the same process.""" expected_stdout = random_string() expected_stderr = random_string() with CaptureOutput() as capturer: sys.stdout.write(expected_stdout + "\n") sys.stderr.write(expected_stderr + "\n") assert expected_stdout in capturer.get_lines() assert expected_stderr in capturer.get_lines()
def commit_file(self, repository, filename=None, contents=None, message=None): """Commit a file to the given repository.""" filename = filename or random_string(15) contents = contents or random_string(1024) exists = repository.context.exists(filename) repository.context.write_file(filename, contents) repository.add_files(filename) repository.commit(message=message or ("Committing %s file '%s'" % ( "changed" if exists else "new", filename, )))
def test_partial_read(self): """Test that partial reading works as expected.""" # This test method uses retry logic because `partial=True' makes these # tests prone to race conditions (this is the whole reason why # `partial=False' by default :-). initial_part = random_string() later_part = random_string() with CaptureOutput() as capturer: sys.stderr.write("%s\n" % initial_part) retry(lambda: initial_part in capturer.get_lines(partial=True)) sys.stderr.write("%s\n" % later_part) retry(lambda: later_part in capturer.get_lines(partial=True))
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_combined_capture_subprocess(self): """Test combined standard output and error capturing from subprocesses.""" expected_stdout = random_string() expected_stderr = random_string() with CaptureOutput() as capturer: subprocess.call([ sys.executable, '-c', ';'.join([ 'import sys', 'sys.stdout.write(%r)' % (expected_stdout + '\n'), 'sys.stderr.write(%r)' % (expected_stderr + '\n'), ]), ]) assert expected_stdout in capturer.get_lines() assert expected_stderr in capturer.get_lines()
def test_tags(self): """Test that tags can be created and introspected.""" with TemporaryDirectory() as directory: repository = self.get_instance(bare=False, local=directory) # Create an initial commit and give it a tag. self.create_initial_commit(repository) initial_tag = random_string(10) assert initial_tag not in repository.tags repository.create_tag(initial_tag) assert initial_tag in repository.tags # Create a follow up commit and give it a tag. self.create_followup_commit(repository) followup_tag = random_string(10) assert followup_tag not in repository.tags repository.create_tag(followup_tag) assert followup_tag in repository.tags
def test_get_password(self): """Test getting a password from an entry.""" random_password = random_string() entry = PasswordEntry(name='some/random/password', store=object()) set_property( entry, 'text', '\n'.join([random_password, '', 'This is the description'])) self.assertEquals(random_password, entry.password)
def test_get_password(self): """Test getting a password from an entry.""" random_password = random_string() entry = PasswordEntry(name="some/random/password", store=object()) set_property( entry, "text", "\n".join([random_password, "", "This is the description"])) self.assertEquals(random_password, entry.password)
def generate_screenshots(): """Generate screenshots from shell scripts.""" this_script = os.path.abspath(__file__) this_directory = os.path.dirname(this_script) repository = os.path.join(this_directory, os.pardir) examples_directory = os.path.join(repository, 'docs', 'examples') images_directory = os.path.join(repository, 'docs', 'images') for shell_script in sorted(glob.glob(os.path.join(examples_directory, '*.sh'))): basename, extension = os.path.splitext(os.path.basename(shell_script)) image_file = os.path.join(images_directory, '%s.png' % basename) logger.info("Generating %s by running %s ..", format_path(image_file), format_path(shell_script)) command_line = [sys.executable, __file__, shell_script] random_title = random_string(25) # Generate the urxvt command line. urxvt_command = [ 'urxvt', # Enforce a default geometry. '-geometry', '98x30', # Set the text and background color. '-fg', TEXT_COLOR, '-bg', BACKGROUND_COLOR, # Set the font name and pixel size. '-fn', 'xft:%s:pixelsize=%i' % (FONT_NAME, FONT_SIZE), # Set the window title. '-title', random_title, # Hide scrollbars. '+sb', ] if which('qtile-run'): # I've been using tiling window managers for years now, at the # moment 'qtile' is my window manager of choice. It requires the # following special handling to enable the 'urxvt' window to float, # which in turn enables it to respect the '--geometry' option. urxvt_command.insert(0, 'qtile-run') urxvt_command.insert(1, '-f') # Apply the Ubuntu color scheme to urxvt. for index, css_color in enumerate(EIGHT_COLOR_PALETTE): urxvt_command.extend(('--color%i' % index, css_color)) # Add the command that should run inside the terminal. urxvt_command.extend(('-e', 'sh', '-c', 'setterm -cursor off; %s' % quote(command_line))) # Launch urxvt. execute(*urxvt_command, asynchronous=True) # Make sure we close the urxvt window. try: # Wait for urxvt to start up. If I were to improve this I could # instead wait for the creation of a file by interpret_script(). time.sleep(10) # Take a screen shot of the window using ImageMagick. execute('import', '-window', random_title, image_file) # Auto-trim the screen shot, then give it a 5px border. execute('convert', image_file, '-trim', '-bordercolor', BACKGROUND_COLOR, '-border', '5', image_file) finally: execute('wmctrl', '-c', random_title)
def test_save_to_path(self): """Test that captured output can be stored in a file.""" expected_output = random_string() with CaptureOutput() as capturer: print(expected_output) fd, temporary_file = tempfile.mkstemp() try: capturer.save_to_path(temporary_file) with open(temporary_file, 'r') as handle: assert expected_output in handle.read() finally: os.unlink(temporary_file)
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_merge_conflicts(self): """Test handling of merge conflicts.""" with TemporaryDirectory() as directory: # Initialize a repository object of the parametrized type. repository = self.get_instance(bare=False, local=directory) # Create the local repository. repository.create() # Create an initial commit in the repository. versioned_filename = random_string(10) versioned_contents = random_string(250) self.commit_file( repository=repository, filename=versioned_filename, contents=versioned_contents, message="Initial commit", ) # Create a new branch in which we'll modify # the file that the initial commit created. repository.create_branch('dev') self.commit_file( repository=repository, filename=versioned_filename, message="Commit on 'dev' branch", ) # Now modify the same file in the default branch. repository.checkout() self.commit_file( repository=repository, filename=versioned_filename, message="Commit on default branch", ) # Now try to merge the 'dev' branch into the default branch # (triggering the merge conflict) and make sure that the intended # exception type is raised. self.assertRaises(MergeConflictError, repository.merge, 'dev') # Make sure the filename of the file with merge conflicts is # available to callers. assert repository.merge_conflicts == [versioned_filename]
def test_format_text(self): """Test human friendly formatting of password store entries.""" entry = PasswordEntry(name='some/random/password', store=object()) set_property(entry, 'text', random_string()) self.assertEquals( # We enable ANSI escape sequences but strip them before we # compare the generated string. This may seem rather pointless # but it ensures that the relevant code paths are covered :-). dedent( ansi_strip( entry.format_text(include_password=True, use_colors=True))), dedent(''' some / random / password Password: {value} ''', value=entry.text))
def test_merge_up(self): """Test merging up through release branches.""" initial_release_branches = ['v1', 'v2', 'v3', 'v4'] intermediate_release_branch = 'v3.1' final_release_branches = ['v1', 'v2', 'v3', intermediate_release_branch, 'v4'] with MockedHomeDirectory() as home: self.configure_author(home, AUTHOR_NAME, AUTHOR_EMAIL) # Initialize a repository object of the parametrized type. repository = self.get_instance( bare=False, local=os.path.join(home, 'repo'), release_filter=r'^v(\d+(?:\.\d+)*)$', release_scheme='branches', ) # Add the repository to ~/.vcs-repo-mgr.ini. prepare_config({ 'merge-up-test': { 'local': repository.local, 'release-filter': r'^v(\d+(?:\.\d+)*)$', 'release-scheme': 'branches', 'type': repository.ALIASES[0], }, }) # Make sure the repository contains an initial commit on the # default branch, otherwise the merge process will try to # checkout() the default branch which can fail when that branch # "doesn't have any contents yet". self.create_initial_commit(repository) # Create the release branches. previous_branch = repository.current_branch for branch_name in initial_release_branches: repository.checkout(revision=previous_branch) repository.create_branch(branch_name) self.commit_file( repository=repository, filename=branch_name, contents="This is release branch '%s'\n" % branch_name, message="Create release branch '%s'" % branch_name, ) previous_branch = branch_name # Create a feature branch based on the initial release branch. feature_branch = 'feature-%s' % random_string(10) repository.checkout('v3') repository.create_branch(feature_branch) self.commit_file( repository=repository, filename=intermediate_release_branch, contents="This will be release branch '%s'\n" % intermediate_release_branch, message="Fixed a bug in version 3!", ) assert feature_branch in repository.branches # Merge the change up into the release branches using the command line interface. returncode, output = run_cli( main, '--repository=merge-up-test', '--revision=v3.1', '--merge-up', feature_branch, merged=True, ) self.assertEquals(returncode, 0) # Make sure the feature branch was closed. assert feature_branch not in repository.branches # Validate the contents of the default branch. repository.checkout() # Check that all of the release branches have been merged into the # default branch by checking the `v1', `v2', etc. filenames. entries = repository.context.list_entries('.') assert all(fn in entries for fn in final_release_branches) # Make sure the contents of the bug fix were merged up. assert repository.context.read_file('v1') == b"This is release branch 'v1'\n" assert repository.context.read_file('v2') == b"This is release branch 'v2'\n" assert repository.context.read_file('v3') == b"This is release branch 'v3'\n" assert repository.context.read_file('v3.1') == b"This will be release branch 'v3.1'\n" assert repository.context.read_file('v4') == b"This is release branch 'v4'\n"
def test_non_interpreted_lines_capture(self): """Test that interpretation of special characters can be disabled.""" expected_output = random_string() with CaptureOutput() as capturer: print(expected_output) assert expected_output in capturer.get_lines(interpreted=False)
def test_text_capture(self): """Test that capturing of all output as a single string is supported.""" expected_output = random_string() with CaptureOutput() as capturer: print(expected_output) assert expected_output in capturer.get_text()
def test_stdout_capture_same_process(self): """Test standard output capturing from the same process.""" expected_stdout = random_string() with CaptureOutput() as capturer: print(expected_stdout) assert expected_stdout in capturer.get_lines()