001: /********************************************************************************
002: * CruiseControl, a Continuous Integration Toolkit
003: * Copyright (c) 2001-2003, ThoughtWorks, Inc.
004: * 200 E. Randolph, 25th Floor
005: * Chicago, IL 60601 USA
006: * All rights reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * + Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * + Redistributions in binary form must reproduce the above
016: * copyright notice, this list of conditions and the following
017: * disclaimer in the documentation and/or other materials provided
018: * with the distribution.
019: *
020: * + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
021: * names of its contributors may be used to endorse or promote
022: * products derived from this software without specific prior
023: * written permission.
024: *
025: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
026: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
027: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
028: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
029: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
030: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
031: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
032: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
033: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
034: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
035: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
036: ********************************************************************************/package net.sourceforge.cruisecontrol.sourcecontrols;
037:
038: import java.io.BufferedInputStream;
039: import java.io.IOException;
040: import java.io.InputStream;
041: import java.text.DateFormat;
042: import java.text.SimpleDateFormat;
043: import java.util.Calendar;
044: import java.util.Date;
045: import java.util.Iterator;
046: import java.util.List;
047:
048: import junit.framework.TestCase;
049: import net.sourceforge.cruisecontrol.CruiseControlException;
050: import net.sourceforge.cruisecontrol.Modification;
051: import net.sourceforge.cruisecontrol.util.Commandline;
052: import net.sourceforge.cruisecontrol.util.StreamPumper;
053:
054: import org.apache.oro.text.regex.MalformedPatternException;
055: import org.apache.oro.text.regex.Perl5Compiler;
056: import org.apache.oro.text.regex.Perl5Matcher;
057:
058: /**
059: * @author Robert Watkins
060: * @author Jason Yip, jcyip@thoughtworks.com
061: * @author Patrick Conant Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
062: */
063: public class P4Test extends TestCase {
064:
065: /**
066: * Mocks a P4 class by returning a specific P4 server-time offset
067: */
068: static class MockP4 extends P4 {
069: private final long timeOffset;
070:
071: public MockP4(long offset) {
072: this .timeOffset = offset;
073: }
074:
075: protected long calculateServerTimeOffset() {
076: return timeOffset;
077: }
078: }
079:
080: public void testGetQuoteChar() {
081: boolean windows = true;
082: String quoteChar = P4.getQuoteChar(windows);
083: assertEquals("\"", quoteChar);
084:
085: quoteChar = P4.getQuoteChar(!windows);
086: assertEquals("'", quoteChar);
087: }
088:
089: public void testValidate() {
090: P4 p4 = new P4();
091:
092: try {
093: p4.validate();
094: fail("P4 should throw exceptions when required attributes are not set.");
095: } catch (CruiseControlException expected) {
096: }
097:
098: p4.setUser("user");
099: p4.setPort("port");
100: p4.setClient("client");
101: p4.setView("view");
102:
103: try {
104: p4.validate();
105: } catch (CruiseControlException e) {
106: fail("P4 should not throw exceptions when required attributes are set.");
107: }
108: }
109:
110: public void testBuildChangesCommand() throws Exception {
111: P4 p4 = new MockP4(0);
112: p4.setView("foo");
113:
114: DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
115: Date date = dateFormat.parse("12/30/2004");
116: Commandline cmdLine = p4.buildChangesCommand(date, date, true);
117:
118: String[] args = cmdLine.getCommandline();
119: StringBuffer cmd = new StringBuffer();
120: cmd.append(args[0]);
121: for (int i = 1; i < args.length; i++) {
122: cmd.append(" " + args[i]);
123: }
124:
125: assertEquals(
126: "p4 -s changes -s submitted foo@2004/12/30:00:00:00,@2004/12/30:00:00:00",
127: cmd.toString());
128: }
129:
130: public void testBuildChangesCommand_Unix() throws Exception {
131: P4 p4 = new MockP4(0);
132: p4.setView("foo");
133:
134: DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
135: Date date = dateFormat.parse("12/30/2004");
136: Commandline cmdLine = p4.buildChangesCommand(date, date, false);
137:
138: String[] args = cmdLine.getCommandline();
139: StringBuffer cmd = new StringBuffer();
140: cmd.append(args[0]);
141: for (int i = 1; i < args.length; i++) {
142: cmd.append(" " + args[i]);
143: }
144:
145: assertEquals(
146: "p4 -s changes -s submitted foo@2004/12/30:00:00:00,@2004/12/30:00:00:00",
147: cmd.toString());
148: }
149:
150: public void testBuildInfoCommand() {
151: P4 p4 = new P4();
152: Commandline command = p4.buildInfoCommand();
153: assertEquals("p4 info", command.toString());
154:
155: p4.setPort("1234");
156: command = p4.buildInfoCommand();
157: assertEquals("p4 -p 1234 info", command.toString());
158: }
159:
160: private InputStream loadTestLog(String name) {
161: InputStream testStream = getClass().getResourceAsStream(name);
162: assertNotNull("failed to load resource " + name + " in class "
163: + getClass().getName(), testStream);
164: return testStream;
165: }
166:
167: public void testParseChangelists() throws IOException {
168: BufferedInputStream input = new BufferedInputStream(
169: loadTestLog("p4_changes.txt"));
170:
171: P4 p4 = new P4();
172: String[] changelists = p4.parseChangelistNumbers(input);
173: input.close();
174: assertNotNull("No changelists returned", changelists);
175: assertEquals("Returned wrong number of changelists", 4,
176: changelists.length);
177: String[] expectedChangelists = new String[] { "14", "12", "11" };
178: for (int i = 0; i < expectedChangelists.length; i++) {
179: assertEquals("Returned wrong changelist number",
180: expectedChangelists[i], changelists[i]);
181: }
182: }
183:
184: public void testParseChangeDescriptions() throws Exception {
185: BufferedInputStream input = new BufferedInputStream(
186: loadTestLog("p4_describe.txt"));
187:
188: P4 p4 = new P4();
189: p4.setCorrectForServerTime(false);
190: List changelists = p4.parseChangeDescriptions(input);
191: input.close();
192: assertEquals("Returned wrong number of changelists", 3,
193: changelists.size());
194:
195: assertEquals(
196: "Wrong description",
197: "Fixed support for db2. This is now the default database shipped"
198: + " with HPDoc. For now that is. Still has to be tested on"
199: + " PostgreSQL to see that it is still working there. The sea rch"
200: + " mechanism is also upgraded to now ALMOST support AND/OR"
201: + " expressions. There are thoughtsabout this, but not yet implemented (however prepared for)",
202: ((Modification) changelists.get(0)).comment);
203: checkModifications((Modification) changelists.get(0),
204: "//depot/hpdoc/main", 33);
205:
206: assertEquals(
207: "Wrong description",
208: "ok, tests running smooth. Checking in mostly for backup. Not"
209: + " finished yet. CIMD is comming on great and I'm starting to see a framework developing.",
210: ((Modification) changelists.get(1)).comment);
211: checkModifications((Modification) changelists.get(1),
212: "//depot/k4j/main", 65);
213: assertEquals("Wrong description",
214: "Testing ..\nSome ..\nLinebreaks.",
215: ((Modification) changelists.get(2)).comment);
216: checkModifications((Modification) changelists.get(2), "", 0);
217: // XMLOutputter outputter = new XMLOutputter();
218: // for (Iterator iterator = changelistElements.iterator();
219: // iterator.hasNext();) {
220: // Element element = (Element) iterator.next();
221: // Use next lines if you want to see the output of the run. This is what
222: // is inserted into the logs.
223: // outputter.setNewlines(true);
224: // outputter.setIndent(true);
225: // System.out.println(outputter.outputString(element));
226: // }
227: }
228:
229: /**
230: * Check that all modifications match expected values.
231: *
232: * @param modification
233: * The modification to be checked
234: * @param depotPrefix
235: * The prefix all filenames are expected to start with.
236: * @param modCount
237: * The expected number of files changes in this modification.
238: */
239: public void checkModifications(Modification modification,
240: String depotPrefix, int modCount)
241: throws MalformedPatternException {
242: List changeList = modification.files;
243: assertEquals("Wrong number of entries", modCount, changeList
244: .size());
245: for (Iterator i = changeList.iterator(); i.hasNext();) {
246: Modification.ModifiedFile file = (Modification.ModifiedFile) i
247: .next();
248: assertTrue("Filename doesn't start with prefix "
249: + depotPrefix, file.fileName
250: .startsWith(depotPrefix));
251: assertEquals("Filename has # at bad index", -1,
252: file.fileName.indexOf("#"));
253: assertTrue("Revision doesn't match regexp ^\\d+$: "
254: + file.revision, matches(file.revision, "^\\d+$"));
255: assertTrue("Unknown action type: " + file.action, matches(
256: file.action, "(edit|add)"));
257: }
258: }
259:
260: public void testParseInfoResponse() throws IOException {
261: BufferedInputStream input = new BufferedInputStream(
262: loadTestLog("p4_info.txt"));
263:
264: Calendar cal = Calendar.getInstance();
265: // this date is encoded in p4_info.txt. Note month is indexed from 0
266: cal.set(2005, 6, 29, 20, 39, 06);
267: long p4ServerTime = cal.getTime().getTime();
268: long ccServerTime = System.currentTimeMillis();
269: long expectedOffset = p4ServerTime - ccServerTime;
270:
271: P4.ServerInfoConsumer serverInfo = new P4.ServerInfoConsumer();
272: new StreamPumper(input, serverInfo).run();
273: long offset = serverInfo.getOffset();
274:
275: // Need to accept some difference in the expected offset and the actual
276: // offset, because the test takes some time to run. To be safe, we'll
277: // allow up to 1 minute of variability in the offset value.
278: long maxOffset = 1000 * 60;
279: long offsetDifference = Math.abs(offset - expectedOffset);
280:
281: assertTrue(
282: "Server time offset wasn't calculated accurately. Expected "
283: + expectedOffset + " but got " + offset
284: + ". Maximum allowed"
285: + "difference in these values is " + maxOffset
286: + ". P4 server time (from test input) is "
287: + p4ServerTime + "; CC server time is "
288: + ccServerTime, offsetDifference < maxOffset);
289: }
290:
291: public boolean matches(String str, String pattern)
292: throws MalformedPatternException {
293: return new Perl5Matcher().matches(str, new Perl5Compiler()
294: .compile(pattern));
295: }
296:
297: // public void testGetModifications() throws Exception {
298: //
299: // // REAL TEST IF YOU NEED IT
300: // P4 p4 = new P4();
301: // p4.setView("//depot/...");
302: // List changelists = p4.getModifications(new Date(0), new Date(), 0);
303: // assertEquals("Returned wrong number of changelists", 3,
304: // changelists.size());
305: //
306: // }
307:
308: public static void main(String[] args) {
309: junit.textui.TestRunner.run(P4Test.class);
310: }
311:
312: }
|