| // Copyright (C) 2017 The Android Open Source Project |
| // |
| // 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.ericsson.gerrit.plugins.gcconductor.postgresqueue; |
| |
| import static com.ericsson.gerrit.plugins.gcconductor.postgresqueue.TestUtil.configMockFor; |
| import static com.ericsson.gerrit.plugins.gcconductor.postgresqueue.TestUtil.deleteDatabase; |
| import static com.google.common.truth.Truth.assertThat; |
| import static org.mockito.ArgumentMatchers.anyString; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.when; |
| |
| import com.ericsson.gerrit.plugins.gcconductor.GcQueueException; |
| import com.ericsson.gerrit.plugins.gcconductor.RepositoryInfo; |
| import java.sql.Connection; |
| import java.sql.ResultSet; |
| import java.sql.SQLException; |
| import java.sql.Statement; |
| import java.sql.Timestamp; |
| import java.util.Optional; |
| import java.util.concurrent.TimeUnit; |
| import org.apache.commons.dbcp.BasicDataSource; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| public class PostgresQueueTest { |
| |
| private static final String TEST_DATABASE_NAME = "gc_test_queue"; |
| private BasicDataSource dataSource; |
| private PostgresQueue queue; |
| |
| @Before |
| public void setUp() throws SQLException { |
| dataSource = |
| new PostgresModule(null).provideGcDatabaseAccess(configMockFor(TEST_DATABASE_NAME)); |
| queue = new PostgresQueue(dataSource); |
| } |
| |
| @After |
| public void tearDown() throws SQLException { |
| if (dataSource != null) { |
| dataSource.close(); |
| } |
| deleteDatabase(TEST_DATABASE_NAME); |
| } |
| |
| @Test |
| public void shouldCreateSchemaOnInit() throws GcQueueException { |
| assertThat(queue.list()).isEmpty(); |
| } |
| |
| @Test(expected = SQLException.class) |
| public void shouldThrowExceptionIfFailsToCreateSchemaOnInit() throws Exception { |
| BasicDataSource dataSouceMock = mock(BasicDataSource.class); |
| when(dataSouceMock.getConnection()).thenThrow(new SQLException("some message")); |
| queue = new PostgresQueue(dataSouceMock); |
| } |
| |
| @Test |
| public void testAddContainsAndRemove() throws GcQueueException { |
| String repoPath = "/some/path/to/some/repository"; |
| String hostname = "someHostname"; |
| |
| assertThat(queue.list()).isEmpty(); |
| assertThat(queue.contains(repoPath)).isFalse(); |
| |
| queue.add(repoPath, hostname); |
| assertThat(queue.list().size()).isEqualTo(1); |
| assertThat(queue.contains(repoPath)).isTrue(); |
| |
| queue.add(repoPath, hostname); |
| assertThat(queue.list().size()).isEqualTo(1); |
| assertThat(queue.contains(repoPath)).isTrue(); |
| |
| String repoPath2 = "/some/path/to/some/repository2"; |
| String hostname2 = "someHostname2"; |
| |
| queue.add(repoPath2, hostname2); |
| assertThat(queue.list().size()).isEqualTo(2); |
| assertThat(queue.contains(repoPath)).isTrue(); |
| assertThat(queue.contains(repoPath2)).isTrue(); |
| |
| queue.remove(repoPath2); |
| assertThat(queue.list().size()).isEqualTo(1); |
| assertThat(queue.contains(repoPath)).isTrue(); |
| assertThat(queue.contains(repoPath2)).isFalse(); |
| |
| queue.remove(repoPath); |
| assertThat(queue.list().size()).isEqualTo(0); |
| assertThat(queue.contains(repoPath)).isFalse(); |
| |
| queue.remove(repoPath); |
| assertThat(queue.list().size()).isEqualTo(0); |
| assertThat(queue.contains(repoPath)).isFalse(); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testAddThatFailsWhenGettingConnection() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenGettingConnection()); |
| queue.add("repo", "hostname"); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testAddThatFailsWhenCreatingStatement() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenCreatingStatement()); |
| queue.add("repo", "hostname"); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testAddThatFailsWhenExecutingQuery() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenExecutingQuery()); |
| queue.add("repo", "hostname"); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testContainsThatFailsWhenGettingConnection() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenGettingConnection()); |
| queue.contains("repo"); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testContainsThatFailsWhenCreatingStatement() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenCreatingStatement()); |
| queue.contains("repo"); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testContainsThatFailsWhenExecutingQuery() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenExecutingQuery()); |
| queue.contains("repo"); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testContainsThatFailsWhenIteratingResults() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenIteratingResults()); |
| queue.contains("repo"); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testRemoveThatFailsWhenGettingConnection() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenGettingConnection()); |
| queue.remove("repo"); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testRemoveThatFailsWhenCreatingStatement() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenCreatingStatement()); |
| queue.remove("repo"); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testRemoveThatFailsWhenExecutingQuery() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenExecutingQuery()); |
| queue.remove("repo"); |
| } |
| |
| @Test |
| public void testList() throws GcQueueException { |
| String repoPath = "/some/path/to/some/repository.git"; |
| String repoPath2 = "/some/path/to/some/repository2.git"; |
| String hostname = "hostname"; |
| String executor = "hostname-1"; |
| |
| assertThat(queue.list()).isEmpty(); |
| Timestamp before = new Timestamp(System.currentTimeMillis()); |
| queue.add(repoPath, hostname); |
| queue.add(repoPath2, hostname); |
| queue.pick(executor, 0, Optional.empty()); |
| |
| assertThat(queue.list().size()).isEqualTo(2); |
| |
| assertThat(queue.list().get(0).getPath()).isEqualTo(repoPath); |
| assertThat(queue.list().get(0).getExecutor()).isEqualTo(executor); |
| assertThat(queue.list().get(0).getQueuedAt()).isAtLeast(before); |
| assertThat(queue.list().get(0).getQueuedAt()) |
| .isAtMost(new Timestamp(System.currentTimeMillis())); |
| assertThat(queue.list().get(0).getQueuedFrom()).isEqualTo(hostname); |
| |
| assertThat(queue.list().get(1).getPath()).isEqualTo(repoPath2); |
| assertThat(queue.list().get(1).getExecutor()).isNull(); |
| assertThat(queue.list().get(1).getQueuedAt()).isAtLeast(queue.list().get(0).getQueuedAt()); |
| assertThat(queue.list().get(1).getQueuedAt()) |
| .isAtMost(new Timestamp(System.currentTimeMillis())); |
| assertThat(queue.list().get(1).getQueuedFrom()).isEqualTo(hostname); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testListThatFailsWhenGettingConnection() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenGettingConnection()); |
| queue.list(); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testListThatFailsWhenCreatingStatement() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenCreatingStatement()); |
| queue.list(); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testListThatFailsWhenExecutingQuery() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenExecutingQuery()); |
| queue.list(); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testListThatFailsWhenIteratingResults() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenIteratingResults()); |
| queue.list(); |
| } |
| |
| @Test |
| public void testPick() throws GcQueueException { |
| String repoPath = "/some/path/to/some/repository"; |
| String hostname = "someHostname"; |
| String executor = "someExecutor"; |
| String executor2 = "someExecutor2"; |
| |
| // queue is empty nothing to pick |
| assertThat(queue.list()).isEmpty(); |
| assertThat(queue.pick(executor, 0, Optional.empty())).isNull(); |
| |
| // queue contains 1 repository, should pick that one |
| queue.add(repoPath, hostname); |
| RepositoryInfo picked = queue.pick(executor, 0, Optional.empty()); |
| assertThat(picked).isNotNull(); |
| assertThat(picked.getPath()).isEqualTo(repoPath); |
| assertThat(picked.getExecutor()).isEqualTo(executor); |
| |
| // queue contains 1 already picked repository, should pick same one |
| picked = queue.pick(executor, 0, Optional.empty()); |
| assertThat(picked).isNotNull(); |
| assertThat(picked.getPath()).isEqualTo(repoPath); |
| assertThat(picked.getExecutor()).isEqualTo(executor); |
| |
| // queue contains 1 already picked repository, nothing to pick for other |
| // executors |
| assertThat(queue.pick(executor2, 0, Optional.empty())).isNull(); |
| } |
| |
| @Test |
| public void testPickRepositoriesInOrder() throws GcQueueException { |
| String repositoryFormat = "my/path%s.git"; |
| for (int i = 0; i < 100; i++) { |
| queue.add(String.format(repositoryFormat, i), "someHostname"); |
| } |
| for (int i = 0; i < 100; i++) { |
| String pickedRepo = queue.pick("someExecutor", 0, Optional.empty()).getPath(); |
| assertThat(pickedRepo).isEqualTo(String.format(repositoryFormat, i)); |
| queue.remove(pickedRepo); |
| } |
| } |
| |
| @Test |
| public void testPickInQueueForLongerThan() throws GcQueueException, InterruptedException { |
| String repoPath = "/some/path/to/some/repository"; |
| String hostname = "someHostname"; |
| String executor = "someExecutor"; |
| |
| // pick repository older than 10 seconds, nothing to pick |
| queue.add(repoPath, hostname); |
| assertThat(queue.pick(executor, 10, Optional.empty())).isNull(); |
| assertThat(queue.list().get(0).getExecutor()).isNull(); |
| |
| // make 2 seconds elapse and pick repository older than 1 second, should pick one |
| TimeUnit.SECONDS.sleep((2)); |
| RepositoryInfo picked = queue.pick(executor, 1, Optional.empty()); |
| assertThat(picked.getPath()).isEqualTo(repoPath); |
| assertThat(picked.getExecutor()).isEqualTo(executor); |
| } |
| |
| @Test |
| public void testPickQueuedFrom() throws GcQueueException { |
| String repoPath = "/some/path/to/some/repository"; |
| String hostname = "hostname"; |
| String otherHostname = "otherHostname"; |
| String executor = "hostname-1"; |
| |
| // pick repository queued from otherHostname, nothing to pick |
| queue.add(repoPath, hostname); |
| assertThat(queue.pick(executor, 0, Optional.of(otherHostname))).isNull(); |
| assertThat(queue.list().get(0).getExecutor()).isNull(); |
| |
| // pick repository queued from hostname, should pick one |
| RepositoryInfo picked = queue.pick(executor, 0, Optional.of(hostname)); |
| assertThat(picked.getPath()).isEqualTo(repoPath); |
| assertThat(picked.getExecutor()).isEqualTo(executor); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testPickThatFailsWhenGettingConnection() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenGettingConnection()); |
| queue.pick("executor", 0, Optional.empty()); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testPickThatFailsWhenCreatingStatement() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenCreatingStatement()); |
| queue.pick("executor", 0, Optional.empty()); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testPickThatFailsWhenExecutingQuery() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenExecutingQuery()); |
| queue.pick("executor", 0, Optional.empty()); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testPickThatFailsWhenIteratingResults() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenIteratingResults()); |
| queue.pick("executor", 0, Optional.empty()); |
| } |
| |
| @Test |
| public void testUnpick() throws GcQueueException { |
| String repoPath = "/some/path/to/some/repository"; |
| String hostname = "someHostname"; |
| String executor = "someExecutor"; |
| |
| // queue contains 1 repository, should pick that one |
| queue.add(repoPath, hostname); |
| RepositoryInfo picked = queue.pick(executor, 0, Optional.empty()); |
| assertThat(picked.getPath()).isEqualTo(repoPath); |
| assertThat(picked.getExecutor()).isEqualTo(executor); |
| |
| queue.unpick(repoPath); |
| // unpick repo so should pick that one again |
| queue.unpick(repoPath); |
| picked = queue.pick(executor, 0, Optional.empty()); |
| assertThat(picked.getPath()).isEqualTo(repoPath); |
| assertThat(picked.getExecutor()).isEqualTo(executor); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testUnpickThatFailsWhenGettingConnection() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenGettingConnection()); |
| queue.unpick("/some/path/to/some/repository.git"); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testUnpickFailsWhenCreatingStatement() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenCreatingStatement()); |
| queue.unpick("/some/path/to/some/repository.git"); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testUnpickThatFailsWhenExecutingQuery() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenExecutingQuery()); |
| queue.unpick("/some/path/to/some/repository.git"); |
| } |
| |
| @Test |
| public void testResetQueuedFrom() throws GcQueueException { |
| String repoPath = "/some/path/to/some/repository"; |
| String repoPath2 = "/some/path/to/some/repository2"; |
| String hostname = "hostname"; |
| String otherHostname = "otherHostname"; |
| |
| queue.add(repoPath, hostname); |
| queue.add(repoPath2, hostname); |
| assertThat(queue.list().get(0).getQueuedFrom()).isEqualTo(hostname); |
| assertThat(queue.list().get(1).getQueuedFrom()).isEqualTo(hostname); |
| |
| queue.resetQueuedFrom(otherHostname); |
| assertThat(queue.list().get(0).getQueuedFrom()).isEqualTo(otherHostname); |
| assertThat(queue.list().get(1).getQueuedFrom()).isEqualTo(otherHostname); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testResetQueuedFromThatFailsWhenGettingConnection() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenGettingConnection()); |
| queue.resetQueuedFrom("someHostname"); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testResetQueuedFromFailsWhenCreatingStatement() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenCreatingStatement()); |
| queue.resetQueuedFrom("someHostname"); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testResetQueuedFromThatFailsWhenExecutingQuery() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenExecutingQuery()); |
| queue.resetQueuedFrom("someHostname"); |
| } |
| |
| @Test |
| public void testBumpToFirst() throws GcQueueException { |
| String repoPath = "/some/path/to/some/repository"; |
| String repoPath2 = "/some/path/to/some/repository2"; |
| String repoPath3 = "/some/path/to/some/repository3"; |
| String hostname = "hostname"; |
| |
| // Queue contains 1 repository, bumping should have no effect |
| queue.add(repoPath, hostname); |
| assertThat(queue.list().get(0).getPath()).isEqualTo(repoPath); |
| queue.bumpToFirst(repoPath); |
| assertThat(queue.list().get(0).getPath()).isEqualTo(repoPath); |
| |
| // Queue has 3 repositories, should be able to change their order |
| queue.add(repoPath2, hostname); |
| queue.add(repoPath3, hostname); |
| assertThat(queue.list().get(1).getPath()).isEqualTo(repoPath2); |
| assertThat(queue.list().get(2).getPath()).isEqualTo(repoPath3); |
| |
| // repoPath3 should be first, all other repositories should be shifted down |
| queue.bumpToFirst(repoPath3); |
| assertThat(queue.list().get(0).getPath()).isEqualTo(repoPath3); |
| assertThat(queue.list().get(1).getPath()).isEqualTo(repoPath); |
| assertThat(queue.list().get(2).getPath()).isEqualTo(repoPath2); |
| |
| // Bumping a repository that is already first priority should have no effect |
| queue.bumpToFirst(repoPath3); |
| assertThat(queue.list().get(0).getPath()).isEqualTo(repoPath3); |
| assertThat(queue.list().get(1).getPath()).isEqualTo(repoPath); |
| assertThat(queue.list().get(2).getPath()).isEqualTo(repoPath2); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testBumpToFirstThatFailsWhenGettingConnection() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenGettingConnection()); |
| queue.bumpToFirst("someHostname"); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testBumpToFirstFailsWhenCreatingStatement() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenCreatingStatement()); |
| queue.bumpToFirst("someHostname"); |
| } |
| |
| @Test(expected = GcQueueException.class) |
| public void testBumpToFirstThatFailsWhenExecutingQuery() throws Exception { |
| queue = new PostgresQueue(createDataSourceThatFailsWhenExecutingQuery()); |
| queue.bumpToFirst("someHostname"); |
| } |
| |
| private BasicDataSource createDataSourceThatFailsWhenGettingConnection() throws SQLException { |
| BasicDataSource dataSouceMock = mock(BasicDataSource.class); |
| Connection connectionMock = mock(Connection.class); |
| Statement statementMock = mock(Statement.class); |
| |
| when(dataSouceMock.getConnection()).thenReturn(connectionMock).thenThrow(new SQLException()); |
| when(connectionMock.createStatement()).thenReturn(statementMock); |
| |
| return dataSouceMock; |
| } |
| |
| private BasicDataSource createDataSourceThatFailsWhenCreatingStatement() throws SQLException { |
| BasicDataSource dataSouceMock = mock(BasicDataSource.class); |
| Connection connectionMock = mock(Connection.class); |
| Statement statementMock = mock(Statement.class); |
| |
| when(dataSouceMock.getConnection()).thenReturn(connectionMock); |
| when(connectionMock.createStatement()).thenReturn(statementMock).thenThrow(new SQLException()); |
| |
| return dataSouceMock; |
| } |
| |
| private BasicDataSource createDataSourceThatFailsWhenExecutingQuery() throws SQLException { |
| BasicDataSource dataSouceMock = mock(BasicDataSource.class); |
| Connection connectionMock = mock(Connection.class); |
| Statement statementMock = mock(Statement.class); |
| |
| when(dataSouceMock.getConnection()).thenReturn(connectionMock); |
| when(connectionMock.createStatement()).thenReturn(statementMock); |
| when(statementMock.execute(anyString())).thenReturn(true).thenThrow(new SQLException()); |
| when(statementMock.executeQuery(anyString())).thenThrow(new SQLException()); |
| |
| return dataSouceMock; |
| } |
| |
| private BasicDataSource createDataSourceThatFailsWhenIteratingResults() throws SQLException { |
| BasicDataSource dataSouceMock = mock(BasicDataSource.class); |
| Connection connectionMock = mock(Connection.class); |
| Statement statementMock = mock(Statement.class); |
| ResultSet resultSetMock = mock(ResultSet.class); |
| |
| when(dataSouceMock.getConnection()).thenReturn(connectionMock); |
| when(connectionMock.createStatement()).thenReturn(statementMock); |
| when(statementMock.executeQuery(anyString())).thenReturn(resultSetMock); |
| when(resultSetMock.next()).thenThrow(new SQLException()); |
| |
| return dataSouceMock; |
| } |
| } |