Skip to content

Commit

Permalink
Issue 25184 adding systemtable resource (#25470)
Browse files Browse the repository at this point in the history
* #25184 adding first draft for the system table

* #25184 factory interface done

* #25184 factory first test done

* #25184 factory more test

* #25184 adding the first implementation of the factory and script sql

* #25184 getting done factory

* #25184 getting done factory

* #25184 getting done factory

* #25184 UT and more testing

* #25184  more testing

* #25184  refactor sql script

* #25184 adding upgrade task unit test

* #25184 adding system api

* #25184 adding the system table resource

* #25184 adding the system table resource

* #25184 black white list and postman test done

* #25184 fixes and feedback

* #25184 adding more feedback

* #25184 fixing an unit test

* #25184 fixing unit test
  • Loading branch information
jdotcms authored Jul 24, 2023
1 parent 4f314e4 commit cbed375
Show file tree
Hide file tree
Showing 26 changed files with 1,834 additions and 5 deletions.
528 changes: 528 additions & 0 deletions dotCMS/src/curl-test/SystemTable.postman_collection.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.dotcms.enterprise.LicenseUtil;
import com.dotcms.enterprise.license.LicenseLevel;
import com.dotcms.repackage.net.sf.hibernate.HibernateException;
import com.dotcms.util.ReturnableDelegate;
import com.dotcms.util.VoidDelegate;
import com.dotmarketing.beans.Host;
import com.dotmarketing.business.APILocator;
Expand All @@ -28,7 +29,6 @@
import java.io.File;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.junit.After;
Expand Down Expand Up @@ -259,4 +259,20 @@ protected void initConnection() {
DbConnectionFactory.closeSilently(); // start always we a new one
}
}
}

/**
* Wrap the Delegate into a method db read method, that will close the connection at the end
* @param supplier
* @return
* @param <T>
* @throws Throwable
*/
protected <T> T wrapOnReadOnlyConn(final ReturnableDelegate<T> supplier) throws Throwable {

try {
return supplier.execute();
} finally {
DbConnectionFactory.closeSilently();
}
}
}
6 changes: 6 additions & 0 deletions dotCMS/src/integration-test/java/com/dotcms/MainSuite2b.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.dotcms.auth.providers.saml.v1.DotSamlResourceTest;
import com.dotcms.auth.providers.saml.v1.SAMLHelperTest;
import com.dotcms.bayesian.BayesianAPIImplIT;
import com.dotcms.business.SystemAPITest;
import com.dotcms.business.SystemTableFactoryTest;
import com.dotcms.cache.lettuce.DotObjectCodecTest;
import com.dotcms.cache.lettuce.LettuceCacheTest;
import com.dotcms.cache.lettuce.RedisClientTest;
Expand Down Expand Up @@ -141,6 +143,7 @@
import com.dotmarketing.startup.runonce.Task230110MakeSomeSystemFieldsRemovableByBaseTypeTest;
import com.dotmarketing.startup.runonce.Task230328AddMarkedForDeletionColumnTest;
import com.dotmarketing.startup.runonce.Task230426AlterVarcharLengthOfLockedByColTest;
import com.dotmarketing.startup.runonce.Task230707CreateSystemTableTest;
import com.dotmarketing.startup.runonce.Task230701AddHashIndicesToWorkflowTablesTest;
import com.dotmarketing.startup.runonce.Task230713IncreaseDisabledWysiwygColumnSizeTest;
import com.dotmarketing.startup.runonce.Task230523CreateVariantFieldInContentletIntegrationTest;
Expand Down Expand Up @@ -305,6 +308,9 @@
Task230426AlterVarcharLengthOfLockedByColTest.class,
AssetPathResolverImplIntegrationTest.class,
WebAssetHelperIntegrationTest.class,
SystemTableFactoryTest.class,
Task230707CreateSystemTableTest.class,
SystemAPITest.class,
Task230701AddHashIndicesToWorkflowTablesTest.class,
Task230713IncreaseDisabledWysiwygColumnSizeTest.class,
ContentPageIntegrityCheckerTest.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package com.dotcms.business;

import com.dotcms.IntegrationTestBase;
import com.dotcms.exception.ExceptionUtil;
import com.dotcms.util.IntegrationTestInitService;
import com.dotmarketing.business.APILocator;
import com.dotmarketing.db.LocalTransaction;
import com.dotmarketing.exception.DoesNotExistException;
import com.dotmarketing.exception.DotDuplicateDataException;
import com.dotmarketing.util.Logger;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import java.util.Map;
import java.util.Optional;

/**
* Test for the {@link SystemAPI}
* @author jsanca
*/
public class SystemAPITest extends IntegrationTestBase {

@BeforeClass
public static void prepare () throws Exception {

//Setting web app environment
IntegrationTestInitService.getInstance().init();
}

/**
* Method to test: test CRUD operations of {@link SystemTable}
* Given Scenario: Creates a key/value, query it, update it and delete it
* ExpectedResult: All operations should be successful
* @throws Throwable
*/
@Test
public void test_crud_success () throws Throwable {

final String key1 = "akey1";
final String value1 = "value1";
final String value2 = "value2";

final SystemTable systemTable = APILocator.getSystemAPI().getSystemTable();

if (null != systemTable) {

// SAVE + FIND
LocalTransaction.wrap(()->systemTable.set(key1, value1));
final Optional<String> value1FromDB = wrapOnReadOnlyConn(()->systemTable.get(key1));
Assert.assertTrue("Should return something", value1FromDB.isPresent());
Assert.assertEquals(
"The value previous added should be the same of the value recovery from the db with the key: " + key1,
value1, value1FromDB.get());

// UPDATE + FIND
LocalTransaction.wrap(()->systemTable.set(key1, value2));
final Optional<String> value2FromDB = wrapOnReadOnlyConn(()->systemTable.get(key1));
Assert.assertEquals(
"The value previous added should be the same of the value recovery from the db with the key: " + key1,
value2, value2FromDB.get());

// DELETE + FIND
LocalTransaction.wrap(()->systemTable.delete(key1));
final Optional<String> value3FromDB = wrapOnReadOnlyConn(()->systemTable.get(key1));
Assert.assertFalse("Should not return something", value3FromDB.isPresent());
}
}


/**
* Method to test: test double save constraint {@link SystemTable#save(String, String)}
* Given Scenario: Creates a key/value twice
* ExpectedResult: Should throw an exception b/c the key already exist
* @throws Throwable
*/
@Test()
public void test_double_insert () throws Throwable {

final String key1 = "akey13";
final String value1 = "value1";

final SystemTable systemTable = APILocator.getSystemAPI().getSystemTable();

if (null != systemTable) {

// SAVE + FIND
LocalTransaction.wrap(()->systemTable.set(key1, value1));
final Optional<String> value1FromDB = wrapOnReadOnlyConn(()->systemTable.get(key1));
Assert.assertTrue("Should return something", value1FromDB.isPresent());
Assert.assertEquals(
"The value previous added should be the same of the value recovery from the db with the key: " + key1,
value1, value1FromDB.get());

// this should throw an exception since the key1 already exist.
LocalTransaction.wrap(() -> systemTable.set(key1, value1));
final Optional<String> value2FromDB = wrapOnReadOnlyConn(()->systemTable.get(key1));
Assert.assertTrue("Should return something", value2FromDB.isPresent());
Assert.assertEquals(
"The value previous added should be the same of the value recovery from the db with the key: " + key1,
value1, value2FromDB.get());
}
}


/**
* Method to test: test find all {@link SystemTable#all()}
* Given Scenario: Creates a couple key/value
* ExpectedResult: Should retrieve both keys
* @throws Throwable
*/
@Test()
public void test_find_all () throws Throwable {

final String key1 = "akey11";
final String value1 = "value11";
final String key2 = "akey22";
final String value2 = "value22";

final SystemTable systemTable = APILocator.getSystemAPI().getSystemTable();

if (null != systemTable) {

try {
// SAVE + FIND
LocalTransaction.wrap(() -> systemTable.set(key1, value1));
LocalTransaction.wrap(() -> systemTable.set(key2, value2));
final Map<String, String> value1FromDB = wrapOnReadOnlyConn(() -> systemTable.all());
Assert.assertTrue("Should has key1", value1FromDB.containsKey(key1));
Assert.assertTrue("Should has key2", value1FromDB.containsKey(key2));
Assert.assertEquals(
"The value previous added should be the same of the value recovery from the db with the key: " + key1,
value1, value1FromDB.get(key1));
Assert.assertEquals(
"The value previous added should be the same of the value recovery from the db with the key: " + key2,
value2, value1FromDB.get(key2));
} finally {
try {
LocalTransaction.wrap(() -> systemTable.delete(key1));
LocalTransaction.wrap(() -> systemTable.delete(key2));
} catch (Throwable e) {
Logger.debug(this, e.getMessage());
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package com.dotcms.business;

import com.dotcms.IntegrationTestBase;
import com.dotcms.util.IntegrationTestInitService;
import com.dotmarketing.business.APILocator;
import com.dotmarketing.business.CacheLocator;
import com.dotmarketing.business.DotCacheAdministrator;
import com.dotmarketing.business.FactoryLocator;
import com.dotmarketing.db.LocalTransaction;
import com.dotmarketing.exception.DoesNotExistException;
import com.dotmarketing.exception.DotDuplicateDataException;
import com.dotmarketing.util.Logger;
import com.liferay.portal.model.User;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import java.util.Map;
import java.util.Optional;

/**
* Test for the {@link SystemTableFactory}
* @author jsanca
*/
public class SystemTableFactoryTest extends IntegrationTestBase {

private static DotCacheAdministrator cache;
private static User systemUser;

@BeforeClass
public static void prepare () throws Exception {

//Setting web app environment
IntegrationTestInitService.getInstance().init();

cache = CacheLocator.getCacheAdministrator();

//Setting the test user
systemUser = APILocator.getUserAPI().getSystemUser();
}

/**
* Method to test: test CRUD operations of {@link SystemTableFactory}
* Given Scenario: Creates a key/value, query it, update it and delete it
* ExpectedResult: All operations should be successful
* @throws Throwable
*/
@Test
public void test_crud_success () throws Throwable {

final String key1 = "key1";
final String value1 = "value1";
final String value2 = "value2";

final SystemTableFactory systemTableFactory = FactoryLocator.getSystemTableFactory();

if (null != systemTableFactory) {

systemTableFactory.clearCache();
// SAVE + FIND
LocalTransaction.wrap(()->systemTableFactory.saveOrUpdate(key1, value1));
final Optional<String> value1FromDB = wrapOnReadOnlyConn(()->systemTableFactory.find(key1));
Assert.assertTrue("Should return something", value1FromDB.isPresent());
Assert.assertEquals(
"The value previous added should be the same of the value recovery from the db with the key: " + key1,
value1, value1FromDB.get());

// UPDATE + FIND
LocalTransaction.wrap(()->systemTableFactory.saveOrUpdate(key1, value2));
final Optional<String> value2FromDB = wrapOnReadOnlyConn(()->systemTableFactory.find(key1));
Assert.assertEquals(
"The value previous added should be the same of the value recovery from the db with the key: " + key1,
value2, value2FromDB.get());

// DELETE + FIND
LocalTransaction.wrap(()->systemTableFactory.delete(key1));
final Optional<String> value3FromDB = wrapOnReadOnlyConn(()->systemTableFactory.find(key1));
Assert.assertFalse("Should not return something", value3FromDB.isPresent());
}
}


/**
* Method to test: test double save constraint {@link SystemTableFactory#save(String, String)}
* Given Scenario: Creates a key/value twice
* ExpectedResult: Should throw an exception b/c the key already exist
* @throws Throwable
*/
@Test()
public void test_double_insert () throws Throwable {

final String key1 = "key13";
final String value1 = "value1";

final SystemTableFactory systemTableFactory = FactoryLocator.getSystemTableFactory();

if (null != systemTableFactory) {

systemTableFactory.clearCache();
// SAVE + FIND
LocalTransaction.wrap(()->systemTableFactory.saveOrUpdate(key1, value1));
final Optional<String> value1FromDB = wrapOnReadOnlyConn(()->systemTableFactory.find(key1));
Assert.assertTrue("Should return something", value1FromDB.isPresent());
Assert.assertEquals(
"The value previous added should be the same of the value recovery from the db with the key: " + key1,
value1, value1FromDB.get());

// this should be an update
LocalTransaction.wrap(()->systemTableFactory.saveOrUpdate(key1, value1));
final Optional<String> value2FromDB = wrapOnReadOnlyConn(()->systemTableFactory.find(key1));
Assert.assertTrue("Should return something", value2FromDB.isPresent());
Assert.assertEquals(
"The value previous added should be the same of the value recovery from the db with the key: " + key1,
value1, value2FromDB.get());

}
}


/**
* Method to test: test find all {@link SystemTableFactory#findAll()}
* Given Scenario: Creates a couple key/value
* ExpectedResult: Should retrieve both keys
* @throws Throwable
*/
@Test()
public void test_find_all () throws Throwable {

final String key1 = "key11";
final String value1 = "value11";
final String key2 = "key22";
final String value2 = "value22";

final SystemTableFactory systemTableFactory = FactoryLocator.getSystemTableFactory();

if (null != systemTableFactory) {

try {
systemTableFactory.clearCache();
// SAVE + FIND
LocalTransaction.wrap(() -> systemTableFactory.saveOrUpdate(key1, value1));
LocalTransaction.wrap(() -> systemTableFactory.saveOrUpdate(key2, value2));
final Map<String, String> value1FromDB = wrapOnReadOnlyConn(() -> systemTableFactory.findAll());
Assert.assertTrue("Should has key1", value1FromDB.containsKey(key1));
Assert.assertTrue("Should has key2", value1FromDB.containsKey(key2));
Assert.assertEquals(
"The value previous added should be the same of the value recovery from the db with the key: " + key1,
value1, value1FromDB.get(key1));
Assert.assertEquals(
"The value previous added should be the same of the value recovery from the db with the key: " + key2,
value2, value1FromDB.get(key2));
} finally {
try {
LocalTransaction.wrap(() -> systemTableFactory.delete(key1));
LocalTransaction.wrap(() -> systemTableFactory.delete(key2));
} catch (Throwable e) {
Logger.debug(this, e.getMessage());
}
}
}
}
}
Loading

0 comments on commit cbed375

Please sign in to comment.