package org.zalando.stups.fullstop.plugin; import com.google.common.collect.ImmutableMap; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.zalando.stups.fullstop.violation.ViolationBuilder; import org.zalando.stups.fullstop.violation.ViolationSink; import org.zalando.stups.pierone.client.TagSummary; import java.time.ZonedDateTime; import java.util.Optional; import static java.util.Optional.empty; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import static org.zalando.stups.fullstop.violation.ViolationMatchers.hasType; import static org.zalando.stups.fullstop.violation.ViolationType.ARTIFACT_BUILT_FROM_DIRTY_REPOSITORY; import static org.zalando.stups.fullstop.violation.ViolationType.IMAGE_IN_PIERONE_NOT_FOUND; import static org.zalando.stups.fullstop.violation.ViolationType.SCM_SOURCE_JSON_MISSING; import static org.zalando.stups.fullstop.violation.ViolationType.SCM_URL_IS_MISSING_IN_SCM_SOURCE_JSON; public class DockerRegistryPluginTest { /** * <code>git status --porcelain</code> lists all uncommitted or untracked changes. */ private static final String DIRTY_REPO_STATUS = "M pom.xml"; /** * <code>git status --porcelain</code> is empty for clean repositories. (No uncommitted or untracked changes) */ private static final String CLEAN_REPO_STATUS = ""; private DockerRegistryPlugin plugin; private EC2InstanceContextProvider mockContextProvider; private ViolationSink mockViolationSink; private EC2InstanceContext mockContext; @Before public void setUp() throws Exception { mockContextProvider = mock(EC2InstanceContextProvider.class); mockViolationSink = mock(ViolationSink.class); mockContext = mock(EC2InstanceContext.class); when(mockContext.violation()).thenAnswer(new Answer<ViolationBuilder>() { @Override public ViolationBuilder answer(InvocationOnMock invocation) throws Throwable { return new ViolationBuilder(); } }); plugin = new DockerRegistryPlugin(mockContextProvider, mockViolationSink); } @After public void tearDown() throws Exception { verifyNoMoreInteractions(mockContextProvider, mockViolationSink); } @Test public void testSupportsEventName() throws Exception { assertThat(plugin.supportsEventName().test("RunInstances")).isTrue(); assertThat(plugin.supportsEventName().test("StartInstances")).isTrue(); assertThat(plugin.supportsEventName().test("TerminateInstances")).isFalse(); assertThat(plugin.supportsEventName().test("StopInstances")).isFalse(); assertThat(plugin.supportsEventName().test("Foobar")).isFalse(); } @Test public void testProcessIsSkippedOnUnknownRuntime() throws Exception { when(mockContext.getRuntime()).thenReturn(empty()); plugin.process(mockContext); } @Test public void testProcessIsSkippedOnNonDockerRuntime() throws Exception { when(mockContext.getRuntime()).thenReturn(Optional.of("rkt")); plugin.process(mockContext); } @Test public void testProcessIsSkippedOnMissingSource() throws Exception { when(mockContext.getRuntime()).thenReturn(Optional.of("Docker")); when(mockContext.getSource()).thenReturn(empty()); plugin.process(mockContext); } @Test public void testProcessThrowsViolationAndSkipsOnMissingPieroneTag() throws Exception { when(mockContext.getRuntime()).thenReturn(Optional.of("Docker")); when(mockContext.getSource()).thenReturn(Optional.of("pierone.example.org/stups/foo:bar1")); when(mockContext.getPieroneTag()).thenReturn(empty()); plugin.process(mockContext); verify(mockViolationSink).put(argThat(hasType(IMAGE_IN_PIERONE_NOT_FOUND))); } @Test public void testProcessThrowsViolationAndSkipsOnMissingScmSource() throws Exception { when(mockContext.getRuntime()).thenReturn(Optional.of("Docker")); when(mockContext.getSource()).thenReturn(Optional.of("pierone.example.org/stups/foo:bar1")); when(mockContext.getPieroneTag()).thenReturn(Optional.of(new TagSummary("bar1", ZonedDateTime.now(), "test_user"))); when(mockContext.getScmSource()).thenReturn(empty()); plugin.process(mockContext); verify(mockViolationSink).put(argThat(hasType(SCM_SOURCE_JSON_MISSING))); } @Test public void testProcessThrowsViolationsOnBadScmSourceJson() throws Exception { when(mockContext.getRuntime()).thenReturn(Optional.of("Docker")); when(mockContext.getSource()).thenReturn(Optional.of("pierone.example.org/stups/foo:bar1")); when(mockContext.getPieroneTag()).thenReturn(Optional.of(new TagSummary("bar1", ZonedDateTime.now(), "test_user"))); when(mockContext.getScmSource()).thenReturn(Optional.of(ImmutableMap.of("status", DIRTY_REPO_STATUS))); plugin.process(mockContext); verify(mockViolationSink).put(argThat(hasType(SCM_URL_IS_MISSING_IN_SCM_SOURCE_JSON))); verify(mockViolationSink).put(argThat(hasType(ARTIFACT_BUILT_FROM_DIRTY_REPOSITORY))); } @Test public void testProcessWithoutViolations() throws Exception { when(mockContext.getRuntime()).thenReturn(Optional.of("Docker")); when(mockContext.getSource()).thenReturn(Optional.of("pierone.example.org/stups/foo:bar1")); when(mockContext.getPieroneTag()).thenReturn(Optional.of(new TagSummary("bar1", ZonedDateTime.now(), "test_user"))); when(mockContext.getScmSource()).thenReturn(Optional.of(ImmutableMap.of( "status", CLEAN_REPO_STATUS, "url", "git@github.com:zalando-stups/fullstop.git"))); plugin.process(mockContext); } @Test public void testProcessWithoutViolationsOnStatusFalse() throws Exception { when(mockContext.getRuntime()).thenReturn(Optional.of("Docker")); when(mockContext.getSource()).thenReturn(Optional.of("pierone.example.org/stups/foo:bar1")); when(mockContext.getPieroneTag()).thenReturn(Optional.of(new TagSummary("bar1", ZonedDateTime.now(), "test_user"))); when(mockContext.getScmSource()).thenReturn(Optional.of(ImmutableMap.of( "status", "FALSE", "url", "git@github.com:zalando-stups/fullstop.git"))); plugin.process(mockContext); } }