deps: Refactor dependencies (#3224)

* remove spring dep
move junit, logging, mockito under dep mgmt

* upgrade anti-corruption-layer deps

* async method invocation

* balking, bloc

* bridge to bytecode

* caching

* callback - cqrs

* component - health check

* hexagonal - metadata mapping

* rest of the patterns

* remove checkstyle, take spotless into use
This commit is contained in:
Ilkka Seppälä
2025-03-29 19:34:27 +02:00
committed by GitHub
parent 371439aeaa
commit 0ca162a55c
1863 changed files with 14408 additions and 17637 deletions
@@ -29,59 +29,44 @@ import com.iluwatar.caching.database.DbManagerFactory;
import lombok.extern.slf4j.Slf4j;
/**
* The Caching pattern describes how to avoid expensive re-acquisition of
* resources by not releasing the resources immediately after their use.
* The resources retain their identity, are kept in some fast-access storage,
* and are re-used to avoid having to acquire them again. There are four main
* caching strategies/techniques in this pattern; each with their own pros and
* cons. They are <code>write-through</code> which writes data to the cache and
* DB in a single transaction, <code>write-around</code> which writes data
* immediately into the DB instead of the cache, <code>write-behind</code>
* which writes data into the cache initially whilst the data is only
* written into the DB when the cache is full, and <code>cache-aside</code>
* which pushes the responsibility of keeping the data synchronized in both
* data sources to the application itself. The <code>read-through</code>
* strategy is also included in the mentioned four strategies --
* returns data from the cache to the caller <b>if</b> it exists <b>else</b>
* queries from DB and stores it into the cache for future use. These strategies
* determine when the data in the cache should be written back to the backing
* store (i.e. Database) and help keep both data sources
* synchronized/up-to-date. This pattern can improve performance and also helps
* to maintainconsistency between data held in the cache and the data in
* the underlying data store.
* The Caching pattern describes how to avoid expensive re-acquisition of resources by not releasing
* the resources immediately after their use. The resources retain their identity, are kept in some
* fast-access storage, and are re-used to avoid having to acquire them again. There are four main
* caching strategies/techniques in this pattern; each with their own pros and cons. They are <code>
* write-through</code> which writes data to the cache and DB in a single transaction, <code>
* write-around</code> which writes data immediately into the DB instead of the cache, <code>
* write-behind</code> which writes data into the cache initially whilst the data is only written
* into the DB when the cache is full, and <code>cache-aside</code> which pushes the responsibility
* of keeping the data synchronized in both data sources to the application itself. The <code>
* read-through</code> strategy is also included in the mentioned four strategies -- returns data
* from the cache to the caller <b>if</b> it exists <b>else</b> queries from DB and stores it into
* the cache for future use. These strategies determine when the data in the cache should be written
* back to the backing store (i.e. Database) and help keep both data sources
* synchronized/up-to-date. This pattern can improve performance and also helps to
* maintainconsistency between data held in the cache and the data in the underlying data store.
*
* <p>In this example, the user account ({@link UserAccount}) entity is used
* as the underlying application data. The cache itself is implemented as an
* internal (Java) data structure. It adopts a Least-Recently-Used (LRU)
* strategy for evicting data from itself when its full. The four
* strategies are individually tested. The testing of the cache is restricted
* towards saving and querying of user accounts from the
* underlying data store( {@link DbManager}). The main class ( {@link App}
* is not aware of the underlying mechanics of the application
* (i.e. save and query) and whether the data is coming from the cache or the
* DB (i.e. separation of concern). The AppManager ({@link AppManager}) handles
* the transaction of data to-and-from the underlying data store (depending on
* the preferred caching policy/strategy).
* <p>
* <i>{@literal App --> AppManager --> CacheStore/LRUCache/CachingPolicy -->
* DBManager} </i>
* </p>
* <p>In this example, the user account ({@link UserAccount}) entity is used as the underlying
* application data. The cache itself is implemented as an internal (Java) data structure. It adopts
* a Least-Recently-Used (LRU) strategy for evicting data from itself when its full. The four
* strategies are individually tested. The testing of the cache is restricted towards saving and
* querying of user accounts from the underlying data store( {@link DbManager}). The main class (
* {@link App} is not aware of the underlying mechanics of the application (i.e. save and query) and
* whether the data is coming from the cache or the DB (i.e. separation of concern). The AppManager
* ({@link AppManager}) handles the transaction of data to-and-from the underlying data store
* (depending on the preferred caching policy/strategy).
*
* <p>
* There are 2 ways to launch the application.
* - to use "in Memory" database.
* - to use the MongoDb as a database
* <p><i>{@literal App --> AppManager --> CacheStore/LRUCache/CachingPolicy --> DBManager} </i>
*
* To run the application with "in Memory" database, just launch it without parameters
* Example: 'java -jar app.jar'
* <p>There are 2 ways to launch the application. - to use "in Memory" database. - to use the
* MongoDb as a database
*
* To run the application with MongoDb you need to be installed the MongoDb
* in your system, or to launch it in the docker container.
* You may launch docker container from the root of current module with command:
* 'docker-compose up'
* Then you can start the application with parameter --mongo
* Example: 'java -jar app.jar --mongo'
* </p>
* <p>To run the application with "in Memory" database, just launch it without parameters Example:
* 'java -jar app.jar'
*
* <p>To run the application with MongoDb you need to be installed the MongoDb in your system, or to
* launch it in the docker container. You may launch docker container from the root of current
* module with command: 'docker-compose up' Then you can start the application with parameter
* --mongo Example: 'java -jar app.jar --mongo'
*
* @see CacheStore
* @see LruCache
@@ -89,13 +74,10 @@ import lombok.extern.slf4j.Slf4j;
*/
@Slf4j
public class App {
/**
* Constant parameter name to use mongoDB.
*/
/** Constant parameter name to use mongoDB. */
private static final String USE_MONGO_DB = "--mongo";
/**
* Application manager.
*/
/** Application manager. */
private final AppManager appManager;
/**
@@ -152,9 +134,7 @@ public class App {
return false;
}
/**
* Read-through and write-through.
*/
/** Read-through and write-through. */
public void useReadAndWriteThroughStrategy() {
LOGGER.info("# CachingPolicy.THROUGH");
appManager.initCachingPolicy(CachingPolicy.THROUGH);
@@ -167,9 +147,7 @@ public class App {
appManager.find("001");
}
/**
* Read-through and write-around.
*/
/** Read-through and write-around. */
public void useReadThroughAndWriteAroundStrategy() {
LOGGER.info("# CachingPolicy.AROUND");
appManager.initCachingPolicy(CachingPolicy.AROUND);
@@ -189,22 +167,14 @@ public class App {
appManager.find("002");
}
/**
* Read-through and write-behind.
*/
/** Read-through and write-behind. */
public void useReadThroughAndWriteBehindStrategy() {
LOGGER.info("# CachingPolicy.BEHIND");
appManager.initCachingPolicy(CachingPolicy.BEHIND);
var userAccount3 = new UserAccount("003",
"Adam",
"He likes food.");
var userAccount4 = new UserAccount("004",
"Rita",
"She hates cats.");
var userAccount5 = new UserAccount("005",
"Isaac",
"He is allergic to mustard.");
var userAccount3 = new UserAccount("003", "Adam", "He likes food.");
var userAccount4 = new UserAccount("004", "Rita", "She hates cats.");
var userAccount5 = new UserAccount("005", "Isaac", "He is allergic to mustard.");
appManager.save(userAccount3);
appManager.save(userAccount4);
@@ -212,32 +182,22 @@ public class App {
LOGGER.info(appManager.printCacheContent());
appManager.find("003");
LOGGER.info(appManager.printCacheContent());
UserAccount userAccount6 = new UserAccount("006",
"Yasha",
"She is an only child.");
UserAccount userAccount6 = new UserAccount("006", "Yasha", "She is an only child.");
appManager.save(userAccount6);
LOGGER.info(appManager.printCacheContent());
appManager.find("004");
LOGGER.info(appManager.printCacheContent());
}
/**
* Cache-Aside.
*/
/** Cache-Aside. */
public void useCacheAsideStrategy() {
LOGGER.info("# CachingPolicy.ASIDE");
appManager.initCachingPolicy(CachingPolicy.ASIDE);
LOGGER.info(appManager.printCacheContent());
var userAccount3 = new UserAccount("003",
"Adam",
"He likes food.");
var userAccount4 = new UserAccount("004",
"Rita",
"She hates cats.");
var userAccount5 = new UserAccount("005",
"Isaac",
"He is allergic to mustard.");
var userAccount3 = new UserAccount("003", "Adam", "He likes food.");
var userAccount4 = new UserAccount("004", "Rita", "She hates cats.");
var userAccount5 = new UserAccount("005", "Isaac", "He is allergic to mustard.");
appManager.save(userAccount3);
appManager.save(userAccount4);
appManager.save(userAccount5);
@@ -29,26 +29,21 @@ import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
/**
* AppManager helps to bridge the gap in communication between the main class
* and the application's back-end. DB connection is initialized through this
* class. The chosen caching strategy/policy is also initialized here.
* Before the cache can be used, the size of the cache has to be set.
* Depending on the chosen caching policy, AppManager will call the
* appropriate function in the CacheStore class.
* AppManager helps to bridge the gap in communication between the main class and the application's
* back-end. DB connection is initialized through this class. The chosen caching strategy/policy is
* also initialized here. Before the cache can be used, the size of the cache has to be set.
* Depending on the chosen caching policy, AppManager will call the appropriate function in the
* CacheStore class.
*/
@Slf4j
public class AppManager {
/**
* Caching Policy.
*/
/** Caching Policy. */
private CachingPolicy cachingPolicy;
/**
* Database Manager.
*/
/** Database Manager. */
private final DbManager dbManager;
/**
* Cache Store.
*/
/** Cache Store. */
private final CacheStore cacheStore;
/**
@@ -62,9 +57,9 @@ public class AppManager {
}
/**
* Developer/Tester is able to choose whether the application should use
* MongoDB as its underlying data storage or a simple Java data structure
* to (temporarily) store the data/objects during runtime.
* Developer/Tester is able to choose whether the application should use MongoDB as its underlying
* data storage or a simple Java data structure to (temporarily) store the data/objects during
* runtime.
*/
public void initDb() {
dbManager.connect();
@@ -91,8 +86,7 @@ public class AppManager {
*/
public UserAccount find(final String userId) {
LOGGER.info("Trying to find {} in cache", userId);
if (cachingPolicy == CachingPolicy.THROUGH
|| cachingPolicy == CachingPolicy.AROUND) {
if (cachingPolicy == CachingPolicy.THROUGH || cachingPolicy == CachingPolicy.AROUND) {
return cacheStore.readThrough(userId);
} else if (cachingPolicy == CachingPolicy.BEHIND) {
return cacheStore.readThroughWithWriteBackPolicy(userId);
@@ -147,12 +141,12 @@ public class AppManager {
*/
private UserAccount findAside(final String userId) {
return Optional.ofNullable(cacheStore.get(userId))
.or(() -> {
Optional<UserAccount> userAccount =
Optional.ofNullable(dbManager.readFromDb(userId));
.or(
() -> {
Optional<UserAccount> userAccount = Optional.ofNullable(dbManager.readFromDb(userId));
userAccount.ifPresent(account -> cacheStore.set(userId, account));
return userAccount;
})
.orElse(null);
.orElse(null);
}
}
@@ -30,27 +30,21 @@ import java.util.Optional;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
/**
* The caching strategies are implemented in this class.
*/
/** The caching strategies are implemented in this class. */
@Slf4j
public class CacheStore {
/**
* Cache capacity.
*/
/** Cache capacity. */
private static final int CAPACITY = 3;
/**
* Lru cache see {@link LruCache}.
*/
/** Lru cache see {@link LruCache}. */
private LruCache cache;
/**
* DbManager.
*/
/** DbManager. */
private final DbManager dbManager;
/**
* Cache Store.
*
* @param dataBaseManager {@link DbManager}
*/
public CacheStore(final DbManager dataBaseManager) {
@@ -60,6 +54,7 @@ public class CacheStore {
/**
* Init cache capacity.
*
* @param capacity int
*/
public void initCapacity(final int capacity) {
@@ -72,6 +67,7 @@ public class CacheStore {
/**
* Get user account using read-through cache.
*
* @param userId {@link String}
* @return {@link UserAccount}
*/
@@ -88,6 +84,7 @@ public class CacheStore {
/**
* Get user account using write-through cache.
*
* @param userAccount {@link UserAccount}
*/
public void writeThrough(final UserAccount userAccount) {
@@ -101,6 +98,7 @@ public class CacheStore {
/**
* Get user account using write-around cache.
*
* @param userAccount {@link UserAccount}
*/
public void writeAround(final UserAccount userAccount) {
@@ -116,6 +114,7 @@ public class CacheStore {
/**
* Get user account using read-through cache with write-back policy.
*
* @param userId {@link String}
* @return {@link UserAccount}
*/
@@ -137,6 +136,7 @@ public class CacheStore {
/**
* Set user account.
*
* @param userAccount {@link UserAccount}
*/
public void writeBehind(final UserAccount userAccount) {
@@ -148,18 +148,14 @@ public class CacheStore {
cache.set(userAccount.getUserId(), userAccount);
}
/**
* Clears cache.
*/
/** Clears cache. */
public void clearCache() {
if (cache != null) {
cache.clear();
}
}
/**
* Writes remaining content in the cache into the DB.
*/
/** Writes remaining content in the cache into the DB. */
public void flushCache() {
LOGGER.info("# flushCache...");
Optional.ofNullable(cache)
@@ -171,6 +167,7 @@ public class CacheStore {
/**
* Print user accounts.
*
* @return {@link String}
*/
public String print() {
@@ -184,6 +181,7 @@ public class CacheStore {
/**
* Delegate to backing cache store.
*
* @param userId {@link String}
* @return {@link UserAccount}
*/
@@ -193,6 +191,7 @@ public class CacheStore {
/**
* Delegate to backing cache store.
*
* @param userId {@link String}
* @param userAccount {@link UserAccount}
*/
@@ -202,6 +201,7 @@ public class CacheStore {
/**
* Delegate to backing cache store.
*
* @param userId {@link String}
*/
public void invalidate(final String userId) {
@@ -27,31 +27,19 @@ package com.iluwatar.caching;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Enum class containing the four caching strategies implemented in the pattern.
*/
/** Enum class containing the four caching strategies implemented in the pattern. */
@AllArgsConstructor
@Getter
public enum CachingPolicy {
/**
* Through.
*/
/** Through. */
THROUGH("through"),
/**
* AROUND.
*/
/** AROUND. */
AROUND("around"),
/**
* BEHIND.
*/
/** BEHIND. */
BEHIND("behind"),
/**
* ASIDE.
*/
/** ASIDE. */
ASIDE("aside");
/**
* Policy value.
*/
/** Policy value. */
private final String policy;
}
@@ -30,42 +30,33 @@ import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
/**
* Data structure/implementation of the application's cache. The data structure
* consists of a hash table attached with a doubly linked-list. The linked-list
* helps in capturing and maintaining the LRU data in the cache. When a data is
* queried (from the cache), added (to the cache), or updated, the data is
* moved to the front of the list to depict itself as the most-recently-used
* data. The LRU data is always at the end of the list.
* Data structure/implementation of the application's cache. The data structure consists of a hash
* table attached with a doubly linked-list. The linked-list helps in capturing and maintaining the
* LRU data in the cache. When a data is queried (from the cache), added (to the cache), or updated,
* the data is moved to the front of the list to depict itself as the most-recently-used data. The
* LRU data is always at the end of the list.
*/
@Slf4j
public class LruCache {
/**
* Static class Node.
*/
/** Static class Node. */
static class Node {
/**
* user id.
*/
/** user id. */
private final String userId;
/**
* User Account.
*/
/** User Account. */
private UserAccount userAccount;
/**
* previous.
*/
/** previous. */
private Node previous;
/**
* next.
*/
/** next. */
private Node next;
/**
* Node definition.
*
* @param id String
* @param id String
* @param account {@link UserAccount}
*/
Node(final String id, final UserAccount account) {
@@ -74,21 +65,16 @@ public class LruCache {
}
}
/**
* Capacity of Cache.
*/
/** Capacity of Cache. */
private int capacity;
/**
* Cache {@link HashMap}.
*/
/** Cache {@link HashMap}. */
private Map<String, Node> cache = new HashMap<>();
/**
* Head.
*/
/** Head. */
private Node head;
/**
* End.
*/
/** End. */
private Node end;
/**
@@ -155,7 +141,7 @@ public class LruCache {
* Set user account.
*
* @param userAccount {@link UserAccount}
* @param userId {@link String}
* @param userId {@link String}
*/
public void set(final String userId, final UserAccount userAccount) {
if (cache.containsKey(userId)) {
@@ -195,14 +181,14 @@ public class LruCache {
public void invalidate(final String userId) {
var toBeRemoved = cache.remove(userId);
if (toBeRemoved != null) {
LOGGER.info("# {} has been updated! "
+ "Removing older version from cache...", userId);
LOGGER.info("# {} has been updated! " + "Removing older version from cache...", userId);
remove(toBeRemoved);
}
}
/**
* Check if the cache is full.
*
* @return boolean
*/
public boolean isFull() {
@@ -218,9 +204,7 @@ public class LruCache {
return end.userAccount;
}
/**
* Clear cache.
*/
/** Clear cache. */
public void clear() {
head = null;
end = null;
@@ -29,24 +29,18 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
/**
* Entity class (stored in cache and DB) used in the application.
*/
/** Entity class (stored in cache and DB) used in the application. */
@Data
@AllArgsConstructor
@ToString
@EqualsAndHashCode
public class UserAccount {
/**
* User Id.
*/
/** User Id. */
private String userId;
/**
* User Name.
*/
/** User Name. */
private String userName;
/**
* Additional Info.
*/
/** Additional Info. */
private String additionalInfo;
}
@@ -24,30 +24,20 @@
*/
package com.iluwatar.caching.constants;
/**
* Constant class for defining constants.
*/
/** Constant class for defining constants. */
public final class CachingConstants {
/**
* User Account.
*/
/** User Account. */
public static final String USER_ACCOUNT = "user_accounts";
/**
* User ID.
*/
/** User ID. */
public static final String USER_ID = "userID";
/**
* User Name.
*/
/** User Name. */
public static final String USER_NAME = "userName";
/**
* Additional Info.
*/
/** Additional Info. */
public static final String ADD_INFO = "additionalInfo";
/**
* Constructor.
*/
private CachingConstants() {
}
/** Constructor. */
private CachingConstants() {}
}
@@ -22,7 +22,5 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* Constants.
*/
/** Constants. */
package com.iluwatar.caching.constants;
@@ -27,19 +27,15 @@ package com.iluwatar.caching.database;
import com.iluwatar.caching.UserAccount;
/**
* <p>DBManager handles the communication with the underlying data store i.e.
* Database. It contains the implemented methods for querying, inserting,
* and updating data. MongoDB was used as the database for the application.</p>
* DBManager handles the communication with the underlying data store i.e. Database. It contains the
* implemented methods for querying, inserting, and updating data. MongoDB was used as the database
* for the application.
*/
public interface DbManager {
/**
* Connect to DB.
*/
/** Connect to DB. */
void connect();
/**
* Disconnect from DB.
*/
/** Disconnect from DB. */
void disconnect();
/**
@@ -24,15 +24,10 @@
*/
package com.iluwatar.caching.database;
/**
* Creates the database connection according the input parameter.
*/
/** Creates the database connection according the input parameter. */
public final class DbManagerFactory {
/**
* Private constructor.
*/
private DbManagerFactory() {
}
/** Private constructor. */
private DbManagerFactory() {}
/**
* Init database.
@@ -40,10 +40,7 @@ import com.mongodb.client.model.UpdateOptions;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
/**
* Implementation of DatabaseManager.
* implements base methods to work with MongoDb.
*/
/** Implementation of DatabaseManager. implements base methods to work with MongoDb. */
@Slf4j
public class MongoDb implements DbManager {
private static final String DATABASE_NAME = "admin";
@@ -56,14 +53,11 @@ public class MongoDb implements DbManager {
this.db = db;
}
/**
* Connect to Db. Check th connection
*/
/** Connect to Db. Check th connection */
@Override
public void connect() {
MongoCredential mongoCredential = MongoCredential.createCredential(MONGO_USER,
DATABASE_NAME,
MONGO_PASSWORD.toCharArray());
MongoCredential mongoCredential =
MongoCredential.createCredential(MONGO_USER, DATABASE_NAME, MONGO_PASSWORD.toCharArray());
MongoClientOptions options = MongoClientOptions.builder().build();
client = new MongoClient(new ServerAddress(), mongoCredential, options);
db = client.getDatabase(DATABASE_NAME);
@@ -82,9 +76,8 @@ public class MongoDb implements DbManager {
*/
@Override
public UserAccount readFromDb(final String userId) {
var iterable = db
.getCollection(CachingConstants.USER_ACCOUNT)
.find(new Document(USER_ID, userId));
var iterable =
db.getCollection(CachingConstants.USER_ACCOUNT).find(new Document(USER_ID, userId));
if (iterable.first() == null) {
return null;
}
@@ -106,11 +99,11 @@ public class MongoDb implements DbManager {
*/
@Override
public UserAccount writeToDb(final UserAccount userAccount) {
db.getCollection(USER_ACCOUNT).insertOne(
db.getCollection(USER_ACCOUNT)
.insertOne(
new Document(USER_ID, userAccount.getUserId())
.append(USER_NAME, userAccount.getUserName())
.append(ADD_INFO, userAccount.getAdditionalInfo())
);
.append(USER_NAME, userAccount.getUserName())
.append(ADD_INFO, userAccount.getAdditionalInfo()));
return userAccount;
}
@@ -123,10 +116,10 @@ public class MongoDb implements DbManager {
@Override
public UserAccount updateDb(final UserAccount userAccount) {
Document id = new Document(USER_ID, userAccount.getUserId());
Document dataSet = new Document(USER_NAME, userAccount.getUserName())
Document dataSet =
new Document(USER_NAME, userAccount.getUserName())
.append(ADD_INFO, userAccount.getAdditionalInfo());
db.getCollection(CachingConstants.USER_ACCOUNT)
.updateOne(id, new Document("$set", dataSet));
db.getCollection(CachingConstants.USER_ACCOUNT).updateOne(id, new Document("$set", dataSet));
return userAccount;
}
@@ -141,15 +134,15 @@ public class MongoDb implements DbManager {
String userId = userAccount.getUserId();
String userName = userAccount.getUserName();
String additionalInfo = userAccount.getAdditionalInfo();
db.getCollection(CachingConstants.USER_ACCOUNT).updateOne(
db.getCollection(CachingConstants.USER_ACCOUNT)
.updateOne(
new Document(USER_ID, userId),
new Document("$set",
new Document(USER_ID, userId)
.append(USER_NAME, userName)
.append(ADD_INFO, additionalInfo)
),
new UpdateOptions().upsert(true)
);
new Document(
"$set",
new Document(USER_ID, userId)
.append(USER_NAME, userName)
.append(ADD_INFO, additionalInfo)),
new UpdateOptions().upsert(true));
return userAccount;
}
}
@@ -28,19 +28,12 @@ import com.iluwatar.caching.UserAccount;
import java.util.HashMap;
import java.util.Map;
/**
* Implementation of DatabaseManager.
* implements base methods to work with hashMap as database.
*/
/** Implementation of DatabaseManager. implements base methods to work with hashMap as database. */
public class VirtualDb implements DbManager {
/**
* Virtual DataBase.
*/
/** Virtual DataBase. */
private Map<String, UserAccount> db;
/**
* Creates new HashMap.
*/
/** Creates new HashMap. */
@Override
public void connect() {
db = new HashMap<>();
@@ -22,7 +22,5 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* Database classes.
*/
/** Database classes. */
package com.iluwatar.caching.database;
@@ -24,23 +24,20 @@
*/
package com.iluwatar.caching;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
/**
* Tests that Caching example runs without errors.
*/
import org.junit.jupiter.api.Test;
/** Tests that Caching example runs without errors. */
class AppTest {
/**
* Issue: Add at least one assertion to this test case.
* <p>
* Solution: Inserted assertion to check whether the execution of the main method in {@link App}
* throws an exception.
*
* <p>Solution: Inserted assertion to check whether the execution of the main method in {@link
* App} throws an exception.
*/
@Test
void shouldExecuteApplicationWithoutException() {
assertDoesNotThrow(() -> App.main(new String[]{}));
assertDoesNotThrow(() -> App.main(new String[] {}));
}
}
@@ -24,20 +24,16 @@
*/
package com.iluwatar.caching;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNotNull;
/**
* Application test
*/
/** Application test */
class CachingTest {
private App app;
/**
* Setup of application test includes: initializing DB connection and cache size/capacity.
*/
/** Setup of application test includes: initializing DB connection and cache size/capacity. */
@BeforeEach
void setUp() {
// VirtualDB (instead of MongoDB) was used in running the JUnit tests
@@ -24,6 +24,13 @@
*/
package com.iluwatar.caching.database;
import static com.iluwatar.caching.constants.CachingConstants.ADD_INFO;
import static com.iluwatar.caching.constants.CachingConstants.USER_ID;
import static com.iluwatar.caching.constants.CachingConstants.USER_NAME;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;
import com.iluwatar.caching.UserAccount;
import com.iluwatar.caching.constants.CachingConstants;
import com.mongodb.client.FindIterable;
@@ -34,20 +41,12 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import static com.iluwatar.caching.constants.CachingConstants.ADD_INFO;
import static com.iluwatar.caching.constants.CachingConstants.USER_ID;
import static com.iluwatar.caching.constants.CachingConstants.USER_NAME;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;
class MongoDbTest {
private static final String ID = "123";
private static final String NAME = "Some user";
private static final String ADDITIONAL_INFO = "Some app Info";
@Mock
MongoDatabase db;
@Mock MongoDatabase db;
private MongoDb mongoDb = new MongoDb();
private UserAccount userAccount;
@@ -66,9 +65,8 @@ class MongoDbTest {
@Test
void readFromDb() {
Document document = new Document(USER_ID, ID)
.append(USER_NAME, NAME)
.append(ADD_INFO, ADDITIONAL_INFO);
Document document =
new Document(USER_ID, ID).append(USER_NAME, NAME).append(ADD_INFO, ADDITIONAL_INFO);
MongoCollection<Document> mongoCollection = mock(MongoCollection.class);
when(db.getCollection(CachingConstants.USER_ACCOUNT)).thenReturn(mongoCollection);
@@ -77,27 +75,36 @@ class MongoDbTest {
when(findIterable.first()).thenReturn(document);
assertEquals(mongoDb.readFromDb(ID),userAccount);
assertEquals(mongoDb.readFromDb(ID), userAccount);
}
@Test
void writeToDb() {
MongoCollection<Document> mongoCollection = mock(MongoCollection.class);
when(db.getCollection(CachingConstants.USER_ACCOUNT)).thenReturn(mongoCollection);
assertDoesNotThrow(()-> {mongoDb.writeToDb(userAccount);});
assertDoesNotThrow(
() -> {
mongoDb.writeToDb(userAccount);
});
}
@Test
void updateDb() {
MongoCollection<Document> mongoCollection = mock(MongoCollection.class);
when(db.getCollection(CachingConstants.USER_ACCOUNT)).thenReturn(mongoCollection);
assertDoesNotThrow(()-> {mongoDb.updateDb(userAccount);});
assertDoesNotThrow(
() -> {
mongoDb.updateDb(userAccount);
});
}
@Test
void upsertDb() {
MongoCollection<Document> mongoCollection = mock(MongoCollection.class);
when(db.getCollection(CachingConstants.USER_ACCOUNT)).thenReturn(mongoCollection);
assertDoesNotThrow(()-> {mongoDb.upsertDb(userAccount);});
assertDoesNotThrow(
() -> {
mongoDb.upsertDb(userAccount);
});
}
}
}