/********************************************************************************
* CruiseControl, a Continuous Integration Toolkit
* Copyright (c) 2001-2003, ThoughtWorks, Inc.
* 200 E. Randolph, 25th Floor
* Chicago, IL 60601 USA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* + Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
********************************************************************************/
package net.sourceforge.cruisecontrol.publishers;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.transform.TransformerFactory;
import junit.framework.TestCase;
import net.sourceforge.cruisecontrol.CruiseControlException;
import net.sourceforge.cruisecontrol.testutil.TestUtil.FilesToDelete;
import net.sourceforge.cruisecontrol.util.IO;
import net.sourceforge.cruisecontrol.util.XMLLogHelper;
import net.sourceforge.cruisecontrol.util.Util;
/**
* Unit tests for
* {@link net.sourceforge.cruisecontrol.publishers.WeblogPublisher WeblogPublisher}.
*
* @author Lasse Koskela
*/
public class WeblogPublisherTest extends TestCase {
private static int counter = 1;
private File xslDir;
private String[] xslFiles = { "header.xsl", "maven.xsl", "checkstyle.xsl",
"compile.xsl", "javadoc.xsl", "unittests.xsl", "modifications.xsl",
"distributables.xsl" };
private WeblogPublisher publisher;
private final FilesToDelete filesToDelete = new FilesToDelete();
protected void setUp() throws Exception {
publisher = new WeblogPublisher();
publisher.setBuildResultsURL("http://localhost:8080/cc");
publisher.setLogDir(createTempDir().getAbsolutePath());
publisher.setUsername("user123");
publisher.setPassword("topsecret");
publisher.setBlogId("myblog");
publisher.setBlogUrl("http://foobar.com/blog/xmlrpc");
xslDir = createTempDir();
for (final String xslFile : xslFiles) {
createTempFile(xslDir, xslFile);
}
publisher.setXSLDir(xslDir.getAbsolutePath());
publisher.setCSS(createTempFile(xslDir, "cc.css").getAbsolutePath());
}
protected void tearDown() {
filesToDelete.delete();
}
public void testUsernameIsRequired() throws Exception {
publisher.validate();
try {
publisher.setUsername(null);
publisher.validate();
fail("Validation should fail when the username is not set");
} catch (CruiseControlException expected) {
assertTrue(expected.getMessage().indexOf("username") != -1);
}
}
public void testPasswordIsRequired() throws Exception {
publisher.validate();
try {
publisher.setPassword(null);
publisher.validate();
fail("Validation should fail when password is not set");
} catch (CruiseControlException expected) {
assertTrue("The error should mention the missing attribute",
expected.getMessage().indexOf("password") != -1);
}
}
public void testBlogIdIsRequired() throws Exception {
publisher.validate();
try {
publisher.setBlogId(null);
publisher.validate();
fail("Validation should fail when blogid is not set");
} catch (CruiseControlException expected) {
assertTrue("The error should mention the missing attribute",
expected.getMessage().indexOf("blogid") != -1);
}
}
public void testBlogUrlIsRequired() throws Exception {
publisher.validate();
try {
publisher.setBlogUrl(null);
publisher.validate();
fail("Validation should fail when blogurl is not set");
} catch (CruiseControlException expected) {
assertTrue("The error should mention the missing attribute",
expected.getMessage().indexOf("blogurl") != -1);
}
}
public void testBlogUrlMustBeValidUrl() throws Exception {
publisher.validate();
String invalidUrl = "htt//thisisnotavalid.url";
try {
publisher.setBlogUrl(invalidUrl);
publisher.validate();
fail("Validation should fail when blogurl is not a valid URL");
} catch (CruiseControlException expected) {
assertTrue("The error should mention the invalid URL", expected
.getMessage().indexOf(invalidUrl) != -1);
}
}
public void testBuildResultsUrlIsNotRequired() throws Exception {
publisher.validate();
try {
publisher.setBuildResultsURL(null);
publisher.validate();
} catch (CruiseControlException expected) {
fail("Validation should fail if buildresultsurl is not set"
+ "since it's not a required attribute.");
}
}
public void testBuildResultsUrlMustBeValidUrl() throws Exception {
publisher.validate();
String invalidUrl = "htt//thisisnotavalid.url";
try {
publisher.setBuildResultsURL(invalidUrl);
publisher.validate();
fail("Validation should fail when buildresultsurl is not a valid URL");
} catch (CruiseControlException expected) {
assertTrue("The error should mention the invalid URL", expected
.getMessage().indexOf(invalidUrl) != -1);
}
}
public void testXslDirIsRequired() throws Exception {
publisher.validate();
try {
publisher.setXSLDir("doesnotexist");
publisher.validate();
fail("Validation should fail when the XSL directory doesn't exist");
} catch (CruiseControlException expected) {
assertTrue("The error should mention the missing directory's name",
expected.getMessage().indexOf("doesnotexist") != -1);
}
}
public void testXslFileMustExist() throws Exception {
publisher.validate();
try {
publisher.setXSLFile("doesnotexist");
publisher.validate();
fail("Validation should fail when the XSL file doesn't exist");
} catch (CruiseControlException expected) {
assertTrue("The error should mention the missing file's name",
expected.getMessage().indexOf("doesnotexist") != -1);
}
}
public void testCssFileIsRequired() throws Exception {
publisher.validate();
try {
publisher.setCSS("doesnotexist");
publisher.validate();
fail("Validation should fail when the CSS file doesn't exist");
} catch (CruiseControlException expected) {
assertTrue("The error should mention the missing file's name",
expected.getMessage().indexOf("doesnotexist") != -1);
}
}
public void testXslFilesAreRequired() throws Exception {
for (final String xslFileName : xslFiles) {
publisher.validate();
try {
new File(xslDir, xslFileName).delete();
publisher.validate();
fail("Validation should fail if " + xslFileName + " is missing");
} catch (CruiseControlException expected) {
assertTrue("The error message should include the "
+ "name of the missing file", expected.getMessage()
.indexOf(xslFileName) != -1);
}
createTempFile(xslDir, xslFileName);
}
}
public void testBuildResultsUrlIsConstructedCorrectly() throws Exception {
String serverURL = "http://localhost:8080/cc";
String expected = serverURL + "?log=LOGFILE";
publisher.setBuildResultsURL(serverURL);
assertEquals(expected, publisher.createBuildResultsUrl("LOGFILE.XML"));
}
public void testBuildResultsUrlIsConstructedCorrectlyWithQuestionMark() {
String serverURL = "http://myserver/context/servlet?key=value";
String expected = serverURL + "&log=LOGFILE";
publisher.setBuildResultsURL(serverURL);
assertEquals(expected, publisher.createBuildResultsUrl("LOGFILE.XML"));
}
public void testBuildResultsLinkIsConstructedCorrectly() throws Exception {
String url = publisher.createBuildResultsUrl("TEST.XML");
String link = "<a href=\"" + url + "\">" + url + "</a>";
assertTrue(publisher.createLinkLine("TEST.XML").indexOf(link) != -1);
}
public void testDefaultLogDirectory() throws Exception {
String expected = "logs" + File.separator + "myproject";
assertEquals(expected, publisher.getDefaultLogDir("myproject"));
}
public void testCreateSubjectForSuccessfulBuild() throws Exception {
boolean isSuccessful = true;
boolean isFix = false;
String subject = publisher.createSubject("myproject", "mylabel",
isSuccessful, isFix);
assertEquals("myproject mylabel - Build Successful", subject);
}
public void testCreateSubjectForFailedBuild() throws Exception {
boolean isSuccessful = false;
boolean isFix = false;
String subject = publisher.createSubject("myproject", "mylabel",
isSuccessful, isFix);
assertEquals("myproject - Build Failed", subject);
}
public void testCreateSubjectForFixedBuild() throws Exception {
boolean isSuccessful = true;
boolean isFix = true;
String subject = publisher.createSubject("myproject", "mylabel",
isSuccessful, isFix);
assertEquals("myproject mylabel - Build Fixed", subject);
}
public void testCreateSubjectUsesPrefixIfSpecified() throws Exception {
boolean isSuccessful = true;
boolean isFix = false;
publisher.setSubjectPrefix("[CC]");
String subject = publisher.createSubject("myproject", "mylabel",
isSuccessful, isFix);
assertEquals("[CC] myproject mylabel - Build Successful", subject);
}
private static class MockXMLLogHelper extends XMLLogHelper {
private boolean isBuildSuccessful = true; // 'true' by default
private boolean wasPreviousBuildSuccessful = true; // 'true' by default
private boolean isBuildNecessary = true; // 'true' by default
public MockXMLLogHelper() {
super(null);
}
public boolean isBuildSuccessful() {
return isBuildSuccessful;
}
public void setBuildSuccessful(boolean b) {
this.isBuildSuccessful = b;
}
public boolean wasPreviousBuildSuccessful() {
return wasPreviousBuildSuccessful;
}
public void setPreviousBuildSuccessful(boolean b) {
this.wasPreviousBuildSuccessful = b;
}
public boolean isBuildNecessary() {
return isBuildNecessary;
}
public void setBuildNecessary(boolean b) {
this.isBuildNecessary = b;
}
}
public void testShouldSendWhenBuildIsSuccessful() throws Exception {
MockXMLLogHelper logHelper = new MockXMLLogHelper();
logHelper.setPreviousBuildSuccessful(true);
logHelper.setBuildSuccessful(true);
publisher.setReportSuccess("always");
assertTrue(publisher.shouldSend(logHelper));
publisher.setReportSuccess("fixes");
assertFalse(publisher.shouldSend(logHelper));
publisher.setReportSuccess("never");
assertFalse(publisher.shouldSend(logHelper));
}
public void testShouldSendWhenBuildIsFixed() throws Exception {
MockXMLLogHelper logHelper = new MockXMLLogHelper();
logHelper.setPreviousBuildSuccessful(false);
logHelper.setBuildSuccessful(true);
publisher.setReportSuccess("always");
assertTrue(publisher.shouldSend(logHelper));
publisher.setReportSuccess("fixes");
assertTrue(publisher.shouldSend(logHelper));
publisher.setReportSuccess("never");
assertFalse(publisher.shouldSend(logHelper));
}
public void testShouldSendWhenBuildFailed() throws Exception {
MockXMLLogHelper logHelper = new MockXMLLogHelper();
logHelper.setPreviousBuildSuccessful(true);
logHelper.setBuildSuccessful(false);
assertTrue(publisher.shouldSend(logHelper));
}
public void testShouldSendWhenBuildFailedManyTimes() throws Exception {
MockXMLLogHelper logHelper = new MockXMLLogHelper();
logHelper.setPreviousBuildSuccessful(false);
logHelper.setBuildSuccessful(false);
publisher.setSpamWhileBroken(true);
assertTrue(publisher.shouldSend(logHelper));
publisher.setSpamWhileBroken(false);
assertFalse(publisher.shouldSend(logHelper));
}
public void testTransformDelegatesCorrectlyWithSingleStylesheetSpecified()
throws Exception {
final boolean[] delegatedToTheCorrectMethod = { false };
publisher = new WeblogPublisher() {
@Override
void transformWithSingleStylesheet(File xml, StringBuilder buf) {
delegatedToTheCorrectMethod[0] = true;
}
};
publisher.setXSLFile("foo.xsl");
publisher.transform(new File("foo.xml"));
assertTrue(delegatedToTheCorrectMethod[0]);
}
public void testTransformDelegatesCorrectlyWithoutStylesheetSpecified()
throws Exception {
final boolean[] delegatedToTheCorrectMethod = { false };
publisher = new WeblogPublisher() {
@Override
void transformWithMultipleStylesheets(File xml, StringBuilder buf) {
delegatedToTheCorrectMethod[0] = true;
}
};
publisher.transform(new File("foo.xml"));
assertTrue(delegatedToTheCorrectMethod[0]);
}
//appendTransform(inFile, xsl, messageBuffer, tFactory);
public void testAllStylesheetsAreUsedInTransformation() throws Exception {
final List<String> xslFilesUsed = new ArrayList<String>();
publisher = new WeblogPublisher() {
@Override
void appendTransform(File xml, File xsl, StringBuilder buf,
TransformerFactory tf) {
xslFilesUsed.add(xsl.getName());
}
};
publisher.setXSLDir("foo");
publisher.transform(new File("foo.xml"));
for (int i = 0; i < publisher.getXslFileNames().length; i++) {
assertTrue("File " + publisher.getXslFileNames()[i]
+ " was not used for transformation", xslFilesUsed
.contains(publisher.getXslFileNames()[i]));
}
}
public void testTheAppendTransformMethodWorksInGeneral() throws Exception {
File xml = createTempXmlFile();
File xsl = createTempXslFile();
StringBuilder buf = new StringBuilder();
TransformerFactory tfactory = TransformerFactory.newInstance();
publisher.appendTransform(xml, xsl, buf, tfactory);
assertEquals("Testing", buf.toString());
}
private File createTempXslFile() throws IOException, CruiseControlException {
File f = createTempFile();
StringBuilder buf = new StringBuilder();
buf.append("<?xml version='1.0'?>").append('\n');
buf.append("<xsl:stylesheet");
buf.append(" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"");
buf.append(" version=\"1.0\">").append('\n');
buf.append("<xsl:output method=\"text\"/>").append('\n');
buf.append("<xsl:template match=\"/\">");
buf.append("<xsl:value-of select=\"just\"/>");
buf.append("</xsl:template>").append('\n');
buf.append("</xsl:stylesheet>");
IO.write(f, buf.toString());
filesToDelete.add(f);
return f;
}
private File createTempXmlFile() throws CruiseControlException, IOException {
File f = createTempFile();
IO.write(f, "<?xml version='1.0'?><just>Testing</just>");
filesToDelete.add(f);
return f;
}
private File createTempFile() throws IOException {
File tempFile = File.createTempFile("WeblogPublisherTest", ".tmp");
tempFile.deleteOnExit();
filesToDelete.add(tempFile);
return tempFile;
}
private File createTempFile(File parent, String name) throws CruiseControlException {
File tempFile = new File(parent, name);
tempFile.deleteOnExit();
IO.write(tempFile, "");
filesToDelete.add(tempFile);
return tempFile;
}
private File createTempDir() {
File tempDir = new File(System.getProperty("java.io.tmpdir"));
tempDir = new File(tempDir, "tempdir_" + (counter++));
Util.doMkDirs(tempDir);
tempDir.deleteOnExit();
filesToDelete.add(tempDir);
return tempDir;
}
}