assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize(
COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION
+ 26 // level 1
- + 47 // content of DaoModule
+ + 48 // content of DaoModule
+ 2 // content of EsSearchModule
+ 54 // content of CorePropertyDefinitions
+ 1 // content of CePropertyDefinitions
import org.sonar.db.ce.CeQueueDao;
import org.sonar.db.ce.CeTaskInputDao;
import org.sonar.db.component.ComponentDao;
+import org.sonar.db.component.ComponentKeyUpdaterDao;
import org.sonar.db.component.ComponentLinkDao;
import org.sonar.db.component.ResourceDao;
import org.sonar.db.component.ResourceIndexDao;
-import org.sonar.db.component.ComponentKeyUpdaterDao;
import org.sonar.db.component.SnapshotDao;
import org.sonar.db.dashboard.ActiveDashboardDao;
import org.sonar.db.dashboard.DashboardDao;
import org.sonar.db.metric.MetricDao;
import org.sonar.db.notification.NotificationQueueDao;
import org.sonar.db.permission.PermissionDao;
-import org.sonar.db.permission.template.PermissionTemplateDao;
import org.sonar.db.permission.template.PermissionTemplateCharacteristicDao;
+import org.sonar.db.permission.template.PermissionTemplateDao;
import org.sonar.db.property.PropertiesDao;
import org.sonar.db.purge.PurgeDao;
import org.sonar.db.qualitygate.ProjectQgateAssociationDao;
import org.sonar.db.qualityprofile.ActiveRuleDao;
import org.sonar.db.qualityprofile.QualityProfileDao;
import org.sonar.db.rule.RuleDao;
+import org.sonar.db.scannercontext.ScannerContextDao;
import org.sonar.db.source.FileSourceDao;
import org.sonar.db.user.AuthorDao;
import org.sonar.db.user.AuthorizationDao;
PermissionTemplateDao.class,
PermissionTemplateCharacteristicDao.class,
PropertiesDao.class,
+ ProjectQgateAssociationDao.class,
+ PurgeDao.class,
QualityGateDao.class,
QualityGateConditionDao.class,
- ProjectQgateAssociationDao.class,
QualityProfileDao.class,
- PurgeDao.class,
+ ScannerContextDao.class,
RuleDao.class,
ActiveRuleDao.class,
ResourceIndexDao.class,
import org.sonar.db.qualityprofile.ActiveRuleDao;
import org.sonar.db.qualityprofile.QualityProfileDao;
import org.sonar.db.rule.RuleDao;
+import org.sonar.db.scannercontext.ScannerContextDao;
import org.sonar.db.source.FileSourceDao;
import org.sonar.db.user.AuthorDao;
import org.sonar.db.user.AuthorizationDao;
private final GroupDao groupDao;
private final RuleDao ruleDao;
private final ActiveRuleDao activeRuleDao;
+ private final ScannerContextDao scannerContextDao;
public DbClient(Database database, MyBatis myBatis, Dao... daos) {
this.database = database;
groupDao = getDao(map, GroupDao.class);
ruleDao = getDao(map, RuleDao.class);
activeRuleDao = getDao(map, ActiveRuleDao.class);
+ scannerContextDao = getDao(map, ScannerContextDao.class);
doOnLoad(map);
}
return activeRuleDao;
}
+ public ScannerContextDao scannerContextDao() {
+ return scannerContextDao;
+ }
+
protected <K extends Dao> K getDao(Map<Class, Dao> map, Class<K> clazz) {
return (K) map.get(clazz);
}
import org.sonar.db.ce.CeTaskInputMapper;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentDtoWithSnapshotId;
+import org.sonar.db.component.ComponentKeyUpdaterMapper;
import org.sonar.db.component.ComponentLinkDto;
import org.sonar.db.component.ComponentLinkMapper;
import org.sonar.db.component.ComponentMapper;
import org.sonar.db.component.ResourceDto;
import org.sonar.db.component.ResourceIndexDto;
import org.sonar.db.component.ResourceIndexMapper;
-import org.sonar.db.component.ComponentKeyUpdaterMapper;
import org.sonar.db.component.ResourceMapper;
import org.sonar.db.component.SnapshotDto;
import org.sonar.db.component.SnapshotMapper;
import org.sonar.db.notification.NotificationQueueDto;
import org.sonar.db.notification.NotificationQueueMapper;
import org.sonar.db.permission.GroupWithPermissionDto;
+import org.sonar.db.permission.UserWithPermissionDto;
+import org.sonar.db.permission.template.PermissionTemplateCharacteristicDto;
+import org.sonar.db.permission.template.PermissionTemplateCharacteristicMapper;
import org.sonar.db.permission.template.PermissionTemplateDto;
import org.sonar.db.permission.template.PermissionTemplateGroupDto;
import org.sonar.db.permission.template.PermissionTemplateMapper;
import org.sonar.db.permission.template.PermissionTemplateUserDto;
-import org.sonar.db.permission.UserWithPermissionDto;
-import org.sonar.db.permission.template.PermissionTemplateCharacteristicDto;
-import org.sonar.db.permission.template.PermissionTemplateCharacteristicMapper;
import org.sonar.db.property.PropertiesMapper;
import org.sonar.db.property.PropertyDto;
import org.sonar.db.purge.IdUuidPair;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.db.scannercontext;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import org.sonar.core.util.CloseableIterator;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * An {@link InputStream} that will read from a {@link CloseableIterator} of {@link String}, inserting {@code \n} between
+ * each element of the Iterator.
+ */
+final class LogsIteratorInputStream extends InputStream {
+ private static final int UNSET = -1;
+ private static final int END_OF_STREAM = -1;
+
+ private final Charset charset;
+ private final byte[] lineFeed;
+ private CloseableIterator<String> logsIterator;
+ private byte[] buf;
+ private int nextChar = UNSET;
+
+ LogsIteratorInputStream(CloseableIterator<String> logsIterator, Charset charset) {
+ checkArgument(logsIterator.hasNext(), "LogsIterator can't be empty or already read");
+ this.charset = charset;
+ this.lineFeed = "\n".getBytes(charset);
+ this.logsIterator = logsIterator;
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (nextChar == UNSET || nextChar >= buf.length) {
+ fill();
+ if (nextChar == UNSET) {
+ return END_OF_STREAM;
+ }
+ }
+ return buf[nextChar++];
+ }
+
+ private void fill() {
+ if (logsIterator.hasNext()) {
+ byte[] line = logsIterator.next().getBytes(charset);
+ boolean hasNextLine = logsIterator.hasNext();
+ int bufLength = hasNextLine ? (line.length + lineFeed.length) : line.length;
+ // empty last line
+ if (bufLength == 0) {
+ this.buf = null;
+ this.nextChar = UNSET;
+ } else {
+ this.buf = new byte[bufLength];
+ System.arraycopy(line, 0, buf, 0, line.length);
+ if (hasNextLine) {
+ System.arraycopy(lineFeed, 0, buf, line.length, lineFeed.length);
+ }
+ this.nextChar = 0;
+ }
+ } else {
+ this.buf = null;
+ this.nextChar = UNSET;
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ this.logsIterator.close();
+ this.buf = null;
+
+ super.close();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.db.scannercontext;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Optional;
+import org.apache.commons.io.IOUtils;
+import org.sonar.api.utils.System2;
+import org.sonar.core.util.CloseableIterator;
+import org.sonar.db.Dao;
+import org.sonar.db.DbSession;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+public class ScannerContextDao implements Dao {
+
+ private static final Charset UTF_8 = Charset.forName("UTF-8");
+
+ private final System2 system;
+
+ public ScannerContextDao(System2 system) {
+ this.system = system;
+ }
+
+ /**
+ * @throws IllegalArgumentException if {@code scannerContextLines} is empty or fully read.
+ */
+ public void insert(DbSession dbSession, String analysisUuid, CloseableIterator<String> scannerContextLines) {
+ checkArgument(scannerContextLines.hasNext(), "Scanner context can not be empty");
+ long now = system.now();
+ try (PreparedStatement stmt = dbSession.getConnection().prepareStatement(
+ "INSERT INTO scanner_context (analysis_uuid, created_at, updated_at, data) VALUES (?, ?, ?, ?)");
+ InputStream inputStream = new LogsIteratorInputStream(scannerContextLines, UTF_8)) {
+ stmt.setString(1, analysisUuid);
+ stmt.setLong(2, now);
+ stmt.setLong(3, now);
+ stmt.setBinaryStream(4, inputStream);
+ stmt.executeUpdate();
+ } catch (SQLException | IOException e) {
+ throw new IllegalStateException("Fail to insert scanner context for analysis " + analysisUuid, e);
+ }
+ }
+
+ /**
+ * The scanner context is very likely to contain lines, which are forcefully separated by {@code \n} characters,
+ * whichever the platform SQ is running on ({@see LogsIteratorInputStream}).
+ */
+ public Optional<String> selectScannerContext(DbSession dbSession, String analysisUuid) {
+ try (PreparedStatement stmt = dbSession.getConnection().prepareStatement("select data from scanner_context where analysis_uuid=?")) {
+ stmt.setString(1, analysisUuid);
+ try (ResultSet rs = stmt.executeQuery()) {
+ if (rs.next()) {
+ return Optional.of(IOUtils.toString(rs.getBinaryStream(1), UTF_8));
+ }
+ return Optional.empty();
+ }
+ } catch (SQLException | IOException e) {
+ throw new IllegalStateException("Fail to retrieve scanner context of analysis " + analysisUuid, e);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.db.scannercontext;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
);
CREATE TABLE "CE_TASK_INPUT" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
"TASK_UUID" VARCHAR(40) NOT NULL,
"DATA" BLOB(167772150),
"CREATED_AT" BIGINT NOT NULL,
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new DaoModule().configure(container);
- assertThat(container.size()).isEqualTo(2 + 47);
+ assertThat(container.size()).isEqualTo(2 + 48);
}
}
package org.sonar.db;
import com.google.common.base.Joiner;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Collections2;
+import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import java.io.InputStream;
import org.picocontainer.containers.TransientPicoContainer;
import org.sonar.api.utils.System2;
+import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
import static java.sql.ResultSetMetaData.columnNoNulls;
}
public void executeUpdateSql(String sql, Object... params) {
- try (Connection connection = db.getDatabase().getDataSource().getConnection()) {
+ try (Connection connection = getConnection()) {
new QueryRunner().update(connection, sql, params);
} catch (Exception e) {
throw new IllegalStateException("Fail to execute sql: " + sql, e);
* <pre>int issues = countRowsOfTable("issues")</pre>
*/
public int countRowsOfTable(String tableName) {
- Preconditions.checkArgument(StringUtils.containsNone(tableName, " "), "Parameter must be the name of a table. Got " + tableName);
- return countSql("select count(1) from " + tableName.toLowerCase(Locale.ENGLISH));
+ return countRowsOfTable(tableName, this::getConnection);
+ }
+
+ public int countRowsOfTable(DbSession dbSession, String tableName) {
+ return countRowsOfTable(tableName, () -> dbSession.getConnection());
+ }
+
+ private int countRowsOfTable(String tableName, SqlExceptionSupplier<Connection> connectionSupplier) {
+ checkArgument(StringUtils.containsNone(tableName, " "), "Parameter must be the name of a table. Got " + tableName);
+ return countSql("select count(1) from " + tableName.toLowerCase(Locale.ENGLISH), connectionSupplier);
}
/**
* <pre>int OpenIssues = countSql("select count('id') from issues where status is not null")</pre>
*/
public int countSql(String sql) {
- Preconditions.checkArgument(StringUtils.contains(sql, "count("),
+ return countSql(sql, this::getConnection);
+ }
+
+ public int countSql(DbSession dbSession, String sql) {
+ return countSql(sql, () -> dbSession.getConnection());
+ }
+
+ private int countSql(String sql, SqlExceptionSupplier<Connection> connectionSupplier) {
+ checkArgument(StringUtils.contains(sql, "count("),
"Parameter must be a SQL request containing 'count(x)' function. Got " + sql);
try (
- Connection connection = db.getDatabase().getDataSource().getConnection();
+ Connection connection = connectionSupplier.get();
PreparedStatement stmt = connection.prepareStatement(sql);
ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
}
public List<Map<String, Object>> select(String selectSql) {
+ return select(selectSql, this::getConnection);
+ }
+
+ private List<Map<String, Object>> select(String selectSql, SqlExceptionSupplier<Connection> connectionSupplier) {
try (
- Connection connection = db.getDatabase().getDataSource().getConnection();
+ Connection connection = connectionSupplier.get();
PreparedStatement stmt = connection.prepareStatement(selectSql);
ResultSet rs = stmt.executeQuery()) {
return getHashMap(rs);
}
public Map<String, Object> selectFirst(String selectSql) {
- List<Map<String, Object>> rows = select(selectSql);
+ return selectFirst(selectSql, this::getConnection);
+ }
+
+ public Map<String, Object> selectFirst(DbSession dbSession, String selectSql) {
+ return selectFirst(selectSql, () -> dbSession.getConnection());
+ }
+
+ private Map<String, Object> selectFirst(String selectSql, SqlExceptionSupplier<Connection> connectionSupplier) {
+ List<Map<String, Object>> rows = select(selectSql, connectionSupplier);
if (rows.isEmpty()) {
throw new IllegalStateException("No results for " + selectSql);
} else if (rows.size() > 1) {
}
public void assertColumnDefinition(String table, String column, int expectedType, @Nullable Integer expectedSize, @Nullable Boolean isNullable) {
- try (Connection connection = db.getDatabase().getDataSource().getConnection();
+ try (Connection connection = getConnection();
PreparedStatement stmt = connection.prepareStatement("select * from " + table);
ResultSet res = stmt.executeQuery()) {
Integer columnIndex = getColumnIndex(res, column);
@Deprecated
public Connection openConnection() throws Exception {
+ return getConnection();
+ }
+
+ private Connection getConnection() throws SQLException {
return db.getDatabase().getDataSource().getConnection();
}
return db.getCommands();
}
+ /**
+ * A {@link Supplier} that declares the checked exception {@link SQLException}.
+ */
+ @FunctionalInterface
+ private interface SqlExceptionSupplier<T> {
+ T get() throws SQLException;
+ }
+
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.db.scannercontext;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import org.apache.commons.io.IOUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.core.util.CloseableIterator;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class LogsIteratorInputStreamTest {
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ public void read_from_ClosableIterator_with_several_lines() throws IOException {
+ assertThat(read(create("line1", "line2", "line3"))).isEqualTo("line1" + '\n' + "line2" + '\n' + "line3");
+ }
+
+ @Test
+ public void read_from_ClosableIterator_with_single_line() throws IOException {
+ assertThat(read(create("line1"))).isEqualTo("line1");
+ }
+
+ @Test
+ public void read_from_ClosableIterator_with_single_empty_line() throws IOException {
+ assertThat(read(create(""))).isEqualTo("");
+ }
+
+ @Test
+ public void read_from_ClosableIterator_with_several_empty_lines() throws IOException {
+ assertThat(read(create("", "line2", "", "line4", "", "", "", "line8", "")))
+ .isEqualTo('\n' + "line2" + '\n' + '\n' + "line4" + '\n' + '\n' + '\n' + '\n' + "line8" + '\n');
+ }
+
+ @Test
+ public void constructor_throws_IAE_when_ClosableIterator_is_empty() throws IOException {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("LogsIterator can't be empty or already read");
+
+ create();
+ }
+
+ @Test
+ public void constructor_throws_IAE_when_ClosableIterator_has_already_been_read() throws IOException {
+ CloseableIterator<String> iterator = CloseableIterator.from(Arrays.asList("line1").iterator());
+
+ // read iterator to the end
+ iterator.next();
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("LogsIterator can't be empty or already read");
+
+ new LogsIteratorInputStream(iterator, Charset.forName("UTF-8"));
+ }
+
+ private static LogsIteratorInputStream create(String... lines) {
+ return new LogsIteratorInputStream(CloseableIterator.from(Arrays.asList(lines).iterator()), Charset.forName("UTF-8"));
+ }
+
+ private static String read(LogsIteratorInputStream logsIteratorInputStream) throws IOException {
+ return IOUtils.toString(logsIteratorInputStream, "UTF-8");
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.db.scannercontext;
+
+import java.util.Collections;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.core.util.CloseableIterator;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+
+import static java.lang.System.lineSeparator;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+public class ScannerContextDaoTest {
+
+ private static final String TABLE_NAME = "scanner_context";
+ private static final String SOME_UUID = "some UUID";
+
+ @Rule
+ public DbTester dbTester = DbTester.create(System2.INSTANCE);
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private System2 system = mock(System2.class);
+ private DbSession dbSession = dbTester.getSession();
+
+ private ScannerContextDao underTest = new ScannerContextDao(system);
+
+ @Test
+ public void selectScannerContext_returns_empty_on_empty_table() {
+ assertThat(underTest.selectScannerContext(dbSession, SOME_UUID)).isEmpty();
+ }
+
+ @Test
+ public void selectScannerContext_returns_empty_when_no_row_exist_for_analysisUuid() {
+ String data = "some data";
+ underTest.insert(dbSession, SOME_UUID, scannerContextInputStreamOf(data));
+ dbSession.commit();
+
+ assertThat(underTest.selectScannerContext(dbSession, "OTHER_uuid")).isEmpty();
+ assertThat(underTest.selectScannerContext(dbSession, SOME_UUID)).contains(data);
+ }
+
+ @Test
+ public void insert_fails_with_IAE_if_data_is_empty() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Scanner context can not be empty");
+
+ underTest.insert(dbSession, SOME_UUID, CloseableIterator.emptyCloseableIterator());
+ }
+
+ @Test
+ public void insert_fails_with_IAE_if_data_is_fully_read() {
+ CloseableIterator<String> iterator = scannerContextInputStreamOf("aa");
+ iterator.next();
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Scanner context can not be empty");
+
+ underTest.insert(dbSession, SOME_UUID, iterator);
+ }
+
+ @Test
+ public void insert_fails_if_row_already_exists_for_analysis_uuid() {
+ underTest.insert(dbSession, SOME_UUID, scannerContextInputStreamOf("bla"));
+ dbSession.commit();
+
+ assertThat(dbTester.countRowsOfTable(dbSession, TABLE_NAME)).isEqualTo(1);
+
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Fail to insert scanner context for analysis " + SOME_UUID);
+
+ underTest.insert(dbSession, SOME_UUID, scannerContextInputStreamOf("blo"));
+ }
+
+ @Test
+ public void insert_and_select_line_reader() {
+ String scannerContext = "line 1" + lineSeparator() + "line 2" + lineSeparator() + "line 3";
+ underTest.insert(dbSession, SOME_UUID, scannerContextInputStreamOf(scannerContext));
+ dbSession.commit(true);
+
+ assertThat(underTest.selectScannerContext(dbSession, SOME_UUID)).contains(scannerContext);
+ }
+
+ private static CloseableIterator<String> scannerContextInputStreamOf(String data) {
+ return CloseableIterator.from(Collections.singleton(data).iterator());
+ }
+
+}