From 29a2c1076d79e6580f6c005312ee3ab1e64b8fc5 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 27 Nov 2019 00:26:46 +0100 Subject: [PATCH] Fix datbase tests and enable running using GitHub workflows - fix behavior when no entries have to be inserted during a synch - fix database tests - have dbms test test only one database - DBMS to test is passed via environment variable "DBMS", defaulting to PostgreSQL - add shared information on Canonical BibTeX entry - some code improvement - have checkstyle running on github workflows (not on Travis) --- .github/workflows/checkstyle.yml | 27 +++ .github/workflows/test-on-mysql.yml | 40 ++++ .github/workflows/test-on-postgres.yml | 40 ++++ .travis.yml | 12 -- docs/testing.md | 17 ++ .../shared/DBMSConnectionProperties.java | 8 +- .../jabref/logic/shared/DBMSProcessor.java | 9 +- .../jabref/logic/shared/DBMSSynchronizer.java | 52 +++-- .../model/database/shared/DBMSType.java | 12 +- .../jabref/model/entry/CanonicalBibEntry.java | 3 + .../model/entry/SharedBibEntryData.java | 2 +- .../shared/DBMSConnectionPropertiesTest.java | 16 ++ .../logic/shared/DBMSConnectionTest.java | 13 +- .../logic/shared/DBMSProcessorTest.java | 192 +++++++----------- .../logic/shared/DBMSSynchronizerTest.java | 177 ++++++++-------- .../shared/SynchronizationTestSimulator.java | 111 +++++----- .../jabref/logic/shared/TestConnector.java | 24 +-- .../org/jabref/logic/shared/TestManager.java | 35 +--- .../model/entry/CanonicalBibEntryTest.java | 7 +- 19 files changed, 436 insertions(+), 361 deletions(-) create mode 100644 .github/workflows/checkstyle.yml create mode 100644 .github/workflows/test-on-mysql.yml create mode 100644 .github/workflows/test-on-postgres.yml create mode 100644 docs/testing.md create mode 100644 src/test/java/org/jabref/logic/shared/DBMSConnectionPropertiesTest.java diff --git a/.github/workflows/checkstyle.yml b/.github/workflows/checkstyle.yml new file mode 100644 index 000000000000..eec5b0a3d7a8 --- /dev/null +++ b/.github/workflows/checkstyle.yml @@ -0,0 +1,27 @@ +name: checkstyle + +on: [push] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout source + uses: actions/checkout@v1 + with: + depth: 1 + submodules: false + - name: Set up JDK + uses: actions/setup-java@v1 + with: + java-version: 13 + - uses: actions/cache@v1 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: | + ${{ runner.OS }}-gradle-${{ env.cache-name }}- + ${{ runner.OS }}-gradle- + ${{ runner.OS }}- + - name: Run checkstyle test + run: ./gradlew checkstyleMain checkstyleTest checkstyleJmh diff --git a/.github/workflows/test-on-mysql.yml b/.github/workflows/test-on-mysql.yml new file mode 100644 index 000000000000..73afca981d09 --- /dev/null +++ b/.github/workflows/test-on-mysql.yml @@ -0,0 +1,40 @@ +name: Test on MySQL + +on: [push] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Shutdown Ubuntu MySQL (SUDO) + run: sudo service mysql stop # Shutdown the Default MySQL, "sudo" is necessary, please not remove it + - uses: mirromutth/mysql-action@v1.1 + with: + host port: 3800 + container port: 3307 + character set server: 'utf8' + collation server: 'utf8_general_ci' + mysql version: '8.0' + mysql database: 'jabref' + mysql root password: 'root' + - name: Set up JDK + uses: actions/setup-java@v1 + with: + java-version: 13 + - name: Checkout source + uses: actions/checkout@v1 + with: + depth: 1 + submodules: false + - uses: actions/cache@v1 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: | + ${{ runner.OS }}-gradle-${{ env.cache-name }}- + ${{ runner.OS }}-gradle- + ${{ runner.OS }}- + - name: Run database test + run: ./gradlew databaseTest + env: + DBMS: "mysql" diff --git a/.github/workflows/test-on-postgres.yml b/.github/workflows/test-on-postgres.yml new file mode 100644 index 000000000000..f5b3db7d4967 --- /dev/null +++ b/.github/workflows/test-on-postgres.yml @@ -0,0 +1,40 @@ +name: Test on PostgreSQL + +on: [push] + +jobs: + test: + runs-on: ubuntu-latest + services: + postgres: + image: postgres:10.8 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + - 5432:5432 + # needed because the postgres container does not provide a healthcheck + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + steps: + - name: Checkout source + uses: actions/checkout@v1 + with: + depth: 1 + submodules: false + - name: Set up JDK + uses: actions/setup-java@v1 + with: + java-version: 13 + - uses: actions/cache@v1 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: | + ${{ runner.OS }}-gradle-${{ env.cache-name }}- + ${{ runner.OS }}-gradle- + ${{ runner.OS }}- + - name: Run database test + run: ./gradlew databaseTest + env: + DBMS: "postgresql" diff --git a/.travis.yml b/.travis.yml index dc29ce8976a2..b3d2e28825aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,18 +11,12 @@ sudo: required git: depth: 1 -services: - - postgresql - - mysql - env: global: - GRADLE_OPTS=-Dorg.gradle.daemon=false matrix: - TEST_SUITE=check - - TEST_SUITE=checkstyle - TEST_SUITE=fetcherTest - - TEST_SUITE=databaseTest - TEST_SUITE=guiTest # codecov may fail by itself (see gradle build file) # The codecov test itself fails only in case there is an issue with the codecov update. @@ -34,7 +28,6 @@ matrix: fast_finish: true allow_failures: - env: TEST_SUITE=fetcherTest - - env: TEST_SUITE=databaseTest - env: TEST_SUITE=guiTest - env: DEPENDENCY_UPDATES=check @@ -46,13 +39,8 @@ before_install: install: true -before_script: - - psql -c 'create database jabref;' -U postgres - - mysql -u root -e 'create database jabref' - script: - if [ "$TEST_SUITE" != "guiTest" ] && [ "$TEST_SUITE" != "checkstyle" ] && [ "$TEST_SUITE" != "codecov" ]; then ./gradlew $TEST_SUITE $OPTIONS -x checkstyleJmh -x checkstyleMain -x checkstyleTest; fi - - if [ "$TEST_SUITE" == "checkstyle" ]; then ./gradlew checkstyleMain checkstyleTest checkstyleJmh; fi - if [ "$TEST_SUITE" == "guiTest" ]; then ./buildres/gui-tests.sh; fi - if [ "$TEST_SUITE" == "codecov" ]; then ./gradlew jacocoTestReport && bash <(curl -s https://codecov.io/bash); fi - if [ "$DEPENDENCY_UPDATES" == "check" ]; then ./gradlew -q checkOutdatedDependencies; fi diff --git a/docs/testing.md b/docs/testing.md new file mode 100644 index 000000000000..b7d7bb81bfe1 --- /dev/null +++ b/docs/testing.md @@ -0,0 +1,17 @@ +# How to test + +## Database tests + +To quickly host a local PostgreSQL database, execute following statement: + +```shell command +docker run -d -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=postgres -p 5432:5432 --name db postgres:10 postgres -c log_statement=all +``` + +Then, all DBMS Tests (annotated with `@org.jabref.testutils.category.DatabaseTest`) run properly. + +A MySQL can be started using following command: + +``´shell command +docker run -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=jabref -p 3800:3307 mysql:8.0 --port=3307 +``` diff --git a/src/main/java/org/jabref/logic/shared/DBMSConnectionProperties.java b/src/main/java/org/jabref/logic/shared/DBMSConnectionProperties.java index f39eb8a41a45..f7b7d9a87653 100644 --- a/src/main/java/org/jabref/logic/shared/DBMSConnectionProperties.java +++ b/src/main/java/org/jabref/logic/shared/DBMSConnectionProperties.java @@ -117,7 +117,13 @@ public void setUseSSL(boolean useSSL) { } public String getUrl() { - return type.getUrl(host, port, database); + String url = type.getUrl(host, port, database); + if (this.type == DBMSType.MYSQL) { + // quickfix - see https://mysqlconnector.net/troubleshooting/retrieval-public-key/ + url += "?allowPublicKeyRetrieval=true"; + url += "&useSSL=" + this.isUseSSL(); + } + return url; } @Override diff --git a/src/main/java/org/jabref/logic/shared/DBMSProcessor.java b/src/main/java/org/jabref/logic/shared/DBMSProcessor.java index b4651f96eafd..62d8a45a8204 100644 --- a/src/main/java/org/jabref/logic/shared/DBMSProcessor.java +++ b/src/main/java/org/jabref/logic/shared/DBMSProcessor.java @@ -66,7 +66,7 @@ public boolean checkBaseIntegrity() throws SQLException { * * @return true if the structure is old, else false. */ - public boolean checkForPare3Dot6Integrity() throws SQLException { + public boolean databaseIsAtMostJabRef35() throws SQLException { return checkTableAvailability( "ENTRIES", "ENTRY_GROUP", @@ -439,7 +439,14 @@ public Optional getSharedEntry(int sharedID) { return Optional.empty(); } + /** + * Queries the database for shared entries. Optionally, they are filtered by the given list of sharedIds + * + * @param sharedIDs the list of Ids to filter. If list is empty, then no filter is applied + */ public List getSharedEntries(List sharedIDs) { + Objects.requireNonNull(sharedIDs); + List sharedEntries = new ArrayList<>(); StringBuilder query = new StringBuilder(); diff --git a/src/main/java/org/jabref/logic/shared/DBMSSynchronizer.java b/src/main/java/org/jabref/logic/shared/DBMSSynchronizer.java index 23753cdde403..9ddf90cea2c8 100644 --- a/src/main/java/org/jabref/logic/shared/DBMSSynchronizer.java +++ b/src/main/java/org/jabref/logic/shared/DBMSSynchronizer.java @@ -8,6 +8,7 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import org.jabref.logic.exporter.BibDatabaseWriter; import org.jabref.logic.exporter.MetaDataSerializer; @@ -146,15 +147,17 @@ public void initializeDatabases() throws DatabaseNotSupportedException { try { if (!dbmsProcessor.checkBaseIntegrity()) { LOGGER.info("Integrity check failed. Fixing..."); - dbmsProcessor.setupSharedDatabase(); // This check should only be performed once on initial database setup. - // Calling dbmsProcessor.setupSharedDatabase() lets dbmsProcessor.checkBaseIntegrity() be true. - if (dbmsProcessor.checkForPare3Dot6Integrity()) { + if (dbmsProcessor.databaseIsAtMostJabRef35()) { throw new DatabaseNotSupportedException(); } + + // Calling dbmsProcessor.setupSharedDatabase() lets dbmsProcessor.checkBaseIntegrity() be true. + dbmsProcessor.setupSharedDatabase(); } } catch (SQLException e) { + LOGGER.error("Could not check intergrity", e); throw new IllegalStateException(e); } @@ -164,7 +167,7 @@ public void initializeDatabases() throws DatabaseNotSupportedException { } /** - * Synchronizes the local database with shared one. Possible update types are removal, update or insert of a {@link + * Synchronizes the local database with shared one. Possible update types are: removal, update, or insert of a {@link * BibEntry}. */ @Override @@ -178,13 +181,13 @@ public void synchronizeLocalDatabase() { // remove old entries locally removeNotSharedEntries(localEntries, idVersionMap.keySet()); - List entriesToDrag = new ArrayList<>(); + List entriesToInsertIntoLocalDatabase = new ArrayList<>(); // compare versions and update local entry if needed for (Map.Entry idVersionEntry : idVersionMap.entrySet()) { - boolean match = false; + boolean remoteEntryMatchingOneLocalEntryFound = false; for (BibEntry localEntry : localEntries) { - if (idVersionEntry.getKey() == localEntry.getSharedBibEntryData().getSharedID()) { - match = true; + if (idVersionEntry.getKey().equals(localEntry.getSharedBibEntryData().getSharedID())) { + remoteEntryMatchingOneLocalEntryFound = true; if (idVersionEntry.getValue() > localEntry.getSharedBibEntryData().getVersion()) { Optional sharedEntry = dbmsProcessor.getSharedEntry(idVersionEntry.getKey()); if (sharedEntry.isPresent()) { @@ -193,7 +196,7 @@ public void synchronizeLocalDatabase() { localEntry.getSharedBibEntryData() .setVersion(sharedEntry.get().getSharedBibEntryData().getVersion()); sharedEntry.get().getFieldMap().forEach( - // copy remote values to local entry + // copy remote values to local entry (field, value) -> localEntry.setField(field, value, EntriesEventSource.SHARED) ); @@ -207,13 +210,16 @@ public void synchronizeLocalDatabase() { } } } - if (!match) { - entriesToDrag.add(idVersionEntry.getKey()); + if (!remoteEntryMatchingOneLocalEntryFound) { + entriesToInsertIntoLocalDatabase.add(idVersionEntry.getKey()); } } - for (BibEntry bibEntry : dbmsProcessor.getSharedEntries(entriesToDrag)) { - bibDatabase.insertEntry(bibEntry, EntriesEventSource.SHARED); + if (!entriesToInsertIntoLocalDatabase.isEmpty()) { + // in case entries should be added into the local database, insert them + for (BibEntry bibEntry : dbmsProcessor.getSharedEntries(entriesToInsertIntoLocalDatabase)) { + bibDatabase.insertEntry(bibEntry, EntriesEventSource.SHARED); + } } } @@ -224,23 +230,15 @@ public void synchronizeLocalDatabase() { * @param sharedIDs Set of all IDs which are present on shared database */ private void removeNotSharedEntries(List localEntries, Set sharedIDs) { - List entriesToRemove = new ArrayList<>(); - for (BibEntry localEntry : localEntries) { - boolean match = false; - for (int sharedID : sharedIDs) { - if (localEntry.getSharedBibEntryData().getSharedID() == sharedID) { - match = true; - break; - } - } - if (!match) { - entriesToRemove.add(localEntry); - } - } + List entriesToRemove = + localEntries.stream() + .filter(localEntry -> !sharedIDs.contains(localEntry.getSharedBibEntryData().getSharedID())) + .collect(Collectors.toList()); if (!entriesToRemove.isEmpty()) { eventBus.post(new SharedEntriesNotPresentEvent(entriesToRemove)); + // remove all non-shared entries without triggering listeners + bibDatabase.removeEntries(entriesToRemove, EntriesEventSource.SHARED); } - bibDatabase.removeEntries(entriesToRemove, EntriesEventSource.SHARED); // Should not reach the listeners above. } /** diff --git a/src/main/java/org/jabref/model/database/shared/DBMSType.java b/src/main/java/org/jabref/model/database/shared/DBMSType.java index 90d940c2eb8d..71b9e2538be6 100644 --- a/src/main/java/org/jabref/model/database/shared/DBMSType.java +++ b/src/main/java/org/jabref/model/database/shared/DBMSType.java @@ -51,11 +51,15 @@ public int getDefaultPort() { } public static Optional fromString(String typeName) { - try { - return Optional.of(Enum.valueOf(DBMSType.class, typeName.toUpperCase(Locale.ENGLISH))); - } catch (IllegalArgumentException exception) { + if (typeName == null) { return Optional.empty(); + } else { + try { + return Optional.of(Enum.valueOf(DBMSType.class, typeName.toUpperCase(Locale.ENGLISH))); + } catch (IllegalArgumentException exception) { + // IllegalArgumentException is thrown if "typename" is not covered by the Enum + return Optional.empty(); + } } } - } diff --git a/src/main/java/org/jabref/model/entry/CanonicalBibEntry.java b/src/main/java/org/jabref/model/entry/CanonicalBibEntry.java index a854db41907f..1136c253001a 100644 --- a/src/main/java/org/jabref/model/entry/CanonicalBibEntry.java +++ b/src/main/java/org/jabref/model/entry/CanonicalBibEntry.java @@ -56,6 +56,9 @@ public static String getCanonicalRepresentation(BibEntry entry) { String line = String.format(" %s = {%s}", fieldName, String.valueOf(mapFieldToValue.get(fieldName)).replaceAll("\\r\\n", "\n")); sj.add(line); } + + sj.add(String.format(" _jabref_shared = {sharedId: %d, version: %d}", entry.getSharedBibEntryData().getSharedID(), entry.getSharedBibEntryData().getVersion())); + sb.append(sj); // append the closing entry bracket diff --git a/src/main/java/org/jabref/model/entry/SharedBibEntryData.java b/src/main/java/org/jabref/model/entry/SharedBibEntryData.java index 25672e829d84..79546fc202c6 100644 --- a/src/main/java/org/jabref/model/entry/SharedBibEntryData.java +++ b/src/main/java/org/jabref/model/entry/SharedBibEntryData.java @@ -1,7 +1,7 @@ package org.jabref.model.entry; /** - * Stores all informations needed to manage entries on a shared (SQL) database. + * Stores all information needed to manage entries on a shared (SQL) database. */ public class SharedBibEntryData { diff --git a/src/test/java/org/jabref/logic/shared/DBMSConnectionPropertiesTest.java b/src/test/java/org/jabref/logic/shared/DBMSConnectionPropertiesTest.java new file mode 100644 index 000000000000..de9347e51af4 --- /dev/null +++ b/src/test/java/org/jabref/logic/shared/DBMSConnectionPropertiesTest.java @@ -0,0 +1,16 @@ +package org.jabref.logic.shared; + +import org.jabref.model.database.shared.DBMSType; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class DBMSConnectionPropertiesTest { + + @Test + void urlForMySqlIncludesSslConfig() { + DBMSConnectionProperties connectionProperties = new DBMSConnectionProperties(DBMSType.MYSQL, "localhost", 3108, "jabref", "user", "password", false, ""); + assertEquals("jdbc:mariadb://localhost:3108/jabref?allowPublicKeyRetrieval=true&useSSL=false", connectionProperties.getUrl()); + } +} diff --git a/src/test/java/org/jabref/logic/shared/DBMSConnectionTest.java b/src/test/java/org/jabref/logic/shared/DBMSConnectionTest.java index e0cb37bae263..9a3a34d35493 100644 --- a/src/test/java/org/jabref/logic/shared/DBMSConnectionTest.java +++ b/src/test/java/org/jabref/logic/shared/DBMSConnectionTest.java @@ -2,14 +2,12 @@ import java.sql.SQLException; -import org.jabref.logic.shared.exception.InvalidDBMSConnectionPropertiesException; import org.jabref.model.database.shared.DBMSType; import org.jabref.testutils.category.DatabaseTest; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; -import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; @DatabaseTest @@ -17,15 +15,8 @@ public class DBMSConnectionTest { @ParameterizedTest @EnumSource(DBMSType.class) - public void testGetConnection(DBMSType dbmsType) throws SQLException, InvalidDBMSConnectionPropertiesException { - DBMSConnectionProperties properties = TestConnector.getTestConnectionProperties(dbmsType); - assertNotNull(new DBMSConnection(properties).getConnection()); - } - - @ParameterizedTest - @EnumSource(DBMSType.class) - public void testGetConnectionFail(DBMSType dbmsType) throws SQLException, InvalidDBMSConnectionPropertiesException { + public void getConnectionFailsWhenconnectingToInvalidHost(DBMSType dbmsType) { assertThrows(SQLException.class, - () -> new DBMSConnection(new DBMSConnectionProperties(dbmsType, "XXXX", 0, "XXXX", "XXXX", "XXXX", false, "XXXX")).getConnection()); + () -> new DBMSConnection(new DBMSConnectionProperties(dbmsType, "XXXX", 33778, "XXXX", "XXXX", "XXXX", false, "XXXX")).getConnection()); } } diff --git a/src/test/java/org/jabref/logic/shared/DBMSProcessorTest.java b/src/test/java/org/jabref/logic/shared/DBMSProcessorTest.java index 401ba599020b..c35d0e7c0eb5 100644 --- a/src/test/java/org/jabref/logic/shared/DBMSProcessorTest.java +++ b/src/test/java/org/jabref/logic/shared/DBMSProcessorTest.java @@ -19,8 +19,11 @@ import org.jabref.model.entry.types.StandardEntryType; import org.jabref.testutils.category.DatabaseTest; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -29,33 +32,44 @@ import static org.junit.jupiter.api.Assertions.fail; @DatabaseTest +@Execution(ExecutionMode.SAME_THREAD) class DBMSProcessorTest { - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - void testCheckBaseIntegrity(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws SQLException { + private DBMSConnection dbmsConnection; + private DBMSProcessor dbmsProcessor; + private DBMSType dbmsType; + + @BeforeEach + public void setup() throws Exception { + this.dbmsType = TestManager.getDBMSTypeTestParameter(); + this.dbmsConnection = TestConnector.getTestDBMSConnection(dbmsType); + this.dbmsProcessor = DBMSProcessor.getProcessorInstance(TestConnector.getTestDBMSConnection(dbmsType)); + TestManager.clearTables(this.dbmsConnection); + } + + @AfterEach + public void clear() throws SQLException { + this.dbmsConnection.getConnection().close(); + } + + @Test + void testCheckBaseIntegrity() throws SQLException { dbmsProcessor.setupSharedDatabase(); assertTrue(dbmsProcessor.checkBaseIntegrity()); - clear(dbmsConnection); + TestManager.clearTables(this.dbmsConnection); assertFalse(dbmsProcessor.checkBaseIntegrity()); - - clear(dbmsConnection); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - void testSetUpSharedDatabase(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws SQLException { + @Test + void testSetUpSharedDatabase() throws SQLException { dbmsProcessor.setupSharedDatabase(); - clear(dbmsConnection); + clear(); dbmsProcessor.setupSharedDatabase(); assertTrue(dbmsProcessor.checkBaseIntegrity()); - - clear(dbmsConnection); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - void testInsertEntry(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws SQLException { + @Test + void testInsertEntry() throws SQLException { dbmsProcessor.setupSharedDatabase(); BibEntry expectedEntry = getBibEntryExample(); @@ -84,12 +98,10 @@ void testInsertEntry(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProce Map expectedFieldMap = expectedEntry.getFieldMap().entrySet().stream().collect(Collectors.toMap((entry) -> entry.getKey().getName(), Map.Entry::getValue)); assertEquals(expectedFieldMap, actualFieldMap); - clear(dbmsConnection); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - void testUpdateEntry(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws Exception { + @Test + void testUpdateEntry() throws Exception { dbmsProcessor.setupSharedDatabase(); BibEntry expectedEntry = getBibEntryExample(); dbmsProcessor.insertEntry(expectedEntry); @@ -101,14 +113,11 @@ void testUpdateEntry(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProce dbmsProcessor.updateEntry(expectedEntry); Optional actualEntry = dbmsProcessor.getSharedEntry(expectedEntry.getSharedBibEntryData().getSharedID()); - assertEquals(expectedEntry, actualEntry.get()); - - clear(dbmsConnection); + assertEquals(Optional.of(expectedEntry), actualEntry); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - void testGetEntriesByIdList(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws Exception { + @Test + void testGetEntriesByIdList() throws Exception { dbmsProcessor.setupSharedDatabase(); BibEntry firstEntry = getBibEntryExample(); firstEntry.setField(InternalField.INTERNAL_ID_FIELD, "00001"); @@ -120,16 +129,11 @@ void testGetEntriesByIdList(DBMSType dbmsType, DBMSConnection dbmsConnection, DB List sharedEntriesByIdList = dbmsProcessor.getSharedEntries(Arrays.asList(1, 2)); - clear(dbmsConnection); - - assertEquals(firstEntry, sharedEntriesByIdList.get(0)); - assertEquals(secondEntry, sharedEntriesByIdList.get(1)); - + assertEquals(List.of(firstEntry, secondEntry), sharedEntriesByIdList); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - void testUpdateNewerEntry(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws OfflineLockException, SQLException { + @Test + void testUpdateNewerEntry() throws OfflineLockException, SQLException { dbmsProcessor.setupSharedDatabase(); BibEntry bibEntry = getBibEntryExample(); @@ -140,13 +144,10 @@ void testUpdateNewerEntry(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMS bibEntry.setField(StandardField.YEAR, "1993"); assertThrows(OfflineLockException.class, () -> dbmsProcessor.updateEntry(bibEntry)); - - clear(dbmsConnection); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - void testUpdateEqualEntry(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws OfflineLockException, SQLException { + @Test + void testUpdateEqualEntry() throws OfflineLockException, SQLException { dbmsProcessor.setupSharedDatabase(); BibEntry expectedBibEntry = getBibEntryExample(); @@ -156,16 +157,13 @@ void testUpdateEqualEntry(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMS dbmsProcessor.updateEntry(expectedBibEntry); Optional actualBibEntryOptional = dbmsProcessor - .getSharedEntry(expectedBibEntry.getSharedBibEntryData().getSharedID()); - - assertEquals(expectedBibEntry, actualBibEntryOptional.get()); + .getSharedEntry(expectedBibEntry.getSharedBibEntryData().getSharedID()); - clear(dbmsConnection); + assertEquals(Optional.of(expectedBibEntry), actualBibEntryOptional); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - void testRemoveAllEntries(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws SQLException { + @Test + void testRemoveAllEntries() throws SQLException { dbmsProcessor.setupSharedDatabase(); BibEntry firstEntry = getBibEntryExample(); BibEntry secondEntry = getBibEntryExample(); @@ -177,12 +175,10 @@ void testRemoveAllEntries(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMS try (ResultSet resultSet = selectFrom("ENTRY", dbmsConnection, dbmsProcessor)) { assertFalse(resultSet.next()); } - clear(dbmsConnection); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - void testRemoveSomeEntries(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws SQLException { + @Test + void testRemoveSomeEntries() throws SQLException { dbmsProcessor.setupSharedDatabase(); BibEntry firstEntry = getBibEntryExample(); BibEntry secondEntry = getBibEntryExample(); @@ -201,13 +197,10 @@ void testRemoveSomeEntries(DBMSType dbmsType, DBMSConnection dbmsConnection, DBM assertEquals(2, entryResultSet.getInt("SHARED_ID")); assertFalse(entryResultSet.next()); } - - clear(dbmsConnection); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - void testRemoveSingleEntry(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws SQLException { + @Test + void testRemoveSingleEntry() throws SQLException { dbmsProcessor.setupSharedDatabase(); BibEntry entryToRemove = getBibEntryExample(); dbmsProcessor.insertEntry(entryToRemove); @@ -216,49 +209,38 @@ void testRemoveSingleEntry(DBMSType dbmsType, DBMSConnection dbmsConnection, DBM try (ResultSet entryResultSet = selectFrom("ENTRY", dbmsConnection, dbmsProcessor)) { assertFalse(entryResultSet.next()); } - - clear(dbmsConnection); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - void testRemoveEntriesOnNullThrows(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws SQLException { + @Test + void testRemoveEntriesOnNullThrows() throws SQLException { dbmsProcessor.setupSharedDatabase(); assertThrows(NullPointerException.class, () -> dbmsProcessor.removeEntries(null)); - clear(dbmsConnection); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - void testRemoveEmptyEntryList(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws SQLException { + @Test + void testRemoveEmptyEntryList() throws SQLException { dbmsProcessor.setupSharedDatabase(); dbmsProcessor.removeEntries(Collections.emptyList()); try (ResultSet entryResultSet = selectFrom("ENTRY", dbmsConnection, dbmsProcessor)) { assertFalse(entryResultSet.next()); } - - clear(dbmsConnection); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - void testGetSharedEntries(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws SQLException { + @Test + void testGetSharedEntries() throws SQLException { dbmsProcessor.setupSharedDatabase(); BibEntry bibEntry = getBibEntryExampleWithEmptyFields(); dbmsProcessor.insertEntry(bibEntry); - List expectedEntries = Arrays.asList(bibEntry); List actualEntries = dbmsProcessor.getSharedEntries(); - assertEquals(expectedEntries, actualEntries); - clear(dbmsConnection); + assertEquals(List.of(bibEntry), actualEntries); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - void testGetSharedEntry(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws SQLException { + @Test + void testGetSharedEntry() throws SQLException { dbmsProcessor.setupSharedDatabase(); BibEntry expectedBibEntry = getBibEntryExampleWithEmptyFields(); @@ -266,23 +248,18 @@ void testGetSharedEntry(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSPr Optional actualBibEntryOptional = dbmsProcessor.getSharedEntry(expectedBibEntry.getSharedBibEntryData().getSharedID()); - assertEquals(expectedBibEntry, actualBibEntryOptional.get()); - clear(dbmsConnection); + assertEquals(Optional.of(expectedBibEntry), actualBibEntryOptional); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - void testGetNotExistingSharedEntry(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws SQLException { + @Test + void testGetNotExistingSharedEntry() throws SQLException { dbmsProcessor.setupSharedDatabase(); Optional actualBibEntryOptional = dbmsProcessor.getSharedEntry(1); assertFalse(actualBibEntryOptional.isPresent()); - - clear(dbmsConnection); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - void testGetSharedIDVersionMapping(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws OfflineLockException, SQLException { + @Test + void testGetSharedIDVersionMapping() throws OfflineLockException, SQLException { dbmsProcessor.setupSharedDatabase(); BibEntry firstEntry = getBibEntryExample(); BibEntry secondEntry = getBibEntryExample(); @@ -298,13 +275,10 @@ void testGetSharedIDVersionMapping(DBMSType dbmsType, DBMSConnection dbmsConnect Map actualIDVersionMap = dbmsProcessor.getSharedIDVersionMapping(); assertEquals(expectedIDVersionMap, actualIDVersionMap); - - clear(dbmsConnection); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - void testGetSharedMetaData(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws SQLException { + @Test + void testGetSharedMetaData() throws SQLException { dbmsProcessor.setupSharedDatabase(); insertMetaData("databaseType", "bibtex;", dbmsConnection, dbmsProcessor); insertMetaData("protectedFlag", "true;", dbmsConnection, dbmsProcessor); @@ -315,12 +289,10 @@ void testGetSharedMetaData(DBMSType dbmsType, DBMSConnection dbmsConnection, DBM Map actualMetaData = dbmsProcessor.getSharedMetaData(); assertEquals(expectedMetaData, actualMetaData); - clear(dbmsConnection); } - @ParameterizedTest - @MethodSource("getTestingDatabaseSystems") - void testSetSharedMetaData(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws SQLException { + @Test + void testSetSharedMetaData() throws SQLException { dbmsProcessor.setupSharedDatabase(); Map expectedMetaData = getMetaDataExample(); dbmsProcessor.setSharedMetaData(expectedMetaData); @@ -328,7 +300,6 @@ void testSetSharedMetaData(DBMSType dbmsType, DBMSConnection dbmsConnection, DBM Map actualMetaData = dbmsProcessor.getSharedMetaData(); assertEquals(expectedMetaData, actualMetaData); - clear(dbmsConnection); } private Map getMetaDataExample() { @@ -343,22 +314,21 @@ private Map getMetaDataExample() { } private BibEntry getBibEntryExampleWithEmptyFields() { - BibEntry bibEntry = new BibEntry(); - bibEntry.setField(StandardField.AUTHOR, "Author"); - bibEntry.setField(StandardField.TITLE, ""); - bibEntry.setField(StandardField.YEAR, ""); + BibEntry bibEntry = new BibEntry() + .withField(StandardField.AUTHOR, "Author") + .withField(StandardField.TITLE, "") + .withField(StandardField.YEAR, ""); bibEntry.getSharedBibEntryData().setSharedID(1); return bibEntry; } private BibEntry getBibEntryExample() { - BibEntry bibEntry = new BibEntry(StandardEntryType.InProceedings); - bibEntry.setField(StandardField.AUTHOR, "Wirthlin, Michael J and Hutchings, Brad L and Gilson, Kent L"); - bibEntry.setField(StandardField.TITLE, "The nano processor: a low resource reconfigurable processor"); - bibEntry.setField(StandardField.BOOKTITLE, "FPGAs for Custom Computing Machines, 1994. Proceedings. IEEE Workshop on"); - bibEntry.setField(StandardField.YEAR, "1994"); - bibEntry.setCiteKey("nanoproc1994"); - return bibEntry; + return new BibEntry(StandardEntryType.InProceedings) + .withField(StandardField.AUTHOR, "Wirthlin, Michael J and Hutchings, Brad L and Gilson, Kent L") + .withField(StandardField.TITLE, "The nano processor: a low resource reconfigurable processor") + .withField(StandardField.BOOKTITLE, "FPGAs for Custom Computing Machines, 1994. Proceedings. IEEE Workshop on") + .withField(StandardField.YEAR, "1994") + .withCiteKey("nanoproc1994"); } private ResultSet selectFrom(String table, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) { @@ -375,8 +345,8 @@ private ResultSet selectFrom(String table, DBMSConnection dbmsConnection, DBMSPr private void insertMetaData(String key, String value, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) { try { dbmsConnection.getConnection().createStatement().executeUpdate("INSERT INTO " + escape("METADATA", dbmsProcessor) + "(" - + escape("KEY", dbmsProcessor) + ", " + escape("VALUE", dbmsProcessor) + ") VALUES(" - + escapeValue(key) + ", " + escapeValue(value) + ")"); + + escape("KEY", dbmsProcessor) + ", " + escape("VALUE", dbmsProcessor) + ") VALUES(" + + escapeValue(key) + ", " + escapeValue(value) + ")"); } catch (SQLException e) { fail(e.getMessage()); } @@ -389,8 +359,4 @@ private String escape(String expression, DBMSProcessor dbmsProcessor) { private String escapeValue(String value) { return "'" + value + "'"; } - - void clear(DBMSConnection dbmsConnection) throws SQLException { - TestManager.clearTables(dbmsConnection); - } } diff --git a/src/test/java/org/jabref/logic/shared/DBMSSynchronizerTest.java b/src/test/java/org/jabref/logic/shared/DBMSSynchronizerTest.java index 4d41a5a15d93..7c0cbba838f8 100644 --- a/src/test/java/org/jabref/logic/shared/DBMSSynchronizerTest.java +++ b/src/test/java/org/jabref/logic/shared/DBMSSynchronizerTest.java @@ -24,38 +24,59 @@ import org.jabref.model.util.DummyFileUpdateMonitor; import org.jabref.testutils.category.DatabaseTest; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @DatabaseTest +@Execution(ExecutionMode.SAME_THREAD) public class DBMSSynchronizerTest { private DBMSSynchronizer dbmsSynchronizer; private BibDatabase bibDatabase; private final GlobalBibtexKeyPattern pattern = GlobalBibtexKeyPattern.fromPattern("[auth][year]"); + private DBMSConnection dbmsConnection; + private DBMSProcessor dbmsProcessor; + private DBMSType dbmsType; + + private BibEntry createExampleBibEntry(int index) { + BibEntry bibEntry = new BibEntry(StandardEntryType.Book) + .withField(StandardField.AUTHOR, "Wirthlin, Michael J" + index) + .withField(StandardField.TITLE, "The nano processor" + index); + bibEntry.getSharedBibEntryData().setSharedID(index); + return bibEntry; + } - public void setUp(DBMSConnection dbmsConnection) throws Exception { - clear(dbmsConnection); + @BeforeEach + public void setup() throws Exception { + this.dbmsType = TestManager.getDBMSTypeTestParameter(); + this.dbmsConnection = TestConnector.getTestDBMSConnection(dbmsType); + this.dbmsProcessor = DBMSProcessor.getProcessorInstance(this.dbmsConnection); + TestManager.clearTables(this.dbmsConnection); bibDatabase = new BibDatabase(); BibDatabaseContext context = new BibDatabaseContext(bibDatabase); - dbmsSynchronizer = new DBMSSynchronizer(context, ',', pattern, new DummyFileUpdateMonitor()); + dbmsSynchronizer = new DBMSSynchronizer(context, ',', pattern, new DummyFileUpdateMonitor()); bibDatabase.registerListener(dbmsSynchronizer); dbmsSynchronizer.openSharedDatabase(dbmsConnection); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - public void testEntryAddedEventListener(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws Exception { - setUp(dbmsConnection); + @AfterEach + public void clear() throws SQLException { + this.dbmsConnection.getConnection().close(); + } - BibEntry expectedEntry = getBibEntryExample(1); - BibEntry furtherEntry = getBibEntryExample(1); + @Test + public void testEntryAddedEventListener() throws Exception { + BibEntry expectedEntry = createExampleBibEntry(1); + BibEntry furtherEntry = createExampleBibEntry(1); bibDatabase.insertEntry(expectedEntry); // should not add into shared database. @@ -63,36 +84,43 @@ public void testEntryAddedEventListener(DBMSType dbmsType, DBMSConnection dbmsCo List actualEntries = dbmsProcessor.getSharedEntries(); - assertEquals(1, actualEntries.size()); - assertEquals(expectedEntry, actualEntries.get(0)); - - clear(dbmsConnection); + assertEquals(List.of(expectedEntry), actualEntries); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - public void testFieldChangedEventListener(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws Exception { - setUp(dbmsConnection); - - BibEntry expectedEntry = getBibEntryExample(1); + @Test + public void twoLocalFieldChangesAreSynchronizedCorrectly() throws Exception { + BibEntry expectedEntry = createExampleBibEntry(1); expectedEntry.registerListener(dbmsSynchronizer); bibDatabase.insertEntry(expectedEntry); expectedEntry.setField(StandardField.AUTHOR, "Brad L and Gilson"); - expectedEntry.setField(StandardField.TITLE, "The micro multiplexer", EntriesEventSource.SHARED); + expectedEntry.setField(StandardField.TITLE, "The micro multiplexer"); List actualEntries = dbmsProcessor.getSharedEntries(); assertEquals(Collections.singletonList(expectedEntry), actualEntries); - - clear(dbmsConnection); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - public void testEntriesRemovedEventListener(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws Exception { - setUp(dbmsConnection); + @Test + public void oneLocalAndOneSharedFieldChangeIsSynchronizedCorrectly() throws Exception { + BibEntry exampleBibEntry = createExampleBibEntry(1); + exampleBibEntry.registerListener(dbmsSynchronizer); - BibEntry bibEntry = getBibEntryExample(1); + bibDatabase.insertEntry(exampleBibEntry); + exampleBibEntry.setField(StandardField.AUTHOR, "Brad L and Gilson"); + // shared updates are not synchronized back to the remote database + exampleBibEntry.setField(StandardField.TITLE, "The micro multiplexer", EntriesEventSource.SHARED); + + List actualEntries = dbmsProcessor.getSharedEntries(); + + BibEntry expectedBibEntry = createExampleBibEntry(1) + .withField(StandardField.AUTHOR, "Brad L and Gilson"); + + assertEquals(Collections.singletonList(expectedBibEntry), actualEntries); + } + + @Test + public void testEntriesRemovedEventListener() throws Exception { + BibEntry bibEntry = createExampleBibEntry(1); bibDatabase.insertEntry(bibEntry); List actualEntries = dbmsProcessor.getSharedEntries(); @@ -110,15 +138,10 @@ public void testEntriesRemovedEventListener(DBMSType dbmsType, DBMSConnection db actualEntries = dbmsProcessor.getSharedEntries(); assertEquals(1, actualEntries.size()); assertEquals(bibEntry, actualEntries.get(0)); - - clear(dbmsConnection); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - public void testMetaDataChangedEventListener(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws Exception { - setUp(dbmsConnection); - + @Test + public void testMetaDataChangedEventListener() throws Exception { MetaData testMetaData = new MetaData(); testMetaData.registerListener(dbmsSynchronizer); dbmsSynchronizer.setMetaData(testMetaData); @@ -128,29 +151,19 @@ public void testMetaDataChangedEventListener(DBMSType dbmsType, DBMSConnection d Map actualMap = dbmsProcessor.getSharedMetaData(); assertEquals(expectedMap, actualMap); - - clear(dbmsConnection); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - public void testInitializeDatabases(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws Exception { - setUp(dbmsConnection); - - clear(dbmsConnection); + @Test + public void testInitializeDatabases() throws Exception { dbmsSynchronizer.initializeDatabases(); assertTrue(dbmsProcessor.checkBaseIntegrity()); dbmsSynchronizer.initializeDatabases(); assertTrue(dbmsProcessor.checkBaseIntegrity()); - clear(dbmsConnection); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - public void testSynchronizeLocalDatabaseWithEntryRemoval(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws Exception { - setUp(dbmsConnection); - - List expectedBibEntries = Arrays.asList(getBibEntryExample(1), getBibEntryExample(2)); + @Test + public void testSynchronizeLocalDatabaseWithEntryRemoval() throws Exception { + List expectedBibEntries = Arrays.asList(createExampleBibEntry(1), createExampleBibEntry(2)); dbmsProcessor.insertEntry(expectedBibEntries.get(0)); dbmsProcessor.insertEntry(expectedBibEntries.get(1)); @@ -168,38 +181,47 @@ public void testSynchronizeLocalDatabaseWithEntryRemoval(DBMSType dbmsType, DBMS dbmsSynchronizer.synchronizeLocalDatabase(); assertEquals(expectedBibEntries, bibDatabase.getEntries()); - - clear(dbmsConnection); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - public void testSynchronizeLocalDatabaseWithEntryUpdate(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws Exception { - setUp(dbmsConnection); - - BibEntry bibEntry = getBibEntryExample(1); + @Test + public void testSynchronizeLocalDatabaseWithEntryUpdate() throws Exception { + BibEntry bibEntry = createExampleBibEntry(1); bibDatabase.insertEntry(bibEntry); - assertEquals(1, bibDatabase.getEntries().size()); + assertEquals(List.of(bibEntry), bibDatabase.getEntries()); - BibEntry modifiedBibEntry = getBibEntryExample(1); - modifiedBibEntry.setField(new UnknownField("custom"), "custom value"); + BibEntry modifiedBibEntry = createExampleBibEntry(1) + .withField(new UnknownField("custom"), "custom value"); modifiedBibEntry.clearField(StandardField.TITLE); modifiedBibEntry.setType(StandardEntryType.Article); dbmsProcessor.updateEntry(modifiedBibEntry); - //testing point + assertEquals(1, modifiedBibEntry.getSharedBibEntryData().getSharedID()); dbmsSynchronizer.synchronizeLocalDatabase(); - assertEquals(bibDatabase.getEntries(), dbmsProcessor.getSharedEntries()); - clear(dbmsConnection); + assertEquals(List.of(modifiedBibEntry), bibDatabase.getEntries()); + assertEquals(List.of(modifiedBibEntry), dbmsProcessor.getSharedEntries()); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - public void testApplyMetaData(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws Exception { - setUp(dbmsConnection); + @Test + public void updateEntryDoesNotModifyLocalDatabase() throws Exception { + BibEntry bibEntry = createExampleBibEntry(1); + bibDatabase.insertEntry(bibEntry); + assertEquals(List.of(bibEntry), bibDatabase.getEntries()); + + BibEntry modifiedBibEntry = createExampleBibEntry(1) + .withField(new UnknownField("custom"), "custom value"); + modifiedBibEntry.clearField(StandardField.TITLE); + modifiedBibEntry.setType(StandardEntryType.Article); + + dbmsProcessor.updateEntry(modifiedBibEntry); - BibEntry bibEntry = getBibEntryExample(1); + assertEquals(List.of(bibEntry), bibDatabase.getEntries()); + assertEquals(List.of(modifiedBibEntry), dbmsProcessor.getSharedEntries()); + } + + @Test + public void testApplyMetaData() throws Exception { + BibEntry bibEntry = createExampleBibEntry(1); bibDatabase.insertEntry(bibEntry); MetaData testMetaData = new MetaData(); @@ -209,20 +231,5 @@ public void testApplyMetaData(DBMSType dbmsType, DBMSConnection dbmsConnection, dbmsSynchronizer.applyMetaData(); assertEquals("wirthlin, michael j1", bibEntry.getField(StandardField.AUTHOR).get()); - - clear(dbmsConnection); - } - - private BibEntry getBibEntryExample(int index) { - BibEntry bibEntry = new BibEntry(); - bibEntry.setType(StandardEntryType.Book); - bibEntry.setField(StandardField.AUTHOR, "Wirthlin, Michael J" + index); - bibEntry.setField(StandardField.TITLE, "The nano processor" + index); - bibEntry.getSharedBibEntryData().setSharedID(index); - return bibEntry; - } - - public void clear(DBMSConnection dbmsConnection) throws SQLException { - TestManager.clearTables(dbmsConnection); } } diff --git a/src/test/java/org/jabref/logic/shared/SynchronizationTestSimulator.java b/src/test/java/org/jabref/logic/shared/SynchronizationTestSimulator.java index fb8bf59b0d57..6bda1fcb9411 100644 --- a/src/test/java/org/jabref/logic/shared/SynchronizationTestSimulator.java +++ b/src/test/java/org/jabref/logic/shared/SynchronizationTestSimulator.java @@ -1,12 +1,12 @@ package org.jabref.logic.shared; import java.sql.SQLException; +import java.util.List; import org.jabref.model.Defaults; import org.jabref.model.bibtexkeypattern.GlobalBibtexKeyPattern; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.BibDatabaseMode; -import org.jabref.model.database.shared.DBMSType; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.StandardField; import org.jabref.model.entry.field.UnknownField; @@ -14,8 +14,11 @@ import org.jabref.model.util.DummyFileUpdateMonitor; import org.jabref.testutils.category.DatabaseTest; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -24,6 +27,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; @DatabaseTest +@Execution(ExecutionMode.SAME_THREAD) public class SynchronizationTestSimulator { private BibDatabaseContext clientContextA; @@ -31,24 +35,42 @@ public class SynchronizationTestSimulator { private SynchronizationTestEventListener eventListenerB; // used to monitor occurring events private final GlobalBibtexKeyPattern pattern = GlobalBibtexKeyPattern.fromPattern("[auth][year]"); - public void setUp(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws Exception { + private BibEntry getBibEntryExample(int index) { + return new BibEntry(StandardEntryType.InProceedings) + .withField(StandardField.AUTHOR, "Wirthlin, Michael J and Hutchings, Brad L and Gilson, Kent L " + index) + .withField(StandardField.TITLE, "The nano processor: a low resource reconfigurable processor " + index) + .withField(StandardField.BOOKTITLE, "FPGAs for Custom Computing Machines, 1994. Proceedings. IEEE Workshop on " + index) + .withField(StandardField.YEAR, "199" + index) + .withCiteKey("nanoproc199" + index); + } + + @BeforeEach + public void setup() throws Exception { + DBMSConnection dbmsConnection = TestConnector.getTestDBMSConnection(TestManager.getDBMSTypeTestParameter()); + TestManager.clearTables(dbmsConnection); + clientContextA = new BibDatabaseContext(new Defaults(BibDatabaseMode.BIBTEX)); DBMSSynchronizer synchronizerA = new DBMSSynchronizer(clientContextA, ',', pattern, new DummyFileUpdateMonitor()); clientContextA.convertToSharedDatabase(synchronizerA); clientContextA.getDBMSSynchronizer().openSharedDatabase(dbmsConnection); clientContextB = new BibDatabaseContext(new Defaults(BibDatabaseMode.BIBTEX)); - DBMSSynchronizer synchronizerB = new DBMSSynchronizer(clientContextA, ',', pattern, new DummyFileUpdateMonitor()); + DBMSSynchronizer synchronizerB = new DBMSSynchronizer(clientContextB, ',', pattern, new DummyFileUpdateMonitor()); clientContextB.convertToSharedDatabase(synchronizerB); - clientContextB.getDBMSSynchronizer().openSharedDatabase(dbmsConnection); + // use a second connection, because this is another client (typically on another machine) + clientContextB.getDBMSSynchronizer().openSharedDatabase(TestConnector.getTestDBMSConnection(TestManager.getDBMSTypeTestParameter())); eventListenerB = new SynchronizationTestEventListener(); clientContextB.getDBMSSynchronizer().registerListener(eventListenerB); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - public void simulateEntryInsertionAndManualPull(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws Exception { - setUp(dbmsType, dbmsConnection, dbmsProcessor); + @AfterEach + public void clear() throws SQLException { + clientContextA.getDBMSSynchronizer().closeSharedDatabase(); + clientContextB.getDBMSSynchronizer().closeSharedDatabase(); + } + + @Test + public void simulateEntryInsertionAndManualPull() throws Exception { //client A inserts an entry clientContextA.getDatabase().insertEntry(getBibEntryExample(1)); //client A inserts another entry @@ -57,35 +79,25 @@ public void simulateEntryInsertionAndManualPull(DBMSType dbmsType, DBMSConnectio clientContextB.getDBMSSynchronizer().pullChanges(); assertEquals(clientContextA.getDatabase().getEntries(), clientContextB.getDatabase().getEntries()); - - clear(dbmsConnection); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - public void simulateEntryUpdateAndManualPull(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws Exception { - setUp(dbmsType, dbmsConnection, dbmsProcessor); - + @Test + public void simulateEntryUpdateAndManualPull() throws Exception { BibEntry bibEntry = getBibEntryExample(1); - //client A inserts an entry + // client A inserts an entry clientContextA.getDatabase().insertEntry(bibEntry); - //client A changes the entry + // client A changes the entry bibEntry.setField(new UnknownField("custom"), "custom value"); - //client B pulls the changes + // client B pulls the changes bibEntry.clearField(StandardField.AUTHOR); clientContextB.getDBMSSynchronizer().pullChanges(); assertEquals(clientContextA.getDatabase().getEntries(), clientContextB.getDatabase().getEntries()); - - clear(dbmsConnection); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - public void simulateEntryDelitionAndManualPull(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws Exception { - setUp(dbmsType, dbmsConnection, dbmsProcessor); - + @Test + public void simulateEntryDelitionAndManualPull() throws Exception { BibEntry bibEntry = getBibEntryExample(1); //client A inserts an entry clientContextA.getDatabase().insertEntry(bibEntry); @@ -103,15 +115,10 @@ public void simulateEntryDelitionAndManualPull(DBMSType dbmsType, DBMSConnection assertTrue(clientContextA.getDatabase().getEntries().isEmpty()); assertTrue(clientContextB.getDatabase().getEntries().isEmpty()); - - clear(dbmsConnection); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - public void simulateUpdateOnNoLongerExistingEntry(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws Exception { - setUp(dbmsType, dbmsConnection, dbmsProcessor); - + @Test + public void simulateUpdateOnNoLongerExistingEntry() throws Exception { BibEntry bibEntryOfClientA = getBibEntryExample(1); //client A inserts an entry clientContextA.getDatabase().insertEntry(bibEntryOfClientA); @@ -133,53 +140,31 @@ public void simulateUpdateOnNoLongerExistingEntry(DBMSType dbmsType, DBMSConnect // here a new SharedEntryNotPresentEvent has been thrown. In this case the user B would get an pop-up window. assertNotNull(eventListenerB.getSharedEntriesNotPresentEvent()); - assertEquals(bibEntryOfClientB, eventListenerB.getSharedEntriesNotPresentEvent().getBibEntries()); - - clear(dbmsConnection); + assertEquals(List.of(bibEntryOfClientB), eventListenerB.getSharedEntriesNotPresentEvent().getBibEntries()); } - @ParameterizedTest - @MethodSource("org.jabref.logic.shared.TestManager#getTestingDatabaseSystems") - public void simulateEntryChangeConflicts(DBMSType dbmsType, DBMSConnection dbmsConnection, DBMSProcessor dbmsProcessor) throws Exception { - setUp(dbmsType, dbmsConnection, dbmsProcessor); - + @Test + public void simulateEntryChangeConflicts() { BibEntry bibEntryOfClientA = getBibEntryExample(1); - //client A inserts an entry + // client A inserts an entry clientContextA.getDatabase().insertEntry(bibEntryOfClientA); - //client B pulls the entry + // client B pulls the entry clientContextB.getDBMSSynchronizer().pullChanges(); - //A now increases the version number + // A now increases the version number bibEntryOfClientA.setField(StandardField.YEAR, "2001"); // B does nothing here, so there is no event occurrence - // B now tries to update the entry assertFalse(clientContextB.getDatabase().getEntries().isEmpty()); - assertNull(eventListenerB.getUpdateRefusedEvent()); BibEntry bibEntryOfClientB = clientContextB.getDatabase().getEntries().get(0); - //B also tries to change something + // B also tries to change something bibEntryOfClientB.setField(StandardField.YEAR, "2016"); // B now cannot update the shared entry, due to optimistic offline lock. // In this case an BibEntry merge dialog pops up. assertNotNull(eventListenerB.getUpdateRefusedEvent()); - - clear(dbmsConnection); - } - - private BibEntry getBibEntryExample(int index) { - BibEntry bibEntry = new BibEntry(StandardEntryType.InProceedings); - bibEntry.setField(StandardField.AUTHOR, "Wirthlin, Michael J and Hutchings, Brad L and Gilson, Kent L " + index); - bibEntry.setField(StandardField.TITLE, "The nano processor: a low resource reconfigurable processor " + index); - bibEntry.setField(StandardField.BOOKTITLE, "FPGAs for Custom Computing Machines, 1994. Proceedings. IEEE Workshop on " + index); - bibEntry.setField(StandardField.YEAR, "199" + index); - bibEntry.setCiteKey("nanoproc199" + index); - return bibEntry; } - public void clear(DBMSConnection dbmsConnection) throws SQLException { - TestManager.clearTables(dbmsConnection); - } } diff --git a/src/test/java/org/jabref/logic/shared/TestConnector.java b/src/test/java/org/jabref/logic/shared/TestConnector.java index 78f078ce2f9a..ff72457dd4de 100644 --- a/src/test/java/org/jabref/logic/shared/TestConnector.java +++ b/src/test/java/org/jabref/logic/shared/TestConnector.java @@ -6,6 +6,9 @@ import org.jabref.model.database.shared.DBMSType; import org.jabref.testutils.category.DatabaseTest; +/** + * Stores the credentials for the test systems + */ @DatabaseTest public class TestConnector { @@ -15,18 +18,15 @@ public static DBMSConnection getTestDBMSConnection(DBMSType dbmsType) throws SQL } public static DBMSConnectionProperties getTestConnectionProperties(DBMSType dbmsType) { - if (dbmsType == DBMSType.MYSQL) { - return new DBMSConnectionProperties(dbmsType, "localhost", dbmsType.getDefaultPort(), "jabref", "root", "", false, ""); + switch (dbmsType) { + case MYSQL: + return new DBMSConnectionProperties(dbmsType, "127.0.0.1", 3800, "jabref", "root", "root", false, ""); + case POSTGRESQL: + return new DBMSConnectionProperties(dbmsType, "localhost", dbmsType.getDefaultPort(), "postgres", "postgres", "postgres", false, ""); + case ORACLE: + return new DBMSConnectionProperties(dbmsType, "localhost", dbmsType.getDefaultPort(), "xe", "travis", "travis", false, ""); + default: + return new DBMSConnectionProperties(); } - - if (dbmsType == DBMSType.POSTGRESQL) { - return new DBMSConnectionProperties(dbmsType, "localhost", dbmsType.getDefaultPort(), "jabref", "postgres", "", false, ""); - } - - if (dbmsType == DBMSType.ORACLE) { - return new DBMSConnectionProperties(dbmsType, "localhost", dbmsType.getDefaultPort(), "xe", "travis", "travis", false, ""); - } - - return new DBMSConnectionProperties(); } } diff --git a/src/test/java/org/jabref/logic/shared/TestManager.java b/src/test/java/org/jabref/logic/shared/TestManager.java index 2b8f1f4d2f50..f49d226157c0 100644 --- a/src/test/java/org/jabref/logic/shared/TestManager.java +++ b/src/test/java/org/jabref/logic/shared/TestManager.java @@ -1,13 +1,8 @@ package org.jabref.logic.shared; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Stream; +import java.util.Objects; -import org.jabref.logic.shared.exception.InvalidDBMSConnectionPropertiesException; import org.jabref.model.database.shared.DBMSType; /** @@ -16,21 +11,15 @@ */ public class TestManager { - public static Collection getDBMSTypeTestParameter() { - - Set dbmsTypes = new HashSet<>(); - for (DBMSType dbmsType : DBMSType.values()) { - try { - TestConnector.getTestDBMSConnection(dbmsType); - dbmsTypes.add(dbmsType); - } catch (SQLException | InvalidDBMSConnectionPropertiesException e) { - // skip parameter - } - } - return dbmsTypes; + /** + * Determine the DBMSType to test from the environment variable "DMBS". In case that variable is not set, use "PostgreSQL" as default + */ + public static DBMSType getDBMSTypeTestParameter() { + return DBMSType.fromString(System.getenv("DBMS")).orElse(DBMSType.POSTGRESQL); } public static void clearTables(DBMSConnection dbmsConnection) throws SQLException { + Objects.requireNonNull(dbmsConnection); DBMSType dbmsType = dbmsConnection.getProperties().getType(); if (dbmsType == DBMSType.MYSQL) { @@ -51,14 +40,4 @@ public static void clearTables(DBMSConnection dbmsConnection) throws SQLExceptio } } - static Stream getTestingDatabaseSystems() throws InvalidDBMSConnectionPropertiesException, SQLException { - Collection result = new ArrayList<>(); - for (DBMSType dbmsType : getDBMSTypeTestParameter()) { - result.add(new Object[]{ - dbmsType, - TestConnector.getTestDBMSConnection(dbmsType), - DBMSProcessor.getProcessorInstance(TestConnector.getTestDBMSConnection(dbmsType))}); - } - return result.stream(); - } } diff --git a/src/test/java/org/jabref/model/entry/CanonicalBibEntryTest.java b/src/test/java/org/jabref/model/entry/CanonicalBibEntryTest.java index 6d6921128717..2bae22881675 100644 --- a/src/test/java/org/jabref/model/entry/CanonicalBibEntryTest.java +++ b/src/test/java/org/jabref/model/entry/CanonicalBibEntryTest.java @@ -14,7 +14,8 @@ void canonicalRepresentationIsCorrectForStringMonth() { BibEntry entry = new BibEntry(); entry.setMonth(Month.MAY); assertEquals("@misc{,\n" + - " month = {#may#}\n" + + " month = {#may#},\n" + + " _jabref_shared = {sharedId: -1, version: 1}\n" + "}", CanonicalBibEntry.getCanonicalRepresentation(entry)); } @@ -26,7 +27,7 @@ public void simpleCanonicalRepresentation() { e.setField(StandardField.TITLE, "def"); e.setField(StandardField.JOURNAL, "hij"); String canonicalRepresentation = CanonicalBibEntry.getCanonicalRepresentation(e); - assertEquals("@article{key,\n author = {abc},\n journal = {hij},\n title = {def}\n}", + assertEquals("@article{key,\n author = {abc},\n journal = {hij},\n title = {def},\n _jabref_shared = {sharedId: -1, version: 1}\n}", canonicalRepresentation); } @@ -36,6 +37,6 @@ public void canonicalRepresentationWithNewlines() { e.setCiteKey("key"); e.setField(StandardField.ABSTRACT, "line 1\nline 2"); String canonicalRepresentation = CanonicalBibEntry.getCanonicalRepresentation(e); - assertEquals("@article{key,\n abstract = {line 1\nline 2}\n}", canonicalRepresentation); + assertEquals("@article{key,\n abstract = {line 1\nline 2},\n _jabref_shared = {sharedId: -1, version: 1}\n}", canonicalRepresentation); } }