Morph black box tests for system branches and workspaces ======================================================== Morph implements **system branches**, which are checked out and manipulated by the user in **workspaces**. See FIXME for more information. Workspace creation ------------------ The first thing a user needs to do is create a workspace. SCENARIO create and initialise a new workspace GIVEN no workspace WHEN the user initialises a workspace THEN an empty workspace exists The workspace directory may exist, if it is empty. SCENARIO initialise an empty workspace directory GIVEN an empty workspace directory WHEN the user initialises a workspace THEN an empty workspace exists However, the directory must really be empty. It must not be an empty, but initialised workspace. SCENARIO initialise an existing, empty workspace directory GIVEN no workspace WHEN the user initialises a workspace AND the user attempts to initialise a workspace THEN morph failed Likewise, if the directory exists, and is non-empty, but isn't an existing workspace, initialising it should fail. SCENARIO initialise a non-empty workspace directory GIVEN a non-empty workspace directory WHEN the user attempts to initialise a workspace THEN morph failed Checking out system branches ----------------------------------------- Once we have a workspace, we can check out a system branch. SCENARIO check out an existing system branch GIVEN a workspace AND a git server WHEN the user checks out the system branch called master THEN the system branch master is checked out Edit is probably not the best name for is, but we can use `morph edit` to investigate chunks in existing branches. WHEN the user edits the chunk test-chunk in branch master THEN the edited chunk test:test-chunk has git branch master Checking out a system branch should fail, if the branch doesn't exist. SCENARIO checking out a system branch that doesn't exist GIVEN a workspace AND a git server WHEN the user attempts to check out the system branch called foo THEN morph failed Branching system branches ----------------------------------------- We can, instead, create a new system branch, off master. SCENARIO branch off master GIVEN a workspace AND a git server WHEN the user creates a system branch called foo THEN the system branch foo is checked out We can also branch off another system branch. However, we need to first push the other branch to the git server, since Morph is not smart enough to check for that locally. SCENARIO branch off non-master GIVEN a workspace AND a git server WHEN the user creates a system branch called foo AND the user pushes the system branch called foo to the git server AND the user creates a system branch called bar, based on foo THEN the system branch bar is checked out Query commands in workspaces ---------------------------- `morph workspace` writes out the fully qualified path to the workspace directory, regardless of where the user is. There's a few cases. SCENARIO morph workspace works at root of empty workspace GIVEN a workspace WHEN the user reports the workspace from the directory . THEN the workspace is reported correctly Also check it in the root of a system branch checkout, and inside a git checkout inside that. SCENARIO morph workspace works in system branch checkouts GIVEN a workspace AND a git server WHEN the user checks out the system branch called master AND the user reports the workspace from the directory master THEN the workspace is reported correctly We leak a little bit of the implementation here, to keep things simple: the (mocked) git server the implementation sets up has the `test:morphs` repository, which is the system branch root repository. WHEN the user reports the workspace from the directory master/test/morphs THEN the workspace is reported correctly However, running it outside a workspace should fail. SCENARIO morph fails outside workspace GIVEN no workspace WHEN the user attempts to report the workspace from a non-workspace directory THEN morph failed `morph show-system-branch` should report the name of the system branch, when run anywhere in the system branch checkout. As a special case, if there is only one system branch checkout at or below the current working directory, it will find it and report it correctly. SCENARIO morph reports system branch GIVEN a workspace AND a git server WHEN the user checks out the system branch called master AND the user reports the system branch from the directory master THEN the system branch is reported as master WHEN the user reports the system branch from the directory master/test/morphs THEN the system branch is reported as master WHEN the user reports the system branch from the directory . THEN the system branch is reported as master However, if there's two system branches checked out below the current directory, things should fail. SCENARIO morph fails to report system branch with two checked out GIVEN a workspace AND a git server WHEN the user checks out the system branch called master AND the user creates a system branch called foo AND the user attempts to report the system branch from the directory . THEN morph failed `morph show-branch-root` reports the path of the system branch root repository. It can be run inside a checkout, or somewhere outside a checkout, where exactly one checkout exists below. SCENARIO morph reports system branch root repository GIVEN a workspace AND a git server WHEN the user checks out the system branch called master AND the user reports the system branch root repository from the directory master THEN the system branch root repository is reported as workspace/master/test/morphs WHEN the user reports the system branch root repository from the directory . THEN the system branch root repository is reported as workspace/master/test/morphs However, it fails if run outside a checkout and there's no system branches checked out. SCENARIO morph fails to report system branch with none checked out GIVEN a workspace AND a git server WHEN the user attempts to report the system branch root repository from the directory . THEN morph failed Editing components ------------------ `morph edit` can edit refs for a chunk, and check out the chunk's repository. First of all, we verify that that when we create a system branch, all the refs are unchanged. SCENARIO morph branch does not edit refs GIVEN a workspace AND a git server WHEN the user creates a system branch called foo Edit the chunk. We make use of special knowledge here: `test:test-chunk` is a chunk repository created in the mocked git server, for testing purposes. WHEN the user edits the chunk test-chunk in branch foo THEN in branch foo, stratum strata/test-stratum.morph refs test-chunk in foo AND the edited chunk test:test-chunk has git branch foo Editing a morphology should not cause it to start having repo or ref fields when referring to strata, when it didn't before. AND in branch foo, system systems/test-system.morph refers to test-stratum without repo AND in branch foo, system systems/test-system.morph refers to test-stratum without ref Temporary Build Branch behaviour -------------------------------- Morph always builds from committed changes, but it's not always convenient to commit and push changes, so `morph build` can create temporary build branches when necessary. ### What gets included in temporary build branches ### SCENARIO morph builds the branches of edited chunks you checked-out GIVEN a workspace AND a git server WHEN the user checks out the system branch called master AND the user edits the chunk test-chunk in branch master If we make an uncommitted change to an edited chunk, then a temporary build branch is made to include that change. WHEN the user makes changes to test-chunk in branch master AND the user builds systems/test-system.morph of the master branch THEN the changes to test-chunk in branch master are included in the temporary build branch ### When branches are created ### It's convenient to have Temporary Build Branches, but we don't always need them, and they get in the way when we don't need them, so we need to be careful about when to make them. SCENARIO morph makes temporary build branches for uncommitted changes when necessary GIVEN a workspace AND a git server WHEN the user checks out the system branch called master The user hasn't made any changes yet, so attempts to build require no temporary build branches. GIVEN the workspace contains no temporary build branches AND we can build with local branches WHEN the user builds systems/test-system.morph of the master branch THEN the morphs repository in the workspace for master has no temporary build branches Similarly, if we need to build from pushed branches, such as when we're distbuilding, we don't need temporary build branches yet, since we have no local changes. GIVEN the workspace contains no temporary build branches AND the git server contains no temporary build branches AND we must build from pushed branches WHEN the user builds systems/test-system.morph of the master branch THEN the morphs repository in the workspace for master has no temporary build branches AND no temporary build branches were pushed to the morphs repository If we actually want to be able to push our changes for review, we need to use a different branch from master, since we require code to be reviewed then merged, rather than pushing directly to master. WHEN the user creates a system branch called baserock/test When we start making changes we do need temporary build branches, since the chunk specifiers in the strata now need to refer to the local changes to the repository. WHEN the user edits the chunk test-chunk in branch baserock/test If we don't need to build from pushed branches then we have temporary build branches only in the local clones of the repositories. GIVEN the workspace contains no temporary build branches AND the git server contains no temporary build branches AND we can build with local branches WHEN the user builds systems/test-system.morph of the baserock/test branch THEN the morphs repository in the workspace for baserock/test has temporary build branches AND no temporary build branches were pushed to the morphs repository If we do need to build from pushed changes, then the temporary build branch needs to be pushed. GIVEN the workspace contains no temporary build branches AND the git server contains no temporary build branches AND we must build from pushed branches WHEN the user builds systems/test-system.morph of the baserock/test branch THEN the morphs repository in the workspace for baserock/test has temporary build branches AND temporary build branches were pushed to the morphs repository NOTE: We're not checking whether the test-chunk repo has changes since it's currently an implementation detail that it does, but it would be possible to build without a temporary build branch for the chunk repository. Now that we have the chunk repository available, we can make our changes. WHEN the user makes changes to test-chunk in branch baserock/test When we have uncommitted changes to chunk repositories, we need temporary build branches locally for local builds. GIVEN the workspace contains no temporary build branches AND the git server contains no temporary build branches AND we can build with local branches WHEN the user builds systems/test-system.morph of the baserock/test branch THEN the morphs repository in the workspace for baserock/test has temporary build branches AND the test-chunk repository in the workspace for baserock/test has temporary build branches AND no temporary build branches were pushed to the morphs repository AND no temporary build branches were pushed to the test-chunk repository As before, we also need temporary build branches to have been pushed GIVEN the workspace contains no temporary build branches AND the git server contains no temporary build branches AND we must build from pushed branches WHEN the user builds systems/test-system.morph of the baserock/test branch THEN the morphs repository in the workspace for baserock/test has temporary build branches AND the test-chunk repository in the workspace for baserock/test has temporary build branches AND temporary build branches were pushed to the morphs repository AND temporary build branches were pushed to the test-chunk repository Now that we've made our changes, we can commit them. WHEN the user commits changes to morphs in branch baserock/test AND the user commits changes to test-chunk in branch baserock/test For local builds we should be able to use these committed changes, provided the ref in the morphology matches the committed ref in the chunk repository. However, since we do not currently do this integrity check, as it requires extra tracking between edited morphologies and the local repositories, it's easier to just require a temporary build branch. GIVEN the workspace contains no temporary build branches AND the git server contains no temporary build branches AND we can build with local branches WHEN the user builds systems/test-system.morph of the baserock/test branch THEN the morphs repository in the workspace for baserock/test has temporary build branches AND the test-chunk repository in the workspace for baserock/test has temporary build branches AND no temporary build branches were pushed to the morphs repository AND no temporary build branches were pushed to the test-chunk repository For distributed building, it being committed locally is not sufficient, as remote workers need to be able to access the changes, and dist-build workers tunneling into the developer's machine and using those repositories would be madness, so we require temporary build branches to be pushed. GIVEN the workspace contains no temporary build branches AND the git server contains no temporary build branches AND we must build from pushed branches WHEN the user builds systems/test-system.morph of the baserock/test branch THEN the morphs repository in the workspace for baserock/test has temporary build branches AND the test-chunk repository in the workspace for baserock/test has temporary build branches AND temporary build branches were pushed to the morphs repository AND temporary build branches were pushed to the test-chunk repository We can now push our committed changes. WHEN the user pushes the system branch called baserock/test to the git server We now don't need temporary build branches for local builds. GIVEN the workspace contains no temporary build branches AND the git server contains no temporary build branches AND we can build with local branches WHEN the user builds systems/test-system.morph of the baserock/test branch THEN the morphs repository in the workspace for baserock/test has no temporary build branches AND the test-chunk repository in the workspace for baserock/test has no temporary build branches AND no temporary build branches were pushed to the morphs repository AND no temporary build branches were pushed to the test-chunk repository Nor do we need temporary build branches for distributed builds. GIVEN the workspace contains no temporary build branches AND the git server contains no temporary build branches AND we must build from pushed branches WHEN the user builds systems/test-system.morph of the baserock/test branch THEN the morphs repository in the workspace for baserock/test has no temporary build branches AND the test-chunk repository in the workspace for baserock/test has no temporary build branches AND no temporary build branches were pushed to the morphs repository AND no temporary build branches were pushed to the test-chunk repository ### Temporary Build Branch implementations ### IMPLEMENTS WHEN the user makes changes to test-chunk in branch (\S+) chunkdir="$(slashify_colons "test:test-chunk")" cd "$DATADIR/workspace/$MATCH_1/$chunkdir" sed -i -e 's/Hello/Goodbye/g' test-bin IMPLEMENTS THEN the changes to test-chunk in branch (\S+) are included in the temporary build branch build_ref_prefix=baserock/builds/ chunkdir="$(slashify_colons "test:test-chunk")" cd "$DATADIR/workspace/$MATCH_1/$chunkdir" eval "$(git for-each-ref --count=1 --shell --sort=committerdate \ --format='git cat-file -p %(refname):test-bin | diff test-bin -' \ "$build_ref_prefix")" IMPLEMENTS WHEN the user commits changes to (\S+) in branch (\S+) chunkdir="$(slashify_colons "test:$MATCH_1")" cd "$DATADIR/workspace/$MATCH_2/$chunkdir" git commit -a -m 'Commit local changes' Status of system branch checkout -------------------------------- `morph status` shows the status of all git repositories in a system branch checkout: only the ones that exist locally, not all the repositories referenced in the system branch. SCENARIO morph status reports changes correctly GIVEN a workspace AND a git server WHEN the user creates a system branch called foo THEN morph reports no outstanding changes in foo WHEN the user edits the chunk test-chunk in branch foo THEN morph reports changes in foo in test:morphs only WHEN creating file foo in test/test-chunk in branch foo THEN morph reports changes in foo in test:morphs only WHEN adding file foo in test:test-chunk in branch foo to git THEN morph reports changes in foo in test:morphs and test:test-chunk WHEN committing changes in test:morphs in branch foo THEN morph reports changes in foo in test:test-chunk only WHEN committing changes in test:test-chunk in branch foo THEN morph reports no outstanding changes in foo `morph foreach` -------------- `morph foreach` runs a shell command in each of the git repos in a system branch checkout. SCENARIO morph foreach runs command in each git repo GIVEN a workspace AND a git server WHEN the user creates a system branch called foo AND the user edits the chunk test-chunk in branch foo AND running shell command in each repo in foo THEN morph ran command in test/morphs in foo AND morph ran command in test/test-chunk in foo Generating a manifest works SCENARIO morph generates a manifest GIVEN a workspace AND a system artifact WHEN morph generates a manifest THEN the manifest is generated