/*************************GO-LICENSE-START*********************************
* Copyright 2014 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.
*************************GO-LICENSE-END***********************************/
package com.thoughtworks.go.server.service.lookups;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import com.googlecode.junit.ext.JunitExtRunner;
import com.googlecode.junit.ext.RunIf;
import com.thoughtworks.go.helper.CommandSnippetMother;
import com.thoughtworks.go.junitext.EnhancedOSChecker;
import com.thoughtworks.go.serverhealth.HealthStateLevel;
import com.thoughtworks.go.serverhealth.ServerHealthService;
import com.thoughtworks.go.serverhealth.ServerHealthState;
import com.thoughtworks.go.util.FileUtil;
import com.thoughtworks.go.util.SystemEnvironment;
import com.thoughtworks.go.util.TempFiles;
import com.thoughtworks.go.util.TestFileUtil;
import org.apache.commons.io.FileUtils;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import static com.thoughtworks.go.junitext.EnhancedOSChecker.DO_NOT_RUN_ON;
import static com.thoughtworks.go.junitext.EnhancedOSChecker.WINDOWS;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@RunWith(JunitExtRunner.class)
public class CommandRepositoryDirectoryWalkerTest {
TempFiles tempFiles = new TempFiles();
private File hiddenFolder;
private File visibleReadableFolder;
private File folderWithNoReadAccess;
private ServerHealthService serverHealthService;
private CommandRepositoryDirectoryWalker walker;
private File xmlFile;
private File docFile;
private File sampleDir;
@Before
public void setUp() throws IOException {
hiddenFolder = tempFiles.mkdir(".hidden");
visibleReadableFolder = tempFiles.mkdir("visible");
folderWithNoReadAccess = tempFiles.mkdir("noReadAccess");
xmlFile = tempFiles.createFile("foo.xml");
docFile = tempFiles.createFile("foo.doc");
serverHealthService = mock(ServerHealthService.class);
walker = new CommandRepositoryDirectoryWalker(serverHealthService, mock(SystemEnvironment.class));
sampleDir = tempFiles.mkdir("sampleDir");
}
@After
public void tearDown() {
tempFiles.cleanUp();
sampleDir.delete();
}
@Test
public void shouldIgnoreAllUnixStyleHiddenDirectoriesAndShouldNotUpdateServerHealth() throws IOException {
assertThat(walker.handleDirectory(hiddenFolder, 0, new ArrayList()), is(false));
verify(serverHealthService, never()).update(Matchers.<ServerHealthState>anyObject());
}
@Test
public void shouldProcessADirectoryWithReadAccess() throws IOException {
assertThat(walker.handleDirectory(visibleReadableFolder, 0, new ArrayList()), is(true));
}
@Test
@RunIf(value = EnhancedOSChecker.class, arguments = {DO_NOT_RUN_ON, WINDOWS})
public void shouldIgnoreFoldersForWhichUsersDoNotHaveReadAccess() throws IOException {
folderWithNoReadAccess.setReadable(false);
assertThat(walker.handleDirectory(folderWithNoReadAccess, 0, new ArrayList()), is(false));
}
@Test
public void shouldProcessXmlFiles() throws IOException {
FileUtil.writeContentToFile(CommandSnippetMother.validXMLSnippetContentForCommand("MsBuild"), xmlFile);
ArrayList results = new ArrayList();
walker.handleFile(xmlFile, 0, results);
assertThat(results.size(), is(1));
CommandSnippet snippet = (CommandSnippet) results.get(0);
Assert.assertThat(snippet.getBaseFileName(), is("foo"));
Assert.assertThat(snippet.getCommandName(), is("MsBuild"));
Assert.assertThat(snippet.getArguments(), is(Arrays.asList("pack", "component.nuspec")));
}
@Test
public void shouldProcessXmlFilesInsideCommandRepo() throws Exception {
File command_repo = tempFiles.createUniqueFolder("command-repo");
File windows = TestFileUtil.createTestFolder(command_repo, "windows");
FileUtil.writeContentToFile(CommandSnippetMother.validXMLSnippetContentForCommand("MsBuild"), new File(windows, "msbuild.xml"));
CommandSnippets results = walker.getAllCommandSnippets(command_repo.getPath());
String expectedRelativePath = "/windows/msbuild.xml".replace('/', File.separatorChar);
assertThat(results,
is(new CommandSnippets(Arrays.asList(new CommandSnippet("MsBuild", Arrays.asList("pack", "component.nuspec"), new EmptySnippetComment(), "msbuild", expectedRelativePath)))));
}
@Test
public void shouldIgnoreNonXmlFiles() throws IOException {
ArrayList results = new ArrayList();
walker.handleFile(docFile, 0, results);
assertThat(results.isEmpty(), is(true));
}
@Test
@RunIf(value = EnhancedOSChecker.class, arguments = {DO_NOT_RUN_ON, WINDOWS})
public void shouldUpdateServerHealthServiceIfTheCommandRepositoryDirectoryIsUnReadable() throws IOException {
sampleDir.setReadable(false);
walker.getAllCommandSnippets(sampleDir.getPath());
verify(serverHealthService).update(serverHealthWarningMessageWhichContains("Failed to access command repository located in Go Server Directory at " + sampleDir.getPath() +
". The directory does not exist or Go does not have sufficient permissions to access it."));
}
@Test
@RunIf(value = EnhancedOSChecker.class, arguments = {DO_NOT_RUN_ON, WINDOWS})
public void shouldUpdateServerHealthServiceIfTheCommandRepositoryDirectoryIsNotExecutable() throws IOException {
sampleDir.setReadable(true);
sampleDir.setExecutable(false);
walker.getAllCommandSnippets(sampleDir.getPath());
verify(serverHealthService).update(serverHealthWarningMessageWhichContains("Failed to access command repository located in Go Server Directory at " + sampleDir.getPath() +
". The directory does not exist or Go does not have sufficient permissions to access it."));
}
@Test
@RunIf(value = EnhancedOSChecker.class, arguments = {DO_NOT_RUN_ON, WINDOWS})
public void shouldUpdateServerHealthServiceIfTheCommandRepositoryDirectoryDoesNotExist() throws IOException {
File nonExistentDirectory = new File("dirDoesNotExist");
walker.getAllCommandSnippets(nonExistentDirectory.getPath());
verify(serverHealthService).update(serverHealthWarningMessageWhichContains("Failed to access command repository located in Go Server Directory at " + nonExistentDirectory.getPath() +
". The directory does not exist or Go does not have sufficient permissions to access it."));
}
@Test
@RunIf(value = EnhancedOSChecker.class, arguments = {DO_NOT_RUN_ON, WINDOWS})
public void shouldUpdateServerHealthServiceIfTheCommandRepositoryDirectoryIsUnReadableAndRemoveItOnceItsReadable() throws IOException {
sampleDir.setReadable(false);
walker.getAllCommandSnippets(sampleDir.getPath());
verify(serverHealthService).update(serverHealthWarningMessageWhichContains("Failed to access command repository located in Go Server Directory at " + sampleDir.getPath() +
". The directory does not exist or Go does not have sufficient permissions to access it."));
sampleDir.setReadable(true);
walker.getAllCommandSnippets(sampleDir.getPath());
verify(serverHealthService, times(2)).update(serverHealthMessageWhichSaysItsOk());
verifyNoMoreInteractions(serverHealthService);
}
@Test
@RunIf(value = EnhancedOSChecker.class, arguments = {DO_NOT_RUN_ON, WINDOWS})
public void shouldUpdateServerHealthServiceIfACommandSnippetXMLIsUnReadableAndRemoveItOnceItsReadable() throws IOException {
File dirWithUnreadableFile = tempFiles.mkdir("dirWithUnreadableFile");
File unreadableFile = new File(dirWithUnreadableFile, "unreadable.xml");
FileUtils.copyFile(xmlFile, unreadableFile);
unreadableFile.setReadable(false);
walker.getAllCommandSnippets(dirWithUnreadableFile.getPath());
verify(serverHealthService).update(serverHealthWarningMessageWhichContains("Failed to access command snippet XML file located in Go Server Directory at " + unreadableFile.getPath() +
". Go does not have sufficient permissions to access it."));
unreadableFile.setReadable(true);
walker.getAllCommandSnippets(dirWithUnreadableFile.getPath());
verify(serverHealthService, times(2)).update(serverHealthMessageWhichSaysItsOk());
verifyNoMoreInteractions(serverHealthService);
}
@Test
@RunIf(value = EnhancedOSChecker.class, arguments = {DO_NOT_RUN_ON, WINDOWS})
public void shouldUpdateServerHealthServiceIfTheCommandRepositoryDirectoryIsActuallyAFile() throws IOException {
walker.getAllCommandSnippets(xmlFile.getPath());
verify(serverHealthService).update(serverHealthWarningMessageWhichContains("Failed to access command repository located in Go Server Directory at " + xmlFile.getPath() +
". The directory does not exist or Go does not have sufficient permissions to access it."));
}
private ServerHealthState serverHealthMessageWhichSaysItsOk() {
return argThat(new BaseMatcher<ServerHealthState>() {
@Override
public boolean matches(Object o) {
return ((ServerHealthState) o).isRealSuccess();
}
@Override
public void describeTo(Description description) {
description.appendText("Expected success health message.");
}
});
}
private ServerHealthState serverHealthWarningMessageWhichContains(final String expectedPartOfMessage) {
return argThat(new BaseMatcher<ServerHealthState>() {
@Override
public boolean matches(Object o) {
ServerHealthState serverHealthState = (ServerHealthState) o;
String description = serverHealthState.getDescription();
boolean isTheMessageWeHaveBeenWaitingFor = description.contains(expectedPartOfMessage);
if (isTheMessageWeHaveBeenWaitingFor) {
assertThat(serverHealthState.getLogLevel(), is(HealthStateLevel.WARNING));
}
return isTheMessageWeHaveBeenWaitingFor;
}
@Override
public void describeTo(Description description) {
description.appendText("Expected message to contain: " + expectedPartOfMessage);
}
});
}
}