summaryrefslogtreecommitdiff
path: root/testing/03-treedelta-rules.yarn
blob: fada9ff839aa888cad0fe49e70a98d995fa9c3ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
<!-- -*- markdown -*- -->

Using the tree deltas in rules
==============================

Gitano is able to use the tree deltas produced by changes in ref tips when
evaluating whether or not an update is permitted.  Since the tree deltas can be
expensive to generate, we only trigger generation of them on demand. As such
they are an area of the code where errors could easily trickle in unless we
keep a close eye on things.

Start and Target trees
----------------------

The first part of the treedelta support are the gitano/starttree and
gitano/targetttee lists.  These contain the flattened entry names for
everything in the trees.

First, let's look at what it takes to prevent the creation of files with FOO in.

    SCENARIO may not create files called FOO
    GIVEN a standard instance
      AND testinstance using adminkey has patched gitano-admin with no-create-FOO.patch
    GIVEN a unix user called alice
      AND alice has keys called main

    WHEN testinstance, using adminkey, adds user alice, using alice main
     AND testinstance adminkey runs create testrepo alice
     AND alice, using main, clones testrepo as testrepo
    THEN alice testrepo has no file called FOO

    WHEN alice applies add-a-FOO.patch in testrepo
     AND alice, using main, expecting failure, pushes testrepo to testrepo.git
    THEN stderr contains No FOOs allowed

    FINALLY the instance is torn down

Next, let's look at how we might require a FOO to be present...

    SCENARIO source must have a FOO
    GIVEN a standard instance
      AND a unix user called alice
      AND alice has keys called main

    WHEN testinstance, using adminkey, adds user alice, using alice main
     AND testinstance adminkey runs create testrepo alice
     AND alice, using main, clones testrepo as testrepo
    THEN alice testrepo has no file called FOO

We now have a repo which has no FOO in it, let's first check that our admin
rule which requires `start_tree` contain a FOO by trying to push an empty tree

    GIVEN testinstance using adminkey has patched gitano-admin with must-start-with-FOO.patch

    WHEN alice, using main, expecting failure, pushes an empty commit in testrepo
    THEN stderr contains Needs a FOO

Next, let's create a FOO in our tree, prove that `start_tree` != `target_tree`

    WHEN alice applies add-a-FOO.patch in testrepo
     AND alice, using main, pushes testrepo to testrepo.git
    THEN stderr contains Needs a FOO

And if we back out the rule, we can push it...

    GIVEN testinstance using adminkey has patched gitano-admin with the reverse of must-start-with-FOO.patch

    WHEN alice, using main, pushes testrepo to testrepo.git
    THEN the output contains new branch

And if we put the rule back in, an empty commit will make it through because
`start_tree` now does contain a FOO

    GIVEN testinstance using adminkey has patched gitano-admin with must-start-with-FOO.patch

    WHEN alice, using main, pushes an empty commit in testrepo
    THEN the output contains master -> master

And once again, prove `start_tree` != `target_tree` by backing out the FOO
and proving we can push that.

    WHEN alice reverts add-a-FOO.patch in testrepo
     AND alice, using main, pushes testrepo to testrepo.git
    THEN the output contains master -> master

And of course, now `start_tree` does not contain a FOO, so no matter what
we do to `target_tree` we can't push...

    WHEN alice applies add-a-FOO.patch in testrepo
     AND alice, using main, pushes testrepo to testrepo.git
    THEN stderr contains Needs a FOO

    FINALLY the instance is torn down

Tree deltas
-----------

When there are trees in play, the `treediff/targets`, `treediff/added`,
`treediff/deleted`, `treediff/modified`, `treediff/renamed`, and
`treediff/renamedto` values end up set.

The _targets_ are any name which shows up in any of _added_, _deleted_,
_modified_, _renamed_, or _renamedto_.  The others are, respectively, the
names of new tree entries, removed tree entries, entries whose content has
changed, and then rename detection logic.

> Sadly currently Gitano can't tell which rename from/to is matched with which.

First up, let's ensure that `treediff/targets` works for the various kinds
of adding, modifying, removing, and renaming operations...

    SCENARIO any change must affect FOO
    GIVEN a standard instance
      AND a unix user called alice
      AND alice has keys called main

    WHEN testinstance, using adminkey, adds user alice, using alice main
     AND testinstance adminkey runs create testrepo alice
     AND alice, using main, clones testrepo as testrepo
    THEN alice testrepo has no file called FOO

    GIVEN testinstance using adminkey has patched gitano-admin with must-affect-FOO.patch

First up, when we try an empty commit we can't push it...

    WHEN alice, using main, expecting failure, pushes an empty commit in testrepo
    THEN stderr contains Needs a FOO

Next, when a FOO is added, it should turn up in `treediff/targets`

    WHEN alice applies add-a-FOO.patch in testrepo
     AND alice, using main, pushes testrepo to testrepo.git
    THEN the output contains new branch

But its mere presence in `start_tree` shouldn't allow empty commits...

    WHEN alice, using main, expecting failure, pushes an empty commit in testrepo
    THEN stderr contains Needs a FOO

Now we verify that altering the content turns up in `treediff/targets`

    WHEN alice applies change-a-FOO.patch in testrepo
     AND alice, using main, pushes testrepo to testrepo.git
    THEN the output contains master -> master

Next, when the FOO gets removed, it should show in `treediff/targets`

    WHEN alice reverts change-a-FOO.patch in testrepo
     AND alice reverts add-a-FOO.patch in testrepo
     AND alice, using main, pushes testrepo to testrepo.git
    THEN the output contains master -> master

Next we need to rename a FOO, to do that, first add it back...

    WHEN alice applies add-a-FOO.patch in testrepo
     AND alice, using main, pushes testrepo to testrepo.git
    THEN the output contains master -> master

and then check that renaming the FOO causes it to turn up in `treediff/targets`

    WHEN alice applies rename-a-FOO.patch in testrepo
     AND alice, using main, pushes testrepo to testrepo.git
    THEN the output contains master -> master

and finally we ensure that renaming it *back* works too...

    WHEN alice reverts rename-a-FOO.patch in testrepo
     AND alice, using main, pushes testrepo to testrepo.git
    THEN the output contains master -> master

    FINALLY the instance is torn down

Now that we know that `treediff/targets` works in all cases, we ensure that
the particular `treediff/*` element is also populated for the given activity

    SCENARIO any change must affect FOO with specificity
    GIVEN a standard instance
      AND a unix user called alice
      AND alice has keys called main

    WHEN testinstance, using adminkey, adds user alice, using alice main
     AND testinstance adminkey runs create testrepo alice
     AND alice, using main, clones testrepo as testrepo
    THEN alice testrepo has no file called FOO

    GIVEN testinstance using adminkey has patched gitano-admin with must-add-FOO.patch

First up, when we try an empty commit we can't push it...

    WHEN alice, using main, expecting failure, pushes an empty commit in testrepo
    THEN stderr contains Needs a FOO

Next, when a FOO is added, it should turn up in `treediff/added`

    WHEN alice applies add-a-FOO.patch in testrepo
     AND alice, using main, pushes testrepo to testrepo.git
    THEN the output contains new branch

But its mere presence in `start_tree` shouldn't allow empty commits...

    WHEN alice, using main, expecting failure, pushes an empty commit in testrepo
    THEN stderr contains Needs a FOO

Now we verify that altering the content turns up in `treediff/modified`

    GIVEN testinstance using adminkey has patched gitano-admin with the reverse of must-add-FOO.patch
      AND testinstance using adminkey has patched gitano-admin with must-modify-FOO.patch

    WHEN alice applies change-a-FOO.patch in testrepo
     AND alice, using main, pushes testrepo to testrepo.git
    THEN the output contains master -> master

Next, when the FOO gets removed, it should show in `treediff/deleted`

    GIVEN testinstance using adminkey has patched gitano-admin with the reverse of must-modify-FOO.patch
      AND testinstance using adminkey has patched gitano-admin with must-remove-FOO.patch

    WHEN alice reverts change-a-FOO.patch in testrepo
     AND alice reverts add-a-FOO.patch in testrepo
     AND alice, using main, pushes testrepo to testrepo.git
    THEN the output contains master -> master

Next we need to rename a FOO, to do that, first add it back...

    GIVEN testinstance using adminkey has patched gitano-admin with the reverse of must-remove-FOO.patch

    WHEN alice applies add-a-FOO.patch in testrepo
     AND alice, using main, pushes testrepo to testrepo.git
    THEN the output contains master -> master

and then check that renaming the FOO causes it to turn up in `treediff/renamed`

    GIVEN testinstance using adminkey has patched gitano-admin with must-rename-from-FOO.patch

    WHEN alice applies rename-a-FOO.patch in testrepo
     AND alice, using main, pushes testrepo to testrepo.git
    THEN the output contains master -> master

and finally we ensure that renaming it *back* works too...

    GIVEN testinstance using adminkey has patched gitano-admin with the reverse of must-rename-from-FOO.patch
      AND testinstance using adminkey has patched gitano-admin with must-rename-to-FOO.patch

    WHEN alice reverts rename-a-FOO.patch in testrepo
     AND alice, using main, pushes testrepo to testrepo.git
    THEN the output contains master -> master

    FINALLY the instance is torn down