summaryrefslogtreecommitdiff
path: root/subversion/tests/cmdline/entries_tests.py
blob: 0fcdc1a1c6bfa43113356db4aa9bc99e00c25d1f (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
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
#!/usr/bin/env python
#
#  entries_tests.py:  test the old entries API using entries-dump
#
#  Subversion is a tool for revision control.
#  See http://subversion.apache.org for more information.
#
# ====================================================================
#    Licensed to the Apache Software Foundation (ASF) under one
#    or more contributor license agreements.  See the NOTICE file
#    distributed with this work for additional information
#    regarding copyright ownership.  The ASF licenses this file
#    to you under the Apache License, Version 2.0 (the
#    "License"); you may not use this file except in compliance
#    with the License.  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing,
#    software distributed under the License is distributed on an
#    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
#    KIND, either express or implied.  See the License for the
#    specific language governing permissions and limitations
#    under the License.
######################################################################

#
# This test series is to validate the old entries API using the entries-dump
# tool to see what the API reports. In particular, this test is designed to
# try and exercise all "extraordinary" code paths in the read_entries()
# function in libsvn_wc/entries.c. Much of that function is exercised by
# the regular test suite and its secondary "status" via entries-dump. This
# test tries to pick up the straggly little edge cases.
#

import os, logging

logger = logging.getLogger()

import svntest

Item = svntest.wc.StateItem


SCHEDULE_NORMAL = 0
SCHEDULE_ADD = 1
SCHEDULE_DELETE = 2
SCHEDULE_REPLACE = 3


def validate(entry, **kw):
  for key, value in kw.items():
    if getattr(entry, key) != value:
      logger.warn("Entry '%s' has an incorrect value for .%s", entry.name, key)
      logger.warn("  Expected: %s", value)
      logger.warn("    Actual: %s", getattr(entry, key))
      raise svntest.Failure


def check_names(entries, *names):
  if entries is None:
    logger.warn('entries-dump probably exited with a failure.')
    raise svntest.Failure
  have = set(entries.keys())
  want = set(names)
  missing = want - have
  if missing:
    logger.warn("Entry name(s) not found: %s",
          ', '.join("'%s'" % name for name in missing))
    raise svntest.Failure


def basic_entries(sbox):
  "basic entries behavior"

  sbox.build()
  wc_dir = sbox.wc_dir

  alpha_path = os.path.join(wc_dir, 'A', 'B', 'E', 'alpha')
  beta_path = os.path.join(wc_dir, 'A', 'B', 'E', 'beta')
  added_path = os.path.join(wc_dir, 'A', 'B', 'E', 'added')
  G_path = os.path.join(wc_dir, 'A', 'D', 'G')
  G2_path = os.path.join(wc_dir, 'A', 'D', 'G2')
  iota_path = os.path.join(wc_dir, 'iota')
  iota2_path = os.path.join(wc_dir, 'A', 'B', 'E', 'iota2')

  # Remove 'alpha'. When it is committed, it will be marked DELETED.
  svntest.actions.run_and_verify_svn(None, [], 'rm', alpha_path)

  # Tweak 'beta' in order to bump its revision to ensure the replacement
  # gets the new revision (2), not the value from the parent (1).
  svntest.actions.run_and_verify_svn(None, [],
                                     'ps', 'random-prop', 'propvalue',
                                     beta_path)

  expected_output = svntest.wc.State(wc_dir, {
    'A/B/E/alpha' : Item(verb='Deleting'),
    'A/B/E/beta' : Item(verb='Sending'),
    })
  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
  expected_status.remove('A/B/E/alpha')
  expected_status.tweak('A/B/E/beta', wc_rev=2)
  svntest.actions.run_and_verify_commit(wc_dir,
                                        expected_output, expected_status,
                                        [],
                                        alpha_path, beta_path)

  # bump 'G' and iota another revision (3) for later testing
  svntest.actions.run_and_verify_svn(None, [],
                                     'ps', 'random-prop', 'propvalue',
                                     G_path, iota_path)

  expected_output = svntest.wc.State(wc_dir, {
    'A/D/G' : Item(verb='Sending'),
    'iota' : Item(verb='Sending'),
    })
  expected_status.tweak('A/D/G', 'iota', wc_rev=3)
  svntest.actions.run_and_verify_commit(wc_dir,
                                        expected_output, expected_status,
                                        [],
                                        G_path, iota_path)

  # Add a file over the DELETED 'alpha'. It should be schedule-add.
  open(alpha_path, 'w').write('New alpha contents\n')

  # Delete 'beta', then add a file over it. Should be schedule-replace.
  svntest.actions.run_and_verify_svn(None, [], 'rm', beta_path)
  open(beta_path, 'w').write('New beta contents\n')

  # Plain old add. Should have revision == 0.
  open(added_path, 'w').write('Added file contents\n')

  svntest.actions.run_and_verify_svn(None, [], 'add',
                                     alpha_path, beta_path, added_path)

  svntest.actions.run_and_verify_svn(None, [], 'cp',
                                     iota_path, iota2_path)

  entries = svntest.main.run_entriesdump(os.path.join(wc_dir, 'A', 'B', 'E'))
  check_names(entries, 'alpha', 'beta', 'added', 'iota2')

  # plain add should be rev=0. over a DELETED, should be SCHEDULE_ADD
  validate(entries['alpha'], schedule=SCHEDULE_ADD, revision=0, copied=False)

  # should pick up the BASE node's revision
  validate(entries['beta'], schedule=SCHEDULE_REPLACE, revision=2,
           copied=False)

  # plain add should be rev=0
  validate(entries['added'], schedule=SCHEDULE_ADD, revision=0, copied=False)

  # copyfrom_rev is (3), but we inherit the rev from the parent (1)
  validate(entries['iota2'], schedule=SCHEDULE_ADD, revision=1, copied=True,
           copyfrom_rev=3)

  svntest.actions.run_and_verify_svn(None, [], 'cp', G_path, G2_path)

  entries = svntest.main.run_entriesdump(G2_path)
  check_names(entries, 'pi', 'rho', 'tau')

  # added, but revision should match the copyfrom_rev (directories don't
  # inherit a revision like iota2 did above)
  validate(entries[''], schedule=SCHEDULE_ADD, copied=True, revision=3)

  # children should be SCHEDULE_NORMAL. still rev=1 cuz of mixed-rev source.
  validate(entries['pi'], schedule=SCHEDULE_NORMAL, copied=True, revision=1)


def obstructed_entries(sbox):
  "validate entries when obstructions exist"

  sbox.build()
  wc_dir = sbox.wc_dir

  D_path = os.path.join(wc_dir, 'A', 'D')
  H_path = os.path.join(wc_dir, 'A', 'D', 'H')

  # blast a directory. its revision should become SVN_INVALID_REVNUM.
  entries = svntest.main.run_entriesdump(D_path)
  check_names(entries, 'H')
  validate(entries['H'], revision=1)

  svntest.main.safe_rmtree(H_path)

  entries = svntest.main.run_entriesdump(D_path)
  check_names(entries, 'H')

  # Data is not missing in single-db
  validate(entries['H'], revision=1)

  ### need to get svn_wc__db_read_info() to generate obstructed_add


def deletion_details(sbox):
  "various details about deleted nodes"

  sbox.build()
  wc_dir = sbox.wc_dir

  iota_path = os.path.join(wc_dir, 'iota')
  D_path = os.path.join(wc_dir, 'A', 'D')
  D2_path = os.path.join(wc_dir, 'A', 'D2')
  D2_G_path = os.path.join(wc_dir, 'A', 'D2', 'G')
  E_path = os.path.join(wc_dir, 'A', 'B', 'E')
  H_path = os.path.join(wc_dir, 'A', 'D', 'H')

  entries = svntest.main.run_entriesdump(wc_dir)
  check_names(entries, 'iota')
  iota = entries['iota']

  # blast iota, then verify the now-deleted entry still contains much of
  # the same information.
  svntest.actions.run_and_verify_svn(None, [], 'rm', iota_path)
  entries = svntest.main.run_entriesdump(wc_dir)
  check_names(entries, 'iota')
  validate(entries['iota'], revision=iota.revision,
           cmt_rev=iota.cmt_rev, cmt_author=iota.cmt_author)

  # even deleted nodes have a URL
  validate(entries['iota'], url='%s/iota' % sbox.repo_url)

  svntest.actions.run_and_verify_svn(None, [], 'cp', D_path, D2_path)
  svntest.actions.run_and_verify_svn(None, [], 'rm', D2_G_path)

  entries = svntest.main.run_entriesdump(D2_path)
  check_names(entries, 'gamma', 'G')

  # copied nodes have URLs
  validate(entries['gamma'], url='%s/A/D2/gamma' % sbox.repo_url,
           copied=True, schedule=SCHEDULE_NORMAL)

  entries = svntest.main.run_entriesdump(D2_G_path)
  check_names(entries, 'pi')

  # oh, and this sucker has a URL, too
  validate(entries['pi'], url='%s/A/D2/G/pi' % sbox.repo_url,
           copied=True, schedule=SCHEDULE_DELETE)

  ### hmm. somehow, subtrees can be *added* over a *deleted* subtree.
  ### maybe this can happen via 'svn merge' ? ... the operations below
  ### will fail because E_path is scheduled for deletion, disallowing
  ### any new node to sit on top of it. (tho it *should* allow it...)

  ### for now... this test case is done. just return
  return

  svntest.actions.run_and_verify_svn(None, [], 'rm', E_path)
  svntest.actions.run_and_verify_svn(None, [], 'cp', H_path, E_path)

  entries = svntest.main.run_entriesdump(E_path)
  check_names(entries, 'chi', 'omega', 'psi', 'alpha', 'beta')

  validate(entries['alpha'], schedule=SCHEDULE_DELETE)
  validate(entries['chi'], schedule=SCHEDULE_NORMAL, copied=True)



########################################################################
# Run the tests

# list all tests here, starting with None:
test_list = [ None,
              basic_entries,
              obstructed_entries,
              deletion_details,
             ]


if __name__ == '__main__':
  svntest.main.run_tests(test_list)
  # NOTREACHED