/* * Copyright 2016 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 com.thoughtworks.go.config.AgentConfig; import com.thoughtworks.go.config.CaseInsensitiveString; import com.thoughtworks.go.domain.AgentInstance; import com.thoughtworks.go.domain.AgentRuntimeStatus; import com.thoughtworks.go.remote.AgentIdentifier; import com.thoughtworks.go.server.domain.AgentInstances; import com.thoughtworks.go.server.domain.Username; import com.thoughtworks.go.server.persistence.AgentDao; import com.thoughtworks.go.server.service.result.HttpOperationResult; import com.thoughtworks.go.server.ui.AgentViewModel; import com.thoughtworks.go.server.ui.AgentsViewModel; import com.thoughtworks.go.server.util.UuidGenerator; import com.thoughtworks.go.serverhealth.HealthStateScope; import com.thoughtworks.go.serverhealth.HealthStateType; import com.thoughtworks.go.serverhealth.ServerHealthService; import com.thoughtworks.go.serverhealth.ServerHealthState; import com.thoughtworks.go.util.LogFixture; import com.thoughtworks.go.util.SystemEnvironment; import com.thoughtworks.go.utils.Timeout; import org.apache.log4j.Level; import org.junit.Before; import org.junit.Test; import java.io.FileOutputStream; import java.io.IOException; import java.util.Arrays; import static com.thoughtworks.go.util.LogFixture.logFixtureFor; import static com.thoughtworks.go.util.SystemUtil.currentWorkingDirectory; import static java.lang.String.format; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; public class AgentServiceTest { private AgentService agentService; private AgentInstances agentInstances; private AgentDao agentDao; private AgentIdentifier agentIdentifier; private UuidGenerator uuidGenerator; private ServerHealthService serverHealthService; @Before public void setUp() { agentInstances = mock(AgentInstances.class); AgentConfig config = new AgentConfig("uuid", "host", "192.168.1.1"); when(agentInstances.findAgentAndRefreshStatus("uuid")).thenReturn(AgentInstance.createFromConfig(config, new SystemEnvironment())); agentDao = mock(AgentDao.class); uuidGenerator = mock(UuidGenerator.class); agentService = new AgentService(mock(AgentConfigService.class), new SystemEnvironment(), agentInstances, mock(EnvironmentConfigService.class), mock(GoConfigService.class), mock(SecurityService.class), agentDao, uuidGenerator, serverHealthService = mock(ServerHealthService.class)); agentIdentifier = config.getAgentIdentifier(); when(agentDao.cookieFor(agentIdentifier)).thenReturn("cookie"); } @Test public void shouldUpdateStatus() throws Exception { AgentRuntimeInfo runtimeInfo = new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "pavanIsGreat", false); when(agentDao.cookieFor(runtimeInfo.getIdentifier())).thenReturn("pavanIsGreat"); agentService.updateRuntimeInfo(runtimeInfo); verify(agentInstances).updateAgentRuntimeInfo(runtimeInfo); } @Test public void shouldThrowExceptionWhenAgentWithNoCookieTriesToUpdateStatus() throws Exception { AgentRuntimeInfo runtimeInfo = new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), null, false); try (LogFixture logFixture = logFixtureFor(AgentService.class, Level.DEBUG)) { try { agentService.updateRuntimeInfo(runtimeInfo); fail("should throw exception when no cookie is set"); } catch (Exception e) { assertThat(e, instanceOf(AgentNoCookieSetException.class)); assertThat(e.getMessage(), is(format("Agent [%s] has no cookie set", runtimeInfo.agentInfoDebugString()))); assertThat(Arrays.asList(logFixture.getMessages()), hasItem(format("Agent [%s] has no cookie set", runtimeInfo.agentInfoDebugString()))); } } } @Test public void shouldThrowExceptionWhenADuplicateAgentTriesToUpdateStatus() throws Exception { AgentRuntimeInfo runtimeInfo = new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), null, false); runtimeInfo.setCookie("invalid_cookie"); AgentInstance original = AgentInstance.createFromLiveAgent(new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), null, false), new SystemEnvironment()); try (LogFixture logFixture = logFixtureFor(AgentService.class, Level.DEBUG)) { try { when(agentService.findAgentAndRefreshStatus(runtimeInfo.getUUId())).thenReturn(original); agentService.updateRuntimeInfo(runtimeInfo); fail("should throw exception when cookie mismatched"); } catch (Exception e) { assertThat(e.getMessage(), is(format("Agent [%s] has invalid cookie", runtimeInfo.agentInfoDebugString()))); assertThat(Arrays.asList(logFixture.getMessages()), hasItem(format("Found agent [%s] with duplicate uuid. Please check the agent installation.", runtimeInfo.agentInfoDebugString()))); verify(serverHealthService).update(ServerHealthState.warning(format("[%s] has duplicate unique identifier which conflicts with [%s]", runtimeInfo.agentInfoForDisplay(), original.agentInfoForDisplay()), "Please check the agent installation. Click <a href='https://docs.gocd.io/current/faq/agent_guid_issue.html' target='_blank'>here</a> for more info.", HealthStateType.duplicateAgent(HealthStateScope.forAgent(runtimeInfo.getCookie())), Timeout.THIRTY_SECONDS)); } } verify(agentInstances).findAgentAndRefreshStatus(runtimeInfo.getUUId()); verifyNoMoreInteractions(agentInstances); } @Test public void shouldAssociateCookieForAnAgent() throws Exception { when(uuidGenerator.randomUuid()).thenReturn("foo"); assertThat(agentService.assignCookie(agentIdentifier), is("foo")); verify(agentDao).associateCookie(eq(agentIdentifier), any(String.class)); } @Test public void shouldUnderstandFilteringAgentListBasedOnUuid() { AgentInstance instance1 = AgentInstance.createFromLiveAgent(AgentRuntimeInfo.fromServer(new AgentConfig("uuid-1", "host-1", "192.168.1.2"), true, "/foo/bar", 100l, "linux", false), new SystemEnvironment()); AgentInstance instance3 = AgentInstance.createFromLiveAgent(AgentRuntimeInfo.fromServer(new AgentConfig("uuid-3", "host-3", "192.168.1.4"), true, "/baz/quux", 300l, "linux", false), new SystemEnvironment()); when(agentInstances.filter(Arrays.asList("uuid-1", "uuid-3"))).thenReturn(Arrays.asList(instance1, instance3)); AgentsViewModel agents = agentService.filter(Arrays.asList("uuid-1", "uuid-3")); AgentViewModel view1 = new AgentViewModel(instance1); AgentViewModel view2 = new AgentViewModel(instance3); assertThat(agents, is(new AgentsViewModel(view1, view2))); verify(agentInstances).filter(Arrays.asList("uuid-1", "uuid-3")); } @Test public void shouldFailWhenDeleteIsNotSuccessful() throws Exception { SecurityService securityService = mock(SecurityService.class); AgentConfigService agentConfigService = mock(AgentConfigService.class); AgentInstance agentInstance = mock(AgentInstance.class); String uuid = "1234"; Username username = new Username(new CaseInsensitiveString("test")); HttpOperationResult operationResult = mock(HttpOperationResult.class); when(securityService.hasOperatePermissionForAgents(username)).thenReturn(true); when(agentInstance.canBeDeleted()).thenReturn(true); doThrow(new RuntimeException()).when(agentConfigService).deleteAgents(username, agentInstance); when(agentInstances.findAgentAndRefreshStatus(uuid)).thenReturn(agentInstance); AgentService agentService = new AgentService(agentConfigService, new SystemEnvironment(), agentInstances, mock(EnvironmentConfigService.class), mock(GoConfigService.class), securityService, agentDao, uuidGenerator, serverHealthService = mock(ServerHealthService.class)); agentService.deleteAgents(username, operationResult, Arrays.asList(uuid)); verify(operationResult).internalServerError(any(String.class), any(HealthStateType.class)); } private void writeToFile(final String fileName) throws IOException { try (FileOutputStream fos = new FileOutputStream(fileName)) { fos.write(fileName.getBytes()); } } }