/*
* Copyright 2017 ThoughtWorks, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.thoughtworks.go.server.service;
import java.sql.SQLException;
import java.util.ArrayList;
import javax.sql.DataSource;
import com.thoughtworks.go.config.CaseInsensitiveString;
import com.thoughtworks.go.config.GoConfigDao;
import com.thoughtworks.go.domain.JobResult;
import com.thoughtworks.go.domain.NotificationFilter;
import com.thoughtworks.go.domain.Pipeline;
import com.thoughtworks.go.domain.Stage;
import com.thoughtworks.go.domain.StageEvent;
import com.thoughtworks.go.domain.User;
import com.thoughtworks.go.fixture.PipelineWithTwoStages;
import com.thoughtworks.go.server.dao.DatabaseAccessHelper;
import com.thoughtworks.go.server.dao.JobInstanceDao;
import com.thoughtworks.go.server.dao.PipelineDao;
import com.thoughtworks.go.server.dao.StageDao;
import com.thoughtworks.go.server.dao.UserDao;
import com.thoughtworks.go.server.dao.sparql.ShineDao;
import com.thoughtworks.go.server.domain.Username;
import com.thoughtworks.go.server.messaging.InMemoryEmailNotificationTopic;
import com.thoughtworks.go.server.messaging.StageNotificationListener;
import com.thoughtworks.go.server.messaging.StageResultMessage;
import com.thoughtworks.go.server.messaging.StageResultTopic;
import com.thoughtworks.go.server.persistence.MaterialRepository;
import com.thoughtworks.go.server.transaction.TransactionTemplate;
import com.thoughtworks.go.util.GoConfigFileHelper;
import com.thoughtworks.go.util.SystemEnvironment;
import com.thoughtworks.go.util.SystemUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:WEB-INF/applicationContext-global.xml",
"classpath:WEB-INF/applicationContext-dataLocalAccess.xml",
"classpath:WEB-INF/applicationContext-acegi-security.xml"
})
public class StageNotificationServiceIntegrationTest {
@Autowired private PipelineDao pipelineDao;
@Autowired private StageDao stageDao;
@Autowired private JobInstanceDao jobInstanceDao;
@Autowired private DataSource dataSource;
@Autowired private GoConfigDao goConfigDao;
@Autowired private UserDao userDao;
@Autowired private SystemEnvironment systemEnvironment;
@Autowired private DatabaseAccessHelper dbHelper;
@Autowired private MaterialRepository materialRepository;
@Autowired private PipelineService pipelineService;
@Autowired private UserService userService;
@Autowired private GoConfigService goConfigService;
@Autowired private StageResultTopic stageResultTopic;
@Autowired private ServerConfigService serverConfigService;
@Autowired private TransactionTemplate transactionTemplate;
private ShineDao shineDao;
private PipelineWithTwoStages pipelineFixture;
private StageNotificationService stageNotificationService;
private StageNotificationListener stageNotificationListener;
private InMemoryEmailNotificationTopic inMemoryEmailNotificationTopic;
private static GoConfigFileHelper configFileHelper = new GoConfigFileHelper();
private StageService stageService;
@Before
public void setUp() throws Exception {
stageService = mock(StageService.class);
shineDao = mock(ShineDao.class);
stageNotificationService = new StageNotificationService(pipelineService, userService,inMemoryEmailNotificationTopic, systemEnvironment, stageService, serverConfigService, shineDao);
stageNotificationListener = new StageNotificationListener(stageNotificationService, goConfigService, stageResultTopic);
dbHelper.onSetUp();
configFileHelper.onSetUp();
configFileHelper.usingEmptyConfigFileWithLicenseAllowsUnlimitedAgents();
configFileHelper.usingCruiseConfigDao(goConfigDao);
pipelineFixture = new PipelineWithTwoStages(materialRepository, transactionTemplate);
pipelineFixture.usingConfigHelper(configFileHelper).usingDbHelper(dbHelper).onSetUp();
configFileHelper.addSecurityWithAdminConfig();
inMemoryEmailNotificationTopic = new InMemoryEmailNotificationTopic();
stageNotificationService.setEmailNotificationTopic(inMemoryEmailNotificationTopic);
}
@After
public void teardown() throws Exception {
dbHelper.onTearDown();
pipelineFixture.onTearDown();
inMemoryEmailNotificationTopic.reset();
}
private Stage mockStageServiceWithStage(Pipeline pipeline) {
Stage ftStage = pipeline.getStages().byName(pipelineFixture.ftStage);
when(stageService.findStageWithIdentifier(ftStage.getIdentifier())).thenReturn(ftStage);
when(shineDao.failedTestsFor(ftStage.getIdentifier())).thenReturn(new ArrayList<>());
return ftStage;
}
@Test
public void shouldOnlySendEmailToMatchedUser() throws SQLException {
String jezMail = prepareOneMatchedUser();
String chrisMail = prepareOneNotMatchedUser();
Pipeline pipeline = pipelineFixture.createPipelineWithFirstStagePassedAndSecondStageRunning();
Stage ftStage = mockStageServiceWithStage(pipeline);
stageNotificationListener.onMessage(new StageResultMessage(ftStage.getIdentifier(), StageEvent.Passes, Username.BLANK));
String subject = "Stage [" + ftStage.getIdentifier().stageLocator() + "]" + " passed";
assertThat(inMemoryEmailNotificationTopic.getSubject(jezMail), is(subject));
assertThat(inMemoryEmailNotificationTopic.getBody(jezMail), containsString("Sent by Go on behalf of jez"));
assertThat(inMemoryEmailNotificationTopic.emailCount(chrisMail), is(0));
}
private String prepareOneNotMatchedUser() {
String chrisMail = "chris@cruise.com";
User chris = new User("chris", new String[]{"will not be matched"}, chrisMail, true);
chris.addNotificationFilter(new NotificationFilter(pipelineFixture.pipelineName, pipelineFixture.ftStage, StageEvent.All, true));
userDao.saveOrUpdate(chris);
return chrisMail;
}
@Test
public void shouldSendEmailWithCancelledInfo() throws SQLException {
String jezMail = prepareOneMatchedUser();
Pipeline pipeline = pipelineFixture.createPipelineWithFirstStagePassedAndSecondStageRunning();
Stage ftStage = mockStageServiceWithStage(pipeline);
stageNotificationListener.onMessage(
new StageResultMessage(ftStage.getIdentifier(), StageEvent.Passes,
new Username(new CaseInsensitiveString("chris"))));
assertThat(inMemoryEmailNotificationTopic.getBody(jezMail),
containsString("The stage was cancelled by chris."));
}
private String prepareOneMatchedUser() {
return prepareOneMatchedUser(StageEvent.All);
}
private String prepareOneMatchedUser(StageEvent event) {
String jezMail = "jez@cruise.com";
User jez = new User("jez", new String[]{"lgao"}, jezMail, true);
jez.addNotificationFilter(new NotificationFilter(pipelineFixture.pipelineName, pipelineFixture.ftStage, event, true));
userDao.saveOrUpdate(jez);
return jezMail;
}
@Test
public void shouldSendEmailWithLink() throws SQLException {
String jezMail = prepareOneMatchedUser();
Pipeline pipeline = pipelineFixture.createPipelineWithFirstStagePassedAndSecondStageRunning();
Stage ftStage = mockStageServiceWithStage(pipeline);
stageNotificationListener.onMessage(
new StageResultMessage(ftStage.getIdentifier(), StageEvent.Passes, Username.BLANK));
String body = inMemoryEmailNotificationTopic.getBody(jezMail);
String ipAddress = SystemUtil.getFirstLocalNonLoopbackIpAddress();
int port = systemEnvironment.getServerPort();
assertThat(body, containsString(String.format("http://%s:%s/go/pipelines/%s/%s/%s/%s", ipAddress, port,
pipelineFixture.pipelineName, pipeline.getCounter(), pipelineFixture.ftStage, ftStage.getCounter())));
}
@Test
public void shouldSendEmailWhenStageBreaks() throws SQLException {
String jezMail = prepareOneMatchedUser(StageEvent.Breaks);
Pipeline pipeline = pipelineFixture.createdPipelineWithAllStagesPassed();
Stage ftStage = mockStageServiceWithStage(pipeline);
stageNotificationListener.onMessage(
new StageResultMessage(ftStage.getIdentifier(), StageEvent.Breaks, Username.BLANK));
String subject = "Stage [" + ftStage.getIdentifier().stageLocator() + "]" + " is broken";
assertThat(inMemoryEmailNotificationTopic.getSubject(jezMail), is(subject));
assertThat(inMemoryEmailNotificationTopic.getBody(jezMail), containsString("Sent by Go on behalf of jez"));
}
@Test
public void shouldSendEmailWhenStageFixed() throws SQLException {
String jezMail = prepareOneMatchedUser(StageEvent.Fixed);
Pipeline pipeline = pipelineFixture.createdPipelineWithAllStagesCompleted(JobResult.Failed);
Stage ftStage = mockStageServiceWithStage(pipeline);
stageNotificationListener.onMessage(
new StageResultMessage(ftStage.getIdentifier(), StageEvent.Fixed, Username.BLANK));
String subject = "Stage [" + ftStage.getIdentifier().stageLocator() + "]" + " is fixed";
assertThat(inMemoryEmailNotificationTopic.getSubject(jezMail), is(subject));
assertThat(inMemoryEmailNotificationTopic.getBody(jezMail), containsString("Sent by Go on behalf of jez"));
}
@Test
public void shouldSendEmailWhenStageContinueFail() throws SQLException {
String jezMail = prepareOneMatchedUser(StageEvent.Fails);
Pipeline pipeline = pipelineFixture.createdPipelineWithAllStagesCompleted(JobResult.Failed);
Stage ftStage = mockStageServiceWithStage(pipeline);
stageNotificationListener.onMessage(
new StageResultMessage(ftStage.getIdentifier(), StageEvent.Fails, Username.BLANK));
String subject = "Stage [" + ftStage.getIdentifier().stageLocator() + "]" + " failed";
assertThat(inMemoryEmailNotificationTopic.getSubject(jezMail), is(subject));
assertThat(inMemoryEmailNotificationTopic.getBody(jezMail), containsString("Sent by Go on behalf of jez"));
}
}