- when updating, don't delete files with local modifications
[opensuse:osc.git] / tests.py
1 #!/usr/bin/python
2
3 import os
4 import sys
5 import time
6 import re
7 import unittest
8 import shutil
9 from textwrap import dedent
10
11 from osc import commandline
12
13 chdir = os.chdir
14 mkdir = os.mkdir
15
16 # here, all tests will happen... 
17 BASEDIR = os.path.join(os.getcwd(), 't')
18
19 PRJ = 'home:poeml'
20 PAC = 'test'
21 TESTPACDIR = os.path.join(PRJ, PAC)
22
23
24 def remove_revid(s):
25     return re.sub('revision \d*', 'revision XX', s)
26
27
28 def checkout_and_clean(self):
29     """check out the package and delete all files
30     leave behind the empty package dir"""
31     runosc('co %s %s' % (PRJ, PAC))
32     chdir(TESTPACDIR)
33
34     files, err = runosc('ls %s %s' %(PRJ, PAC))
35     files = files.strip().split('\n')
36     if files != ['']:
37         for file in files:
38             runosc('rm %s' % file)
39         runosc('ci')
40
41
42 class TestOsc(unittest.TestCase):
43     
44     def setUp(self):
45
46         if not os.path.isabs(BASEDIR):
47             sys.exit('BASEDIR must be absolute')
48
49         shutil.rmtree(BASEDIR, ignore_errors=True)
50         mkdir(BASEDIR)
51         chdir(BASEDIR)
52
53
54
55     #####################################################################
56
57     def testUsermeta(self):
58         expect = """<person>
59   <login>poeml</login>
60   <email>poeml@suse.de</email>
61   <realname>Dr. Peter Poeml</realname>
62   <watchlist>
63     <project name="server:mail"/>
64     <project name="frox"/>
65     <project name="home:cthiel1"/>
66     <project name="server:php"/>
67     <project name="Apache"/>
68     <project name="server:httpd-trunk"/>
69     <project name="server:isc-dhcp"/>
70     <project name="Subversion"/>
71     <project name="Tidy"/>
72     <project name="validators"/>
73     <project name="zsh"/>
74     <project name="home:poeml"/>
75     <project name="Apache:Modules"/>
76   </watchlist>
77 </person>
78
79 """
80
81         self.out, self.err = runosc('usermeta poeml')
82         self.assertEqual(self.err, '')
83         self.assertEqual(self.out, expect)
84
85
86     #####################################################################
87
88     def testLs(self):
89         self.out, self.err = runosc('ls')
90         self.assertEqual(self.err, '')
91         self.assert_('Apache' in self.out)
92         self.assert_(PRJ in self.out)
93
94
95     def testLsPrj(self):
96         self.out, self.err = runosc('ls Apache')
97         self.assertEqual(self.err, '')
98         self.assert_('apache2' in self.out)
99
100
101     def testLsPac(self):
102         self.out, self.err = runosc('ls Apache apache2')
103         self.assertEqual(self.err, '')
104         self.assert_('favicon.ico' in self.out)
105
106     #####################################################################
107
108     def testMetaPrj(self):
109         self.out, self.err = runosc('meta Apache')
110         self.assertEqual(self.err, '')
111         self.assert_('<project name="Apache">' in self.out)
112
113
114     def testMetaPac(self):
115         self.out, self.err = runosc('meta Apache apache2')
116         self.assertEqual(self.err, '')
117         self.assert_('<package project="Apache" name="apache2">' in self.out)
118
119
120     #####################################################################
121
122     def testPlatforms(self):
123         self.out, self.err = runosc('platforms')
124         self.assertEqual(self.err, '')
125         self.assert_('Factory/standard' in self.out)
126         self.assert_('SUSE:SL-10.1/standard' in self.out)
127
128
129     def testPlatformsPac(self):
130         self.out, self.err = runosc('platforms Apache')
131         self.assertEqual(self.err, '')
132         self.assert_('openSUSE_Factory' in self.out)
133
134
135     #####################################################################
136
137     def testMerge(self):
138
139         wc1 = os.path.join(BASEDIR, TESTPACDIR)
140         wc2 = os.path.join(BASEDIR, 'otherwc')
141
142         checkout_and_clean(self)
143
144         # from wc1, create and check in a file
145         open('foo', 'w').write(dedent("""\
146             ein
147             blaues
148             Haus
149             """))
150         runosc('add foo')
151         runosc('ci')
152
153
154         # create second working copy, and do a local modification
155         mkdir(wc2)
156         chdir(wc2)
157         runosc('init %s %s' % (PRJ, PAC))
158         runosc('up')
159         open('foo', 'w').write(dedent("""\
160             kein
161             blaues
162             Haus
163             """))
164
165         self.out, self.err = runosc('st')
166         self.assertEqual(self.err, '')
167         self.assertEqual(self.out, 'M    foo\n')
168
169         # from wc1, commit a change 
170         chdir(wc1)
171         open('foo', 'a').write("""geht aus""")
172         runosc('ci')
173
174         # in wc2, update, and the change should be merged in
175         chdir(wc2)
176         self.out, self.err = runosc('up')
177         self.assertEqual(self.err, '')
178         self.assertEqual(remove_revid(self.out), 'G    foo\nAt revision XX.\n')
179
180         self.out, self.err = runosc('st')
181         self.assertEqual(self.err, '')
182         self.assertEqual(self.out, 'M    foo\n')
183
184         # successful merge is one thing, but checking the local modification 
185         # makes sure that the store copy has been updated to the upstream revision
186         self.out, self.err = runosc('diff')
187         self.assertEqual(self.err, '')
188         expected = dedent("""\
189             Index: foo
190             ===================================================================
191             --- foo     (revision XX) 
192             +++ foo     (working copy) 
193             @@ -1,4 +1,4 @@
194             -ein
195             +kein
196              blaues
197              Haus
198              geht aus
199             """)
200         self.assertEqual(remove_revid(self.out), expected)
201
202
203
204     #####################################################################
205
206     def testUpdateLocalMod(self):
207
208         wc1 = os.path.join(BASEDIR, TESTPACDIR)
209         wc2 = os.path.join(BASEDIR, 'otherwc')
210
211         checkout_and_clean(self)
212
213         # in wc1, create and check in two files
214         touch('f1')
215         touch('f2')
216         runosc('add f1 f2')
217         runosc('ci')
218
219
220         # create second working copy, and do a local modification
221         mkdir(wc2)
222         chdir(wc2)
223         runosc('init %s %s' % (PRJ, PAC))
224         runosc('up')
225         open('f2', 'w').write('foo')
226
227         # from wc1, delete the files
228         chdir(wc1)
229         runosc('rm f1 f2')
230         runosc('ci')
231
232         # in wc2, update
233         # f1 should be deleted
234         # f2 should be kept
235         chdir(wc2)
236         self.out, self.err = runosc('up')
237         self.assertEqual(self.err, '')
238         self.assertEqual(remove_revid(self.out), 'D    f1\nD    f2\nAt revision XX.\n')
239
240         self.out, self.err = runosc('st')
241         self.assertEqual(self.err, '')
242         self.assertEqual(self.out, '?    f2\n')
243
244
245     #####################################################################
246
247     def testCoPrj(self):
248         self.out, self.err = runosc('co %s' % PRJ)
249         self.assertEqual(self.err, '')
250         self.assert_('A    %s/%s' %(PRJ, PAC) in self.out)
251
252
253     def testCoPac(self):
254         # check out package dir
255         self.out, self.err = runosc('co %s %s' % (PRJ, PAC))
256         self.assertEqual(self.err, '')
257         self.assert_('A    %s/%s' %(PRJ, PAC) in self.out)
258
259     def testCoPacAndDoStuff(self):
260         checkout_and_clean(self)
261
262         # check in a file
263         # give an error if it doesn't exist
264         self.out, self.err = runosc('add foo1')
265         self.assertEqual(self.err, '')
266         self.assertEqual(self.out, 'file \'foo1\' does not exist\n')
267
268         touch('foo1')
269         self.out, self.err = runosc('add foo1')
270         self.assertEqual(self.err, '')
271         self.assertEqual(self.out, 'A    foo1\n')
272
273         self.out, self.err = runosc('ci')
274         self.assertEqual(self.err, '')
275         self.assertEqual(self.out, """Sending        foo1
276 Transmitting file data .
277 """)
278
279
280         # delete a file
281         self.out, self.err = runosc('rm foo1')
282         self.assertEqual(self.err, '')
283         self.assertEqual(self.out, 'D    foo1\n')
284
285         self.out, self.err = runosc('ci')
286         self.assertEqual(self.err, '')
287         self.assertEqual(self.out, """Deleting       foo1
288 Transmitting file data 
289 """)
290
291
292         # test 'status'
293         touch('onlyinwc')
294         self.out, self.err = runosc('st')
295         self.assertEqual(self.err, '')
296         self.assertEqual(self.out, '?    onlyinwc\n')
297
298         touch('foo2')
299         self.out, self.err = runosc('add foo2')
300         self.out, self.err = runosc('st')
301         self.assertEqual(self.err, '')
302         self.assertEqual(self.out, '?    onlyinwc\nA    foo2\n')
303
304         # status with an absolute directory as argument
305         self.out, self.err = runosc('st %s' % os.getcwd())
306         self.assertEqual(self.err, '')
307         self.assertEqual(self.out, '?    %s/onlyinwc\nA    %s/foo2\n' % (os.getcwd(), os.getcwd()))
308
309         # status with an absolute directory as argument
310         self.out, self.err = runosc('st %s' % os.getcwd())
311         self.assertEqual(self.err, '')
312         self.assertEqual(self.out, '?    %s/onlyinwc\nA    %s/foo2\n' % (os.getcwd(), os.getcwd()))
313
314         # status with a single file as argument
315         reldir = os.path.basename(os.getcwd())
316         self.out, self.err = runosc('st foo2')
317         self.assertEqual(self.err, '')
318         self.assertEqual(self.out, 'A    foo2\n')
319
320         # check in a single argument
321         self.out, self.err = runosc('ci foo2')
322         self.assertEqual(self.err, '')
323         self.assertEqual(self.out, """Sending        foo2
324 Transmitting file data .
325 """)
326
327         # clean up
328         self.out, self.err = runosc('st')
329         self.assertEqual(self.err, '')
330         self.assertEqual(self.out, '?    onlyinwc\n')
331         os.unlink('onlyinwc')
332
333
334         # test 'addremove'
335         touch('bar1')
336         os.unlink('foo2')
337         self.out, self.err = runosc('addremove')
338         self.assertEqual(self.err, '')
339         self.assertEqual(self.out, 'D    foo2\nA    bar1\n')
340         self.out, self.err = runosc('ci')
341         self.assertEqual(self.err, '')
342         self.assertEqual(self.out, """Sending        bar1
343 Deleting       foo2
344 Transmitting file data .
345 """)
346
347
348
349
350
351
352
353
354 #####################################################################
355
356
357 def runosc(argstring):
358     #time.sleep(1) # don't stress the server
359
360     # we test the osc in this directory, not a system one
361     return runcmd(os.path.join(startdir, 'osc-wrapper.py'), argstring)
362
363
364 def runcmd(cmd, argstring):
365     child_stdin, child_stdout, child_stderr = os.popen3(cmd + ' ' + argstring)
366     return child_stdout.read(), child_stderr.read()
367
368
369 def touch(filename):
370     open(filename, 'w').close();
371
372
373 if __name__ == '__main__':
374
375     #unittest.main()
376     startdir = os.getcwd()
377     suite = unittest.makeSuite(TestOsc)
378     unittest.TextTestRunner(verbosity=2).run(suite)