def test_workspace_recovery(server, tmpdir): """Test that we can detect and recover from various workspace snafus""" repo = P4Repo( root=tmpdir, # allow unit test to delete otherwise readonly files from workspace client_options='allwrite') # clobber writeable file # partially synced writeable files may be left in the workspace if a machine was shutdown mid-sync with open(os.path.join(tmpdir, "file.txt"), 'w') as depotfile: depotfile.write("Overwrite this file") repo.sync() # By default, would raise 'cannot clobber writable file' with open(os.path.join(tmpdir, "file.txt")) as content: assert content.read( ) == "Hello World\n", "Unexpected content in workspace file" # p4 clean os.remove(os.path.join(tmpdir, "file.txt")) open(os.path.join(tmpdir, "added.txt"), 'a').close() repo.clean() assert sorted(os.listdir(tmpdir)) == sorted( ["file.txt", "p4config"]), "Failed to restore workspace file with repo.clean()" os.remove(os.path.join(tmpdir, "file.txt")) os.remove(os.path.join(tmpdir, "p4config")) repo = P4Repo( root=tmpdir) # Open a fresh tmpdir, as if this was a different job repo.sync( ) # Normally: "You already have file.txt", but since p4config is missing it will restore the workspace assert sorted(os.listdir(tmpdir)) == sorted([ "file.txt", "p4config" ]), "Failed to restore corrupt workspace due to missing p4config"
def test_modify_client_type(server, tmpdir): """Test modifying a clients type""" repo = P4Repo(root=tmpdir, client_type='writeable') repo.sync() with pytest.raises( Exception, match= r'Client storage type cannot be changed after client is created'): repo = P4Repo(root=tmpdir, client_type='readonly') repo.sync()
def test_head(server, tmpdir): """Test resolve of HEAD changelist""" repo = P4Repo(root=tmpdir) assert repo.head() == "@6", "Unexpected global HEAD revision" repo = P4Repo(root=tmpdir, stream='//stream-depot/main') assert repo.head() == "@2", "Unexpected HEAD revision for stream" repo = P4Repo(root=tmpdir, stream='//stream-depot/idontexist') with pytest.raises( Exception, match=r"Stream '//stream-depot/idontexist' doesn't exist."): repo.head()
def test_client_migration(server, tmpdir): """Test re-use of workspace data when moved to another host""" repo = P4Repo(root=tmpdir) assert os.listdir(tmpdir) == [], "Workspace should be empty" synced = repo.sync() assert len(synced) > 0, "Didn't sync any files" with tempfile.TemporaryDirectory(prefix="bk-p4-test-") as second_client: copytree(tmpdir, second_client) # Client names include path on disk, so this creates a new unique client repo = P4Repo(root=second_client) synced = repo.sync( ) # Flushes to match previous client, since p4config is there on disk assert synced == [], "Should not have synced any files in second client"
def test_fingerprint_changed(server, tmpdir): """Test updating a fingerprint""" os.environ['P4TRUST'] = os.path.join(tmpdir, 'trust.txt') repo = P4Repo( root=tmpdir, fingerprint= 'FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF') with pytest.raises(Exception, match=r"The authenticity of '.*' can't be established"): repo.sync() repo = P4Repo(root=tmpdir, fingerprint=__LEGIT_P4_FINGERPRINT__) synced = repo.sync() assert len(synced) > 0, "Didn't sync any files"
def main(): """Main""" os.environ.update(get_env()) config = get_config() repo = P4Repo(**config) revision = get_build_revision() if revision == 'HEAD': # Resolve HEAD to a concrete revision revision = repo.head() set_build_revision(revision) # Convert changelist number to revision specifier if re.match(r'^\d*$', revision): revision = '@%s' % revision repo.sync(revision=revision) user_changelist = get_users_changelist() if user_changelist: # Use existing or make a copy of the users changelist for this build changelist = get_build_changelist() if not changelist: changelist = user_changelist if should_backup_changelists(): changelist = repo.backup(user_changelist) set_build_changelist(changelist) repo.p4print_unshelve(changelist) revision = get_build_revision() description = repo.description(get_users_changelist() or revision.strip('@')) set_build_info(revision, description)
def test_stream_switching(server, tmpdir): """Test stream-switching within the same depot""" repo = P4Repo(root=tmpdir, stream='//stream-depot/main') synced = repo.sync() assert len(synced) > 0, "Didn't sync any files" with open(os.path.join(tmpdir, "file.txt")) as content: assert content.read( ) == "Hello Stream World\n", "Unexpected content in workspace file" # Re-use the same checkout directory, but switch streams repo = P4Repo(root=tmpdir, stream='//stream-depot/dev') repo.sync() assert len(synced) > 0, "Didn't sync any files" with open(os.path.join(tmpdir, "file.txt")) as content: assert content.read( ) == "Hello Stream World (dev)\n", "Unexpected content in workspace file"
def test_unshelve(server, tmpdir): """Test unshelving a pending changelist""" repo = P4Repo(root=tmpdir) repo.sync() with open(os.path.join(tmpdir, "file.txt")) as content: assert content.read( ) == "Hello World\n", "Unexpected content in workspace file" repo.unshelve('3') # Modify a file with open(os.path.join(tmpdir, "file.txt")) as content: assert content.read( ) == "Goodbye World\n", "Unexpected content in workspace file" repo.sync() repo.unshelve('4') # Delete a file assert not os.path.exists(os.path.join(tmpdir, "file.txt")) repo.sync() repo.unshelve('5') # Add a file assert os.path.exists(os.path.join(tmpdir, "newfile.txt")) repo.sync() with pytest.raises( Exception, match=r'Changelist 999 does not contain any shelved files.'): repo.unshelve('999') # Unshelved changes are removed in following syncs repo.sync() with open(os.path.join(tmpdir, "file.txt")) as content: assert content.read( ) == "Hello World\n", "Unexpected content in workspace file" assert not os.path.exists(os.path.join( tmpdir, "newfile.txt")), "File unshelved for add was not deleted"
def test_fingerprint_good(server, tmpdir): """Test supplying the correct fingerprint""" os.environ['P4TRUST'] = os.path.join(tmpdir, 'trust.txt') repo = P4Repo(root=tmpdir, fingerprint=__LEGIT_P4_FINGERPRINT__) synced = repo.sync() assert len(synced) > 0, "Didn't sync any files"
def test_client_migration(): """Test re-use of workspace data when moved to another host""" with setup_server_and_client() as client_root: repo = P4Repo(root=client_root) assert os.listdir(client_root) == [], "Workspace should be empty" synced = repo.sync() assert len(synced) > 0, "Didn't sync any files" with tempfile.TemporaryDirectory( prefix="bk-p4-test-") as second_client_root: copytree(client_root, second_client_root) repo = P4Repo(root=second_client_root) synced = repo.sync( ) # Flushes to match previous client, since p4config is there on disk assert synced == [], "Should not have synced any files in second client"
def main(): """Main""" os.environ.update(get_env()) config = get_config() repo = P4Repo(**config) revision = get_build_revision() if revision is None: revision = repo.head() set_build_revision(revision) repo.sync(revision=revision) user_changelist = get_users_changelist() if user_changelist: # Use existing or make a copy of the users changelist for this build changelist = get_build_changelist() if not changelist: changelist = user_changelist if should_backup_changelists(): changelist = repo.backup(user_changelist) set_build_changelist(changelist) repo.p4print_unshelve(changelist) description = repo.description( # Prefer users change description over latest submitted change get_users_changelist() or repo.head_at_revision(revision)) set_build_info(revision, description)
def test_head(server, tmpdir): """Test resolve of HEAD changelist""" # workspace with no changes in view defaults to global view repo = P4Repo(root=tmpdir, view="//depot/empty_dir/... empty_dir/...") assert repo.head() == "@9", "Unexpected global HEAD revision" repo = P4Repo(root=tmpdir, stream='//stream-depot/dev') assert repo.head() == "@8", "Unexpected HEAD revision for stream" repo = P4Repo(root=tmpdir, stream='//stream-depot/idontexist') with pytest.raises( Exception, match=r"Stream '//stream-depot/idontexist' doesn't exist."): repo.head() assert repo.head_at_revision( "@my-label") == "2", "Unexpected HEAD revision for label"
def main(): """Perform any last-second cleanup regardless of success or failure""" os.environ.update(get_env()) config = get_config() repo = P4Repo(**config) repo.revert()
def test_checkout_stream(server, tmpdir): """Test checking out a stream depot""" repo = P4Repo(root=tmpdir, stream='//stream-depot/main') assert os.listdir(tmpdir) == [], "Workspace should be empty" repo.sync() with open(os.path.join(tmpdir, "file.txt")) as content: assert content.read( ) == "Hello Stream World\n", "Unexpected content in workspace file"
def test_p4print_unshelve(server, tmpdir): """Test unshelving a pending changelist by p4printing content into a file""" repo = P4Repo(root=tmpdir) repo.sync() with open(os.path.join(tmpdir, "file.txt")) as content: assert content.read( ) == "Hello World\n", "Unexpected content in workspace file" repo.p4print_unshelve('3') # Modify a file with open(os.path.join(tmpdir, "file.txt")) as content: assert content.read( ) == "Goodbye World\n", "Unexpected content in workspace file" repo.p4print_unshelve('4') # Delete a file assert not os.path.exists(os.path.join(tmpdir, "file.txt")) repo.p4print_unshelve('5') # Add a file assert os.path.exists(os.path.join(tmpdir, "newfile.txt")) with pytest.raises( Exception, match=r'Changelist 999 does not contain any shelved files.'): repo.p4print_unshelve('999') assert len( repo._read_patched()) == 2 # changes to file.txt and newfile.txt # Unshelved changes are removed in following syncs repo.sync() with open(os.path.join(tmpdir, "file.txt")) as content: assert content.read( ) == "Hello World\n", "Unexpected content in workspace file" assert not os.path.exists(os.path.join( tmpdir, "newfile.txt")), "File unshelved for add was not deleted" # Shelved changes containing files not selected for sync are skipped repo = P4Repo(root=tmpdir, sync=['//depot/fake-dir/...']) repo.sync() repo.p4print_unshelve('3') # Modify file.txt assert not os.path.exists(os.path.join(tmpdir, "file.txt")) # Shelved changes containing files not mapped into this workspace do not throw an exception repo = P4Repo(root=tmpdir, stream='//stream-depot/main') repo.p4print_unshelve('3') # Modify a file
def test_checkout_stream(): """Test checking out a stream depot""" with setup_server_and_client() as client_root: repo = P4Repo(root=client_root, stream='//stream-depot/main') assert os.listdir(client_root) == [], "Workspace should be empty" repo.sync() with open(os.path.join(client_root, "file.txt")) as content: assert content.read( ) == "Hello Stream World\n", "Unexpected content in workspace file"
def test_backup_shelve(server, tmpdir): """Test making a copy of a shelved changelist""" repo = P4Repo(root=tmpdir) backup_changelist = repo.backup('3') assert backup_changelist != '3', "Backup changelist number must be new" repo.revert() repo.unshelve(backup_changelist) with open(os.path.join(tmpdir, "file.txt")) as content: assert content.read( ) == "Goodbye World\n", "Unexpected content in workspace file"
def test_fingerprint_bad(server, tmpdir): """Test supplying an incorrect fingerprint""" os.environ['P4TRUST'] = os.path.join(tmpdir, 'trust.txt') repo = P4Repo( root=tmpdir, fingerprint= 'FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF') with pytest.raises(Exception, match=r"The authenticity of '.+' can't be established"): repo.sync()
def test_checkout_label(server, tmpdir): """Test checking out at a specific label""" repo = P4Repo(root=tmpdir) with pytest.raises(Exception, match=r'Invalid changelist/client/label/date'): repo.sync(revision="@nonexistent-label") repo.sync(revision="@my-label") with open(os.path.join(tmpdir, "file.txt")) as content: assert content.read( ) == "Hello World\n", "Unexpected content in workspace file"
def test_p4print_unshelve(): """Test unshelving a pending changelist by p4printing content into a file""" with setup_server_and_client() as client_root: repo = P4Repo(root=client_root) repo.sync() with open(os.path.join(client_root, "file.txt")) as content: assert content.read( ) == "Hello World\n", "Unexpected content in workspace file" repo.p4print_unshelve('3') # Modify a file with open(os.path.join(client_root, "file.txt")) as content: assert content.read( ) == "Goodbye World\n", "Unexpected content in workspace file" repo.p4print_unshelve('4') # Delete a file assert not os.path.exists(os.path.join(client_root, "file.txt")) repo.p4print_unshelve('5') # Add a file assert os.path.exists(os.path.join(client_root, "newfile.txt")) with pytest.raises( Exception, match=r'Changelist 999 does not contain any shelved files.'): repo.p4print_unshelve('999') assert len( repo._read_patched()) == 2 # changes to file.txt and newfile.txt # Unshelved changes are removed in following syncs repo.sync() with open(os.path.join(client_root, "file.txt")) as content: assert content.read( ) == "Hello World\n", "Unexpected content in workspace file" assert not os.path.exists(os.path.join(client_root, "newfile.txt")) # Shelved changes containing files not mapped into this workspace do not throw an exception repo = P4Repo(root=client_root, stream='//stream-depot/main') repo.p4print_unshelve('3') # Modify a file
def test_stream_switching_migration(server, tmpdir): """Test stream-switching and client migration simultaneously""" repo = P4Repo(root=tmpdir, stream='//stream-depot/main') synced = repo.sync() assert len(synced) > 0, "Didn't sync any files" assert set(os.listdir(tmpdir)) == set( ["file.txt", "file_2.txt", "p4config"]) with open(os.path.join(tmpdir, "file.txt")) as content: assert content.read( ) == "Hello Stream World\n", "Unexpected content in workspace file" with tempfile.TemporaryDirectory(prefix="bk-p4-test-") as second_client: copytree(tmpdir, second_client) # Client names include path on disk, so this creates a new unique client # Re-use the same checkout directory and switch streams at the same time repo = P4Repo(root=second_client, stream='//stream-depot/dev') repo.sync() assert len(synced) > 0, "Didn't sync any files" assert set(os.listdir(second_client)) == set( ["file.txt", "p4config"]) # file_2.txt was de-synced with open(os.path.join(second_client, "file.txt")) as content: assert content.read( ) == "Hello Stream World (dev)\n", "Unexpected content in workspace file"
def test_fixture(capsys): """Check that tests can start and connect to a local perforce server""" port = setup_server(from_zip='server.zip') with capsys.disabled(): print('port:', port, 'user: carl') repo = P4Repo() assert repo.info()['serverAddress'] == port # There should be a sample file checked into the fixture server # Returns [metadata, contents] content = repo.perforce.run_print("//depot/file.txt")[1] assert content == "Hello World\n" assert repo.head() == "2", "Unexpected head revision" shelved_change = repo.perforce.run_describe('-sS', '3') assert len(shelved_change) > 0, "Shelved changelist was missing" assert shelved_change[0]['depotFile'] == [ '//depot/file.txt' ], "Unexpected files in shelved changelist"
def test_checkout(server, tmpdir): """Test normal flow of checking out files""" repo = P4Repo(root=tmpdir) assert os.listdir(tmpdir) == [], "Workspace should be empty" repo.sync() assert sorted(os.listdir(tmpdir)) == sorted( ["file.txt", "p4config"]), "Workspace sync not as expected" with open(os.path.join(tmpdir, "file.txt")) as content: assert content.read( ) == "Hello World\n", "Unexpected content in workspace file" repo.sync(revision='@0') assert "file.txt" not in os.listdir( tmpdir), "Workspace file wasn't de-synced" # Validate p4config with open(os.path.join(tmpdir, "p4config")) as content: assert "P4PORT=%s\n" % repo.perforce.port in content.readlines( ), "Unexpected p4config content"
def main(): """Main""" os.environ.update(get_env()) config = get_config() repo = P4Repo(**config) revision = get_build_revision() if revision is None: revision = repo.head() set_build_revision(revision) repo.sync(revision=revision) user_changelist = get_users_changelist() if user_changelist: repo.p4print_unshelve(user_changelist) description = repo.description( # Prefer users change description over latest submitted change user_changelist or repo.head_at_revision(revision)) set_build_info(revision, description)
def test_unshelve(): """Test unshelving a pending changelist""" with setup_server_and_client() as client_root: repo = P4Repo(root=client_root) repo.sync() with open(os.path.join(client_root, "file.txt")) as content: assert content.read( ) == "Hello World\n", "Unexpected content in workspace file" repo.unshelve('3') with open(os.path.join(client_root, "file.txt")) as content: assert content.read( ) == "Goodbye World\n", "Unexpected content in workspace file" with pytest.raises( Exception, match=r'Changelist 999 does not contain any shelved files.'): repo.unshelve('999') # Unshelved changes are removed in following syncs repo.sync() with open(os.path.join(client_root, "file.txt")) as content: assert content.read( ) == "Hello World\n", "Unexpected content in workspace file"
def test_checkout_partial_multiple(server, tmpdir): """Test checking out a subset of view with multiple paths""" repo = P4Repo(root=tmpdir, sync=['//depot/fake-dir/...', '//depot/file.txt']) repo.sync() assert 'file.txt' in os.listdir(tmpdir)
def test_server_fixture(capsys, server): """Check that tests can start and connect to a local perforce server""" with capsys.disabled(): print('port:', server, 'user: carl') repo = P4Repo() # To change the fixture server, uncomment the line below with 'store_server' and put a breakpoint on it # Run unit tests in the debugger and hit the breakpoint # Log in using details printed to stdout (port/user) via p4v or the command line # Make changes to the p4 server # Continue execution so that the 'store_server' line executes # Replace server.zip with new_server.zip # Update validation code below to document the new server contents # store_server(repo, 'new_server.zip') # Validate contents of server fixture @HEAD depotfiles = [ info['depotFile'] for info in repo.perforce.run_files('//...') ] depotfile_to_content = { depotfile: repo.perforce.run_print(depotfile)[1] for depotfile in depotfiles } assert depotfile_to_content == { "//depot/file.txt": "Hello World\n", "//stream-depot/main/file.txt": "Hello Stream World\n", "//stream-depot/main/file_2.txt": "file_2\n", "//stream-depot/dev/file.txt": "Hello Stream World (dev)\n", } # Check submitted changes submitted_changes = repo.perforce.run_changes('-s', 'submitted') submitted_changeinfo = { change["change"]: repo.perforce.run_describe(change["change"])[0] for change in submitted_changes } # Filter info to only contain relevant keys for submitted changes submitted_changeinfo = { change: {key: info.get(key) for key in ['depotFile', 'desc', 'action']} for change, info in submitted_changeinfo.items() } assert submitted_changeinfo == { '1': { 'action': ['add'], 'depotFile': ['//depot/file.txt'], 'desc': 'Initial Commit' }, '2': { 'action': ['add'], 'depotFile': ['//stream-depot/main/file.txt'], 'desc': 'Initial Commit to Stream\n' }, '6': { 'action': ['edit'], 'depotFile': ['//depot/file.txt'], 'desc': 'modify //depot/file.txt\n' }, '7': { 'action': ['branch'], 'depotFile': ['//stream-depot/dev/file.txt'], 'desc': 'Copy files from //stream-depot/main to //stream-depot/dev\n' }, '8': { 'action': ['edit'], 'depotFile': ['//stream-depot/dev/file.txt'], 'desc': 'Update contents of //stream-depot/dev/file.txt\n' }, '9': { 'action': ['add'], 'depotFile': ['//stream-depot/main/file_2.txt'], 'desc': 'file_2.txt - exists in main but not dev\n' } } # Check shelved changes shelved_changes = repo.perforce.run_changes('-s', 'pending') shelved_changeinfo = { change["change"]: repo.perforce.run_describe('-S', change["change"])[0] for change in shelved_changes } # Filter info to only contain relevant keys for submitted changes shelved_changeinfo = { change: {key: info.get(key) for key in ['depotFile', 'desc', 'action']} for change, info in shelved_changeinfo.items() } assert shelved_changeinfo == { '3': { 'action': ['edit'], 'depotFile': ['//depot/file.txt'], 'desc': 'Modify file in shelved change\n', # Change content from 'Hello World\n' to 'Goodbye World\n' }, '4': { 'action': ['delete'], 'depotFile': ['//depot/file.txt'], 'desc': 'Delete file in shelved change\n', }, '5': { 'action': ['add'], 'depotFile': ['//depot/newfile.txt'], 'desc': 'Add file in shelved change\n', }, } labels = repo.perforce.run_labels() # Filter info to only contain relevant keys labelinfo = { label.get('label'): {key: label.get(key) for key in ['Revision']} for label in labels } assert labelinfo == {'my-label': {'Revision': '@2'}}
def test_checkout_partial_dir(server, tmpdir): """Test checking out a subset of view with one directory""" repo = P4Repo(root=tmpdir, sync=['//depot/...']) repo.sync() assert 'file.txt' in os.listdir(tmpdir)
def test_partitioned_client(server, tmpdir): """Test creation of a partitioned client""" repo = P4Repo(root=tmpdir, client_type='partitioned') repo.sync() assert "file.txt" in os.listdir(tmpdir), "Workspace file was not synced"
def test_readonly_client(server, tmpdir): """Test creation of a readonly client""" repo = P4Repo(root=tmpdir, client_type='readonly') repo.sync() assert "file.txt" in os.listdir(tmpdir), "Workspace file was not synced"