@@ -0,0 +1,117 @@ | |||
/* | |||
* Copyright (C) 2009-2014 SonarSource SA | |||
* All rights reserved | |||
* mailto:contact AT sonarsource DOT com | |||
*/ | |||
package qualitygate; | |||
import com.sonar.orchestrator.Orchestrator; | |||
import com.sonar.orchestrator.build.SonarRunner; | |||
import com.sonar.orchestrator.selenium.Selenese; | |||
import com.sonar.orchestrator.util.NetworkUtils; | |||
import java.util.Iterator; | |||
import javax.mail.internet.MimeMessage; | |||
import org.junit.Before; | |||
import org.junit.ClassRule; | |||
import org.junit.Test; | |||
import org.sonar.wsclient.Sonar; | |||
import org.sonar.wsclient.qualitygate.NewCondition; | |||
import org.sonar.wsclient.qualitygate.QualityGate; | |||
import org.sonar.wsclient.qualitygate.QualityGateClient; | |||
import org.sonar.wsclient.services.Measure; | |||
import org.sonar.wsclient.services.PropertyUpdateQuery; | |||
import org.sonar.wsclient.services.Resource; | |||
import org.sonar.wsclient.services.ResourceQuery; | |||
import org.subethamail.wiser.Wiser; | |||
import org.subethamail.wiser.WiserMessage; | |||
import util.ItUtils; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static util.ItUtils.projectDir; | |||
public class QualityGateNotificationTest { | |||
private static final String PROJECT_KEY = "sample"; | |||
@ClassRule | |||
public static Orchestrator orchestrator = Orchestrator.builderEnv() | |||
.addPlugin(ItUtils.xooPlugin()) | |||
// 1 second. Required for notification test. | |||
.setServerProperty("sonar.notifications.delay", "1") | |||
.build(); | |||
@Before | |||
public void cleanUp() throws Exception { | |||
orchestrator.resetData(); | |||
} | |||
@Test | |||
public void status_on_metric_variation_and_send_notifications() throws Exception { | |||
Wiser smtpServer = new Wiser(NetworkUtils.getNextAvailablePort()); | |||
try { | |||
// Configure SMTP | |||
smtpServer.start(); | |||
Sonar wsClient = orchestrator.getServer().getAdminWsClient(); | |||
wsClient.update(new PropertyUpdateQuery("email.smtp_host.secured", "localhost")); | |||
wsClient.update(new PropertyUpdateQuery("email.smtp_port.secured", Integer.toString(smtpServer.getServer().getPort()))); | |||
// Create user, who will receive notifications for new violations | |||
orchestrator.getServer().adminWsClient().post("api/users/create", "login", "tester", "name", "Tester", "email", "tester@example.org", "password", "tester"); | |||
Selenese selenese = Selenese | |||
.builder() | |||
.setHtmlTestsInClasspath("notifications", | |||
"/selenium/qualitygate/notifications/email_configuration.html", | |||
"/selenium/qualitygate/notifications/activate_notification_channels.html").build(); | |||
orchestrator.executeSelenese(selenese); | |||
// Create quality gate with conditions on variations | |||
QualityGate simple = qgClient().create("SimpleWithDifferential"); | |||
qgClient().setDefault(simple.id()); | |||
qgClient().createCondition(NewCondition.create(simple.id()).metricKey("ncloc").period(1).operator("EQ").warningThreshold("0")); | |||
SonarRunner analysis = SonarRunner.create(projectDir("qualitygate/xoo-sample")); | |||
orchestrator.executeBuild(analysis); | |||
assertThat(fetchGateStatus().getData()).isEqualTo("OK"); | |||
orchestrator.executeBuild(analysis); | |||
assertThat(fetchGateStatus().getData()).isEqualTo("WARN"); | |||
qgClient().unsetDefault(); | |||
qgClient().destroy(simple.id()); | |||
// Wait until all notifications are delivered | |||
Thread.sleep(10000); | |||
Iterator<WiserMessage> emails = smtpServer.getMessages().iterator(); | |||
MimeMessage message = emails.next().getMimeMessage(); | |||
assertThat(message.getHeader("To", null)).isEqualTo("<test@example.org>"); | |||
assertThat((String) message.getContent()).contains("This is a test message from Sonar"); | |||
assertThat(emails.hasNext()).isTrue(); | |||
message = emails.next().getMimeMessage(); | |||
assertThat(message.getHeader("To", null)).isEqualTo("<tester@example.org>"); | |||
assertThat((String) message.getContent()).contains("Quality gate status: Orange (was Green)"); | |||
assertThat((String) message.getContent()).contains("Quality gate threshold: Lines of code variation = 0 since previous analysis"); | |||
assertThat((String) message.getContent()).contains("/dashboard/index/sample"); | |||
assertThat(emails.hasNext()).isFalse(); | |||
} finally { | |||
smtpServer.stop(); | |||
} | |||
} | |||
private Measure fetchGateStatus() { | |||
return fetchResourceWithGateStatus().getMeasure("alert_status"); | |||
} | |||
private Resource fetchResourceWithGateStatus() { | |||
return orchestrator.getServer().getWsClient().find(ResourceQuery.createForMetrics(PROJECT_KEY, "alert_status").setIncludeAlerts(true)); | |||
} | |||
private static QualityGateClient qgClient() { | |||
return orchestrator.getServer().adminWsClient().qualityGateClient(); | |||
} | |||
} |
@@ -3,14 +3,13 @@ | |||
* All rights reserved | |||
* mailto:contact AT sonarsource DOT com | |||
*/ | |||
package org.sonar.it.qualitygate; | |||
package qualitygate; | |||
import com.sonar.orchestrator.Orchestrator; | |||
import com.sonar.orchestrator.build.SonarRunner; | |||
import org.junit.Before; | |||
import org.junit.ClassRule; | |||
import org.junit.Test; | |||
import org.sonar.it.ItUtils; | |||
import org.sonar.wsclient.project.NewProject; | |||
import org.sonar.wsclient.qualitygate.NewCondition; | |||
import org.sonar.wsclient.qualitygate.QualityGate; | |||
@@ -18,9 +17,10 @@ import org.sonar.wsclient.qualitygate.QualityGateClient; | |||
import org.sonar.wsclient.services.Measure; | |||
import org.sonar.wsclient.services.Resource; | |||
import org.sonar.wsclient.services.ResourceQuery; | |||
import util.ItUtils; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.it.ItUtils.projectDir; | |||
import static util.ItUtils.projectDir; | |||
public class QualityGateTest { | |||
@@ -31,6 +31,10 @@ public class QualityGateTest { | |||
@ClassRule | |||
public static Orchestrator orchestrator = Orchestrator.builderEnv() | |||
.addPlugin(ItUtils.xooPlugin()) | |||
// 1 second. Required for notification test. | |||
.setServerProperty("sonar.notifications.delay", "1") | |||
.build(); | |||
@Before | |||
@@ -161,25 +165,6 @@ public class QualityGateTest { | |||
} | |||
} | |||
@Test | |||
public void compute_gate_status_on_metric_variation() { | |||
QualityGate simple = qgClient().create("SimpleWithDifferential"); | |||
qgClient().setDefault(simple.id()); | |||
qgClient().createCondition(NewCondition.create(simple.id()).metricKey("ncloc").period(1).operator("EQ").warningThreshold("0")); | |||
try { | |||
SonarRunner build = SonarRunner.create(projectDir("qualitygate/xoo-sample")); | |||
orchestrator.executeBuild(build); | |||
assertThat(fetchGateStatus().getData()).isEqualTo("OK"); | |||
orchestrator.executeBuild(build); | |||
assertThat(fetchGateStatus().getData()).isEqualTo("WARN"); | |||
} finally { | |||
qgClient().unsetDefault(); | |||
qgClient().destroy(simple.id()); | |||
} | |||
} | |||
private Measure fetchGateStatus() { | |||
return fetchResourceWithGateStatus().getMeasure("alert_status"); | |||
} |
@@ -1,9 +1,8 @@ | |||
/* | |||
package util;/* | |||
* Copyright (C) 2009-2014 SonarSource SA | |||
* All rights reserved | |||
* mailto:contact AT sonarsource DOT com | |||
*/ | |||
package org.sonar.it; | |||
import com.google.common.base.Supplier; | |||
import com.google.common.base.Suppliers; | |||
@@ -50,7 +49,7 @@ public class ItUtils { | |||
/** | |||
* Locate the directory of sample project | |||
* | |||
* | |||
* @param relativePath path related to the directory it/projects, for example "qualitygate/xoo-sample" | |||
*/ | |||
public static File projectDir(String relativePath) { |
@@ -0,0 +1,54 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>create_user_with_email</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<thead> | |||
<tr> | |||
<td rowspan="1" colspan="3">create_user_with_email</td> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sonar/sessions/new</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>login</td> | |||
<td>tester</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>password</td> | |||
<td>tester</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/sonar/account/index</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>check</td> | |||
<td>global_notifs_NewAlerts.EmailNotificationChannel</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>//input[@value='Save changes']</td> | |||
<td></td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -0,0 +1,64 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<title>email_configuration</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<tbody> | |||
<tr> | |||
<td>setTimeout</td> | |||
<td>300000</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/sonar/sessions/new</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/sonar/email_configuration</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>verifyValue</td> | |||
<td>smtp_host</td> | |||
<td>localhost</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>to_address</td> | |||
<td>test@example.org</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>submit_test</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForVisible</td> | |||
<td>info</td> | |||
<td></td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -56,6 +56,9 @@ public class XooRulesDefinition implements RulesDefinition { | |||
.setDebtRemediationFunction(hasTag.debtRemediationFunctions().linear("1min")) | |||
.setEffortToFixDescription("It takes about 1 minute to an experienced software craftsman to remove a line of code"); | |||
repo.createRule(OneIssueOnDirPerFileSensor.RULE_KEY).setName("One Issue On Dir Per File") | |||
.setHtmlDescription("Generate issues on directories"); | |||
NewRule oneIssuePerFile = repo.createRule(OneIssuePerFileSensor.RULE_KEY).setName("One Issue Per File") | |||
.setHtmlDescription("Generate an issue on each file"); | |||
oneIssuePerFile.setDebtSubCharacteristic(RulesDefinition.SubCharacteristics.ARCHITECTURE_CHANGEABILITY) |
@@ -37,7 +37,7 @@ public class XooRulesDefinitionTest { | |||
assertThat(repo).isNotNull(); | |||
assertThat(repo.name()).isEqualTo("Xoo"); | |||
assertThat(repo.language()).isEqualTo("xoo"); | |||
assertThat(repo.rules()).hasSize(7); | |||
assertThat(repo.rules()).hasSize(8); | |||
RulesDefinition.Rule rule = repo.rule(OneIssuePerLineSensor.RULE_KEY); | |||
assertThat(rule.name()).isNotEmpty(); |