Skip to main content
summaryrefslogtreecommitdiffstats
blob: 975c9adfa2e0621221dd64500b22402fa053511f (plain) (blame)
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
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
package org.eclipse.team.tests.ccvs.core.compatible;
/*
 * (c) Copyright IBM Corp. 2000, 2002.
 * All Rights Reserved.
 */
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.text.ParseException;

import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.team.ccvs.core.*;
import org.eclipse.team.ccvs.core.CVSProviderPlugin;
import org.eclipse.team.ccvs.core.ICVSFolder;
import org.eclipse.team.ccvs.core.ICVSResource;
import org.eclipse.team.internal.ccvs.core.CVSException;
import org.eclipse.team.internal.ccvs.core.client.Session;
import org.eclipse.team.internal.ccvs.core.connection.CVSRepositoryLocation;
import org.eclipse.team.internal.ccvs.core.connection.CVSServerException;
import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
import org.eclipse.team.internal.ccvs.core.resources.ICVSFile;
import org.eclipse.team.internal.ccvs.core.resources.LocalResource;
import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
import org.eclipse.team.internal.ccvs.core.util.EntryFileDateFormat;
import org.eclipse.team.internal.ccvs.core.util.Util;
import org.eclipse.team.tests.ccvs.core.JUnitTestCase;
import org.eclipse.team.tests.ccvs.core.NullOutputStream;


/**
 * This is a TestCase that does provide the possibility
 * to run tests on both the reference reference-client and the
 * client provided by us, and to check on equal results
 * in files and messages to the consol.
 * 
 * No own tests should be placed here, instead you should
 * instanciate this testcase in order to make your test from
 * another suite.
 * The class is final, because you need to be able to open
 * two (or more) different enviorments to test certain things.
 */
public final class SameResultEnv extends JUnitTestCase {
	
	public static final String REFERENCE_CLIENT_WORKSPACE="reference";
	public static final String ECLIPSE_CLIENT_WORKSPACE="eclipse";
	
	private File workspace;
	private File referenceClientRoot;
	private File eclipseClientRoot;
	private boolean ignoreExceptions=false;
	private boolean expectExceptions=false;
	
	private CVSRepositoryLocation referenceClientRepository;
	private CVSRepositoryLocation eclipseClientRepository;
		
	public SameResultEnv(String arg, File workspace) {
		super(arg);
		this.workspace = workspace;
		referenceClientRoot = new File(workspace, REFERENCE_CLIENT_WORKSPACE);
		eclipseClientRoot = new File(workspace, ECLIPSE_CLIENT_WORKSPACE);
		
		try {
			deleteFile(".");
		} catch (CVSException e) {
			fail();
		}
	}
	
	/**
	 * Always to be called in the setUp of the testCase that wants to 
	 * use the same-result Enviorment.
	 */
	public void setUp() throws CVSException {
		// By default, exceptions are not ignored.
		// Specific test cases can choose to ignore exceptions
		ignoreExceptions = false;
		mkdirs(".");
	}
	
	/**
	 * Always to be called in the tearDown of the testCase that wants to 
	 * use the same-result Enviorment.
	 */
	public void tearDown() throws CVSException {
		deleteFile("");
	}
	
	/**
	 * Deletes files on the both of the cvs-servers.
	 */
	public void magicDeleteRemote(String project) throws CVSException {
		magicDeleteProject(CompatibleTestSetup.referenceClientRepository,project);
		magicDeleteProject(CompatibleTestSetup.eclipseClientRepository,project);		
	}
	
	/**
	 * Set up both of the repos on the cvs-server(s) with the standard
	 * file-structure:
	 * project
	 *   a.txt
	 *   f1
	 *     b.txt
	 *     c.txt
	 */
	public void magicSetUpRepo(String project) throws CVSException {
		magicSetUpRepo(project,new String[]{"a.txt","f1/b.txt","f1/c.txt"});
	}
	
	/**
	 * Set up both of the repos on the cvs-server(s) with a filestructre
	 * resulting for your input in the parameter createResources.
	 */
	public void magicSetUpRepo(String project,String[] createResources) throws CVSException {
		
		// This will trigger asynchronizer reload
		// deleteFile(project);
		magicDeleteRemote(project);
		
		createRandomFile(createResources, project);
		execute("import",new String[]{"-m","msg"},new String[]{project,"a","b"},project);
		
		deleteFile(".");
		mkdirs(".");
	}
	
	/**
	 * Give null this gives an empty string-array back, otherwise
	 * the parameter.
	 */
	private static String[] notNull(String[] arg) {
		if (arg == null) {
			return new String[0];
		} else {
			return arg;
		}
	}

	/**
	 * Convienience Method, does the same like:<br>
	 * execute(request,null,localOptions,arguments,rootExtention) 
	 */				
	public void execute(String request, 
						String[] localOptions, 
						String[] arguments,
						String rootExtention) 
						throws CVSException {
		
		execute(request,new String[0],localOptions,arguments,rootExtention);
	}

	/**
	 * Convienience Method, does the same like:<br>
	 * execute(request,null,localOptions,arguments,null) 
	 */		
	public void execute(String request, 
						String[] localOptions, 
						String[] arguments) 
						throws CVSException {

		execute(request,new String[0],localOptions,arguments,"");
	}
	
	/**
	 * Run a command in the two folders of this enviorment. In one folder the
	 * reference-client runs in the the other the eclipse-client. After that
	 * the results on disc are compared (the output of the clients is not
	 * considert for the comparison)
	 */
	public void execute(String request, 
						String[] globalOptions, 
						String[] localOptions, 
						String[] arguments,
						String rootExtention) 
						throws CVSException {
		
		globalOptions = notNull(globalOptions);
		
		String[] gOptions1 = new String[globalOptions.length + 2];
		String[] gOptions2 = new String[globalOptions.length + 2];
		
		System.arraycopy(globalOptions,0,gOptions1,0,globalOptions.length);
		System.arraycopy(globalOptions,0,gOptions2,0,globalOptions.length);
		
		gOptions1[globalOptions.length] = gOptions2[globalOptions.length] = "-d";
		gOptions1[globalOptions.length + 1] = CompatibleTestSetup.REFERENCE_CLIENT_REPOSITORY;
		gOptions2[globalOptions.length + 1] = CompatibleTestSetup.ECLIPSE_CLIENT_REPOSITORY;

		execute(request,gOptions1,gOptions2,localOptions,arguments,rootExtention);
	}
	
	/**
	 * Acctally run the command in both folders. See doc above.
	 */
	private void execute(String request, 
						String[] globalOptions1, 
						String[] globalOptions2, 
						String[] localOptions, 
						String[] arguments,
						String rootExtention) 
						throws CVSException {
		
		assertNotNull(request);
		assertNotNull(globalOptions1);
		assertNotNull(globalOptions);
		
		boolean referenceClientException = false;
		boolean eclipseClientException = false;
		
		localOptions = notNull(localOptions);
		arguments = notNull(arguments);
		if (rootExtention == null || rootExtention.equals(".")) {
			rootExtention = "";
		}
		
		try {
			ReferenceClient.execute(request, 
									globalOptions1, 
									localOptions, 
									arguments,
									new File(referenceClientRoot,rootExtention),
									new NullProgressMonitor(), 
									new PrintStream(new NullOutputStream()));
		} catch (ReferenceException e) {
			referenceClientException = true;			
			if (!ignoreExceptions) {
				throw e;
			}
		}
		
		try {
			execute(request, 
					globalOptions2, 
					localOptions, 
					arguments,
					new File(eclipseClientRoot,rootExtention),
					new NullProgressMonitor(), 
					new PrintStream(new NullOutputStream()));
		} catch (CVSServerException e) {
			eclipseClientException = true;
			if (!ignoreExceptions) {
				throw e;
			}
		}
		if(ignoreExceptions) {
			assertEquals(referenceClientException == true, eclipseClientException == true);
		}
		assertConsistent();
	}

	/**
	 * Checks whether the two directories inside the environment
	 * are equal and therefore the state valid.
	 */
	public void assertConsistent() throws CVSException {
		ICVSFolder referenceFolder = Session.getManagedFolder(referenceClientRoot);
		ICVSFolder eclipseFolder = Session.getManagedFolder(eclipseClientRoot);
		CVSProviderPlugin.getSynchronizer().reload(((LocalResource)referenceFolder).getLocalFile(), new NullProgressMonitor());
		CVSProviderPlugin.getSynchronizer().reload(((LocalResource)eclipseFolder).getLocalFile(), new NullProgressMonitor());
		assertEquals(referenceFolder,eclipseFolder);
	}
	
	/**
	 * Create a file with random-content in both, the reference client and 
	 * the eclipse-client.
	 * 
	 * @param relativeFileName is the relative path as allways in the 
	           class used for access
	 */
	public void createRandomFile(String relativeFileName) throws CVSException {
		
		String randomContent;
		
		randomContent = createRandomContent();
		try {
			writeToFile(relativeFileName,new String[]{randomContent});
		} catch (IOException e) {
			throw new CVSException("IOException while creating random content",e);
		}
	}

	/**
	 * Call createRandomFile for every element of the array
	 * 
	 * @see SameResultEnv#createRandomFile(String)
	 */
	public void createRandomFile(String[] relativeFileNames, String rootExtention) throws CVSException {
		
		if (rootExtention == null || rootExtention.equals(".")) {
			rootExtention = "";
		}
		
		if (!rootExtention.equals("") && !rootExtention.startsWith("/")) {
			rootExtention = rootExtention + "/";
		}
		
		for (int i=0; i<relativeFileNames.length; i++) {
			createRandomFile(rootExtention + relativeFileNames[i]);
		}
	}
	
	/**
	 * Read from the file (check that we have acctually got the same
	 * content in both versions
	 */
	public String[] readFromFile(String relativeFileName) throws IOException {
		
		String[] content1;
		String[] content2;
		
		content1 = super.readFromFile(new File(referenceClientRoot,relativeFileName));
		content2 = super.readFromFile(new File(eclipseClientRoot,relativeFileName));
		
		assertEqualsArrays(content1,content2);
		
		return content1;
	}
	
	/**
	 * Delete files from both of the directories
	 */
	public void deleteFile(String relativeFileName) throws CVSException {
		
		if (".".equals(relativeFileName)) {
			relativeFileName = "";
		}
		
		File file1 = new File(referenceClientRoot, relativeFileName);
		File file2 = new File(eclipseClientRoot, relativeFileName);
		
		assertEquals(file1.exists(),file2.exists());
		
		if (!file1.exists()) {
			return;
		}
		
		// Call the "clean-up-delete" that cares about deleting the
		// cache
		if (file1.isDirectory()) {
			delete(Session.getManagedFolder(file1));
			delete(Session.getManagedFolder(file2));
		} else {
			delete(Session.getManagedFile(file1));
			delete(Session.getManagedFile(file2));
		}
	}
	
	/**
	 * Create a folder and all the subfolders 
	 * in both of the directories
	 */
	public void mkdirs(String folderName) {	
		(new File(referenceClientRoot,folderName)).mkdirs();
		(new File(eclipseClientRoot,folderName)).mkdirs();
	}
	
	/**
	 * Append a String to an file (acctally to both of the files, that are going
	 * to have the same content)
	 */
	public void appendToFile(String relativeFileName, String txt) throws IOException {	
		File file1 = new File(referenceClientRoot,relativeFileName);
		File file2 = new File(eclipseClientRoot,relativeFileName);

		// Wait a second so that the timestamp will change for sure
		waitMsec(2000);
		
		appendToFile(file1,txt);
		appendToFile(file2,txt);
	}
	
	/**
	 * Write to the file (acctally to both of the files, that are going
	 * to have the same content)
	 * Does create the underlying folder if they do not exist (the version
	 * of JUnitTest does currently not)
	 */
	public void writeToFile(String relativeFileName, String[] content) throws IOException {	
		
		File file1 = new File(referenceClientRoot,relativeFileName);
		File file2 = new File(eclipseClientRoot,relativeFileName);
		
		file1.getParentFile().mkdirs();
		file2.getParentFile().mkdirs();

		writeToFile(file1,content);
		writeToFile(file2,content);
	}		

	/**
	 * Deep compare of two ManagedResources (most likly folders).
	 * Passwords are ignored.
	 * 
	 * @param ignoreTimestamp if true timestamps of
	           files are ignored for the comparison
	 */
	public static void assertEquals(ICVSResource mResource1, 
										ICVSResource mResource2) 
										throws CVSException {
		
		assertEquals(mResource1.isFolder(), mResource2.isFolder());
		assertEquals(mResource1.isManaged() , mResource2.isManaged());
		assertEquals(mResource1.exists(), mResource2.exists());
		
		if (!mResource1.exists()) {
			return;
		}
		
		if (mResource1.isFolder()) {
			assertEquals((ICVSFolder)mResource1,(ICVSFolder)mResource2);
		} else {
			assertEquals((ICVSFile)mResource1,(ICVSFile)mResource2);
		}	
	}	
	
	/**
	 * Assert that two CVSFile's are equal by comparing the content
	 * and the metainformation out of the ResourceSync.
	 */
	private static void assertEquals(ICVSFile mFile1, ICVSFile mFile2) throws CVSException {
		
		// Check the permissions on disk
		assertEquals(getFile(mFile1).canWrite(), getFile(mFile2).canWrite());
					
		// Compare the content of the files
		try {
			InputStream in1 = new FileInputStream(getFile(mFile1)); 
			InputStream in2 = new FileInputStream(getFile(mFile2)); 
			byte[] buffer1 = new byte[(int)mFile1.getSize()];
			byte[] buffer2 = new byte[(int)mFile2.getSize()];
			// This is not the right way to do it, because the Stream
			// may read less than the whoole file
			in1.read(buffer1);
			in2.read(buffer2);
			in1.close();
			in2.close();
			assertEquals(buffer1.length,buffer2.length);
			assertEquals(new String(buffer1),new String(buffer2));
		} catch (IOException e) {
			throw new CVSException("Error in TestCase");
		}

		// We can not do the ceck, because the reference client does
		// check out dirty files ?!?
		// assertEquals(mFile1.isDirty(),mFile2.isDirty());
		
		assertEquals(mFile1.getSyncInfo() == null,mFile2.getSyncInfo() == null);
		if (mFile1.getSyncInfo() == null) {
			return;
		}
		
		ResourceSyncInfo info1 = mFile1.getSyncInfo();
		ResourceSyncInfo info2 = mFile2.getSyncInfo();
		
		assertEquals(info1.getKeywordMode(), info2.getKeywordMode());
		assertEquals(info1.getTag(), info2.getTag());
		assertEquals(info1.getName(), info2.getName());
		assertEquals(info1.getRevision(), info2.getRevision());
		
		// Ensure that timestamps are written in ISO C asctime() format and if timestamp
		// has a conflict marker then both should have the marker. Also ensure that timestamps
		// are written using same timezone.
		assertTimestampEquals(info1.getTimeStamp(), info2.getTimeStamp());
		
		// We are not able to check for the permissions, as the reference-client doesn't save them
	}

	private static void assertTimestampEquals(String timestamp1, String timestamp2) {
		try {			
			EntryFileDateFormat timestampFormat = new EntryFileDateFormat();
			boolean merge1 = timestamp1.indexOf(ResourceSyncInfo.RESULT_OF_MERGE_CONFLICT) != -1;
			boolean merge2 = timestamp2.indexOf(ResourceSyncInfo.RESULT_OF_MERGE_CONFLICT) != -1;
			boolean dummy1 = timestamp1.indexOf(ResourceSyncInfo.DUMMY_TIMESTAMP) != -1;
			boolean dummy2 = timestamp2.indexOf(ResourceSyncInfo.DUMMY_TIMESTAMP) != -1;
			assertEquals("both timestamps should show same conflict state", merge1, merge2);
			assertEquals("both timestamps should show same dummy state", dummy1, dummy2);
			if(!merge1 && !dummy1) {
				long time1 = timestampFormat.toDate(timestamp1).getTime();
				long time2 = timestampFormat.toDate(timestamp2).getTime();
				/* timestamp tests don't seem to work on some systems.
				long difference = Math.abs(time1 - time2);
				assertTrue("timestamps should be in same timezone:" + timestamp1 + ":" + timestamp2, difference < (5*60*1000)); // 5 minutes
				*/
			}
		} catch(ParseException e) {			
			fail("timestamps in CVS/Entry file are not in ISO C asctime format:" + timestamp1 + ":" + timestamp2);
		}
	}
	
	/**
	 * Assert that two CVSFile's are equal. First the 
	 * metainformation out of the FolderSync for this 
	 * folder is compared, then the amount of children is 
	 * checked and finally the recussion is started to
	 * compare the children of this folder.
	 */
	private static void assertEquals(ICVSFolder mFolder1, 
										ICVSFolder mFolder2) 
										throws CVSException {

		assertEquals(mFolder1.isCVSFolder(),mFolder2.isCVSFolder());
		
		if (mFolder1.isCVSFolder()) {
			String root1 = Util.removePassword(mFolder1.getFolderSyncInfo().getRoot());
			String root2 = Util.removePassword(mFolder2.getFolderSyncInfo().getRoot());
			root1 = root1.substring(0,root1.lastIndexOf("@"));
			root2 = root2.substring(0,root2.lastIndexOf("@"));
			assertEquals(root1,root2);
			
			assertEquals(mFolder1.getFolderSyncInfo().getRepository(),mFolder2.getFolderSyncInfo().getRepository());
			assertEquals(mFolder1.getFolderSyncInfo().getIsStatic(),mFolder2.getFolderSyncInfo().getIsStatic());
			assertEquals(mFolder1.getFolderSyncInfo().getTag(),mFolder2.getFolderSyncInfo().getTag());
		}
		
		ICVSResource[] resourceList1;
		ICVSResource[] resourceList2;
		boolean fileFound;
		
		resourceList1 = mFolder1.getFiles();
		resourceList2 = mFolder2.getFiles();
		assertEquals(resourceList1.length,resourceList2.length);
		for (int i=0; i<resourceList1.length; i++) {
			fileFound = false;
			for (int j=0; j<resourceList2.length; j++) {
				if (resourceList1[i].getName().equals(resourceList2[j].getName())) {
					assertEquals(resourceList1[i], resourceList2[j]);
					fileFound = true;
					break;
				}
			}
			assertTrue("File " + resourceList1[i].getName() + " not found in the list",fileFound);
		}
		
		resourceList1 = mFolder1.getFolders();
		resourceList2 = mFolder2.getFolders();
		assertEquals(resourceList1.length,resourceList2.length);
		for (int i=0; i<resourceList1.length; i++) {
			fileFound = false;
			for (int j=0; j<resourceList2.length; j++) {
				if (resourceList1[i].getName().equals(resourceList2[j].getName())) {
					assertEquals(resourceList1[i], resourceList2[j]);
					fileFound = true;
					break;
				}
			}
			assertTrue("Folder " + resourceList1[i].getName() + " not found in the list",fileFound);
		}
	}
	
	/**
	 * Sets whether Exceptions that are thrown in the execution of both of the clients are
	 * catched or thrown to the upper level. If the exceptions are catched the result of the 
	 * reference-client and this client are compared as if the execution succseded.
	 */
	public void setIgnoreExceptions(boolean ignoreExceptions) {
		this.ignoreExceptions = ignoreExceptions;
	}
}

Back to the top