/*
* 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.io.File;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import javax.sql.DataSource;
import com.googlecode.junit.ext.RunIf;
import com.thoughtworks.go.config.*;
import com.thoughtworks.go.config.materials.svn.SvnMaterialConfig;
import com.thoughtworks.go.database.Database;
import com.thoughtworks.go.domain.Pipeline;
import com.thoughtworks.go.helper.MaterialConfigsMother;
import com.thoughtworks.go.helper.PipelineConfigMother;
import com.thoughtworks.go.helper.PipelineMother;
import com.thoughtworks.go.i18n.Localizer;
import com.thoughtworks.go.junitext.DatabaseChecker;
import com.thoughtworks.go.junitext.GoJUnitExtSpringRunner;
import com.thoughtworks.go.security.CipherProvider;
import com.thoughtworks.go.server.dao.DatabaseAccessHelper;
import com.thoughtworks.go.server.domain.ServerBackup;
import com.thoughtworks.go.server.domain.Username;
import com.thoughtworks.go.server.persistence.ServerBackupRepository;
import com.thoughtworks.go.server.service.result.HttpLocalizedOperationResult;
import com.thoughtworks.go.server.util.ServerVersion;
import com.thoughtworks.go.service.ConfigRepository;
import com.thoughtworks.go.util.*;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.NameFileFilter;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.h2.tools.Restore;
import org.joda.time.DateTime;
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 static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@RunWith(GoJUnitExtSpringRunner.class)
@ContextConfiguration(locations = {
"classpath:WEB-INF/applicationContext-global.xml",
"classpath:WEB-INF/applicationContext-dataLocalAccess.xml",
"classpath:WEB-INF/applicationContext-acegi-security.xml"
})
public class BackupServiceH2IntegrationTest {
@Autowired
GoConfigService goConfigService;
@Autowired DataSource dataSource;
@Autowired ArtifactsDirHolder artifactsDirHolder;
@Autowired DatabaseAccessHelper dbHelper;
@Autowired
GoConfigDao goConfigDao;
@Autowired
ServerBackupRepository backupInfoRepository;
@Autowired TimeProvider timeProvider;
@Autowired Localizer localizer;
@Autowired SystemEnvironment systemEnvironment;
@Autowired ServerVersion serverVersion;
@Autowired ConfigRepository configRepository;
@Autowired Database databaseStrategy;
@Autowired BackupService backupService;
private GoConfigFileHelper configHelper = new GoConfigFileHelper();
private File backupsDirectory;
private TempFiles tempFiles;
private byte[] originalCipher;
private Username admin;
@Before
public void setUp() throws Exception {
configHelper.onSetUp();
dbHelper.onSetUp();
admin = new Username(new CaseInsensitiveString("admin"));
configHelper.addSecurityWithPasswordFile();
configHelper.addAdmins(CaseInsensitiveString.str(admin.getUsername()));
goConfigDao.forceReload();
backupsDirectory = new File(artifactsDirHolder.getArtifactsDir(), ServerConfig.SERVER_BACKUPS);
FileUtils.deleteQuietly(backupsDirectory);
tempFiles = new TempFiles();
originalCipher = new CipherProvider(systemEnvironment).getKey();
FileUtil.writeContentToFile("invalid crapy config", new File(systemEnvironment.getConfigDir(), "cruise-config.xml"));
FileUtil.writeContentToFile("invalid crapy cipher", new File(systemEnvironment.getConfigDir(), "cipher"));
}
@After
public void tearDown() throws Exception {
tempFiles.cleanUp();
dbHelper.onTearDown();
FileUtil.writeContentToFile(goConfigService.xml(), new File(systemEnvironment.getConfigDir(), "cruise-config.xml"));
FileUtil.writeContentToFile(originalCipher, systemEnvironment.getCipherFile());
configHelper.onTearDown();
FileUtils.deleteQuietly(backupsDirectory);
}
@Test
@RunIf(value = DatabaseChecker.class, arguments = {DatabaseChecker.H2})
public void shouldCreateTheBackupUnderArtifactRepository() {
TimeProvider timeProvider = mock(TimeProvider.class);
DateTime now = new DateTime();
when(timeProvider.currentDateTime()).thenReturn(now);
assertThat(backupsDirectory.exists(), is(false));
HttpLocalizedOperationResult result = new HttpLocalizedOperationResult();
BackupService service = new BackupService(dataSource, artifactsDirHolder, goConfigService, timeProvider, backupInfoRepository, systemEnvironment, serverVersion, configRepository,
databaseStrategy);
service.initialize();
service.startBackup(admin, result);
assertThat(result.isSuccessful(), is(true));
assertThat(backupsDirectory.exists(), is(true));
assertThat(backupsDirectory.isDirectory(), is(true));
File backup = new File(backupsDirectory, BackupService.BACKUP + now.toString("YYYYMMdd-HHmmss"));
assertThat(backup.exists(), is(true));
assertThat(new File(backup, "db.zip").exists(), is(true));
assertEquals(new ServerBackup(backup.getAbsolutePath(), now.toDate(), admin.getUsername().toString()), backupInfoRepository.lastBackup());
}
@Test
@RunIf(value = DatabaseChecker.class, arguments = {DatabaseChecker.H2})
public void shouldPerformDbBackupProperly() throws SQLException {
Pipeline expectedPipeline = saveAPipeline();
HttpLocalizedOperationResult result = new HttpLocalizedOperationResult();
backupService.startBackup(admin, result);
assertThat(result.isSuccessful(), is(true));
assertThat(result.message(localizer), is("Backup completed successfully."));
String location = tempFiles.createUniqueFolder("foo").getAbsolutePath();
Restore.execute(dbZip(), location, "cruise", false);
BasicDataSource source = constructTestDataSource(new File(location));
ResultSet resultSet = source.getConnection().prepareStatement("select * from pipelines where id = " + expectedPipeline.getId()).executeQuery();
int size = 0;
while (resultSet.next()) {
assertThat(resultSet.getString("name"), is(expectedPipeline.getName()));
size++;
}
assertThat(size, is(1));
}
private Pipeline saveAPipeline() {
PipelineConfig pipelineConfig = PipelineConfigMother.pipelineConfig("pipeline", new StageConfig(new CaseInsensitiveString("stage"), new JobConfigs(new JobConfig("job-one"))));
pipelineConfig.materialConfigs().clear();
SvnMaterialConfig onDirOne = MaterialConfigsMother.svnMaterialConfig("google.com", "dirOne", "loser", "boozer", false, "**/*.html");
pipelineConfig.addMaterialConfig(onDirOne);
Pipeline building = PipelineMother.building(pipelineConfig);
return dbHelper.savePipelineWithMaterials(building);
}
private String dbZip() {
return backedUpFile("db.zip").getAbsolutePath();
}
private File backedUpFile(final String filename) {
return new ArrayList<>(FileUtils.listFiles(backupsDirectory, new NameFileFilter(filename), TrueFileFilter.TRUE)).get(0);
}
private BasicDataSource constructTestDataSource(File file) {
BasicDataSource source = new BasicDataSource();
source.setDriverClassName("org.h2.Driver");
source.setUrl("jdbc:h2:" + file.getAbsolutePath() + "/cruise;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
source.setUsername("sa");
source.setPassword("");
source.setMaxActive(32);
source.setMaxIdle(32);
return source;
}
}