From d0e28d5ac41bdcb6dbd722af19a6a6cb840fbefa Mon Sep 17 00:00:00 2001
From: Antonio Scardace <33966051+antonioscardace@users.noreply.github.com>
Date: Tue, 11 Jun 2024 15:58:10 +0200
Subject: [PATCH] add: Monitor microservice
---
monitor/pom.xml | 85 ++++++++++++++++
.../netwatch/monitor/MonitorApplication.java | 21 ++++
.../monitor/config/RabbitMqConfig.java | 20 ++++
.../netwatch/monitor/config/RedisConfig.java | 46 +++++++++
.../netwatch/monitor/entities/Contact.java | 21 ++++
.../monitor/entities/Observation.java | 25 +++++
.../monitor/entities/ObservationId.java | 22 +++++
.../netwatch/monitor/entities/Utility.java | 22 +++++
.../netwatch/monitor/requests/IRequest.java | 9 ++
.../monitor/requests/PingRequest.java | 34 +++++++
.../monitor/requests/RequestCreator.java | 18 ++++
.../monitor/services/MonitorService.java | 97 +++++++++++++++++++
.../services/RabbitMqProducerService.java | 31 ++++++
.../monitor/services/RedisService.java | 41 ++++++++
.../netwatch/monitor/utils/AlertMessage.java | 53 ++++++++++
.../src/main/resources/application.properties | 8 ++
.../monitor/requests/PingRequestTest.java | 40 ++++++++
.../monitor/requests/RequestCreatorTest.java | 26 +++++
18 files changed, 619 insertions(+)
create mode 100644 monitor/pom.xml
create mode 100644 monitor/src/main/java/netwatch/monitor/MonitorApplication.java
create mode 100644 monitor/src/main/java/netwatch/monitor/config/RabbitMqConfig.java
create mode 100644 monitor/src/main/java/netwatch/monitor/config/RedisConfig.java
create mode 100644 monitor/src/main/java/netwatch/monitor/entities/Contact.java
create mode 100644 monitor/src/main/java/netwatch/monitor/entities/Observation.java
create mode 100644 monitor/src/main/java/netwatch/monitor/entities/ObservationId.java
create mode 100644 monitor/src/main/java/netwatch/monitor/entities/Utility.java
create mode 100644 monitor/src/main/java/netwatch/monitor/requests/IRequest.java
create mode 100644 monitor/src/main/java/netwatch/monitor/requests/PingRequest.java
create mode 100644 monitor/src/main/java/netwatch/monitor/requests/RequestCreator.java
create mode 100644 monitor/src/main/java/netwatch/monitor/services/MonitorService.java
create mode 100644 monitor/src/main/java/netwatch/monitor/services/RabbitMqProducerService.java
create mode 100644 monitor/src/main/java/netwatch/monitor/services/RedisService.java
create mode 100644 monitor/src/main/java/netwatch/monitor/utils/AlertMessage.java
create mode 100644 monitor/src/main/resources/application.properties
create mode 100644 monitor/src/test/java/netwatch/monitor/requests/PingRequestTest.java
create mode 100644 monitor/src/test/java/netwatch/monitor/requests/RequestCreatorTest.java
diff --git a/monitor/pom.xml b/monitor/pom.xml
new file mode 100644
index 0000000..efd7dc3
--- /dev/null
+++ b/monitor/pom.xml
@@ -0,0 +1,85 @@
+
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.2.0
+
+
+
+ netwatch
+ monitor
+ 0.0.1-SNAPSHOT
+ monitor
+ Microservice for Checking Services Health.
+
+
+ 21
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.springframework.amqp
+ spring-rabbit-test
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+ org.springframework.boot
+ spring-boot-starter-amqp
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ 5.10.1
+ test
+
+
+ org.mockito
+ mockito-core
+ 5.3.1
+ test
+
+
+ org.json
+ json
+ 20231013
+
+
+ org.projectlombok
+ lombok
+ 1.18.30
+ provided
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ 21
+ UTF-8
+
+
+
+
+
+
\ No newline at end of file
diff --git a/monitor/src/main/java/netwatch/monitor/MonitorApplication.java b/monitor/src/main/java/netwatch/monitor/MonitorApplication.java
new file mode 100644
index 0000000..4befe4b
--- /dev/null
+++ b/monitor/src/main/java/netwatch/monitor/MonitorApplication.java
@@ -0,0 +1,21 @@
+package netwatch.monitor;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.web.client.RestTemplate;
+
+@EnableScheduling
+@SpringBootApplication
+public class MonitorApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(MonitorApplication.class, args);
+ }
+
+ @Bean
+ public RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+}
\ No newline at end of file
diff --git a/monitor/src/main/java/netwatch/monitor/config/RabbitMqConfig.java b/monitor/src/main/java/netwatch/monitor/config/RabbitMqConfig.java
new file mode 100644
index 0000000..294596b
--- /dev/null
+++ b/monitor/src/main/java/netwatch/monitor/config/RabbitMqConfig.java
@@ -0,0 +1,20 @@
+package netwatch.monitor.config;
+
+import org.springframework.amqp.core.FanoutExchange;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+// This class configures a Fanout Exchange for broadcasting messages to all bound queues.
+// @author Antonio Scardace
+// @version 1.0
+
+@Configuration
+public class RabbitMqConfig {
+
+ private static final String EXCHANGE_NAME = System.getenv("RABBITMQ_EXCHANGE");
+
+ @Bean
+ public FanoutExchange fanoutExchange() {
+ return new FanoutExchange(EXCHANGE_NAME);
+ }
+}
\ No newline at end of file
diff --git a/monitor/src/main/java/netwatch/monitor/config/RedisConfig.java b/monitor/src/main/java/netwatch/monitor/config/RedisConfig.java
new file mode 100644
index 0000000..7e676db
--- /dev/null
+++ b/monitor/src/main/java/netwatch/monitor/config/RedisConfig.java
@@ -0,0 +1,46 @@
+package netwatch.monitor.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
+import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import netwatch.monitor.entities.ObservationId;
+
+// Configuration class for connecting to Redis and for using RedisTemplate.
+// @author Antonio Scardace
+// @version 1.0
+
+@Configuration
+public class RedisConfig {
+
+ @Value("${spring.redis.host}")
+ private String redisHost;
+
+ @Value("${spring.redis.port}")
+ private int redisPort;
+
+ @Value("${spring.redis.password}")
+ private String redisPassword;
+
+ @Bean
+ public LettuceConnectionFactory redisConnectionFactory() {
+ RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(redisHost, redisPort);
+ config.setPassword(redisPassword);
+ return new LettuceConnectionFactory(config);
+ }
+
+ @Bean
+ public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) {
+ RedisTemplate redisTemplate = new RedisTemplate<>();
+ redisTemplate.setConnectionFactory(connectionFactory);
+ redisTemplate.setKeySerializer(new StringRedisSerializer());
+ redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(ObservationId.class));
+ return redisTemplate;
+ }
+}
\ No newline at end of file
diff --git a/monitor/src/main/java/netwatch/monitor/entities/Contact.java b/monitor/src/main/java/netwatch/monitor/entities/Contact.java
new file mode 100644
index 0000000..12a7ec9
--- /dev/null
+++ b/monitor/src/main/java/netwatch/monitor/entities/Contact.java
@@ -0,0 +1,21 @@
+package netwatch.monitor.entities;
+
+import java.io.Serializable;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+// This class represents the "contacts" entity in the database.
+// The Primary Key is the field "value".
+// @author Antonio Scardace
+// @version 1.0
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Data
+public class Contact implements Serializable {
+
+ private String value;
+ private String type;
+}
\ No newline at end of file
diff --git a/monitor/src/main/java/netwatch/monitor/entities/Observation.java b/monitor/src/main/java/netwatch/monitor/entities/Observation.java
new file mode 100644
index 0000000..6becd2c
--- /dev/null
+++ b/monitor/src/main/java/netwatch/monitor/entities/Observation.java
@@ -0,0 +1,25 @@
+package netwatch.monitor.entities;
+
+import java.io.Serializable;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+// This class represents the "observes" entity in the database.
+// The Primary Key is the composite field "observationId" defined by the Embedded class {@link ObservationId}.
+// It represents the Many-To-Many association table between "utilities" and "contacts" tables.
+// @author Antonio Scardace
+// @version 1.0
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Data
+public class Observation implements Serializable {
+
+ private ObservationId observationId;
+
+ private Utility utility;
+ private Contact contact;
+ private String environment;
+}
\ No newline at end of file
diff --git a/monitor/src/main/java/netwatch/monitor/entities/ObservationId.java b/monitor/src/main/java/netwatch/monitor/entities/ObservationId.java
new file mode 100644
index 0000000..ea34cca
--- /dev/null
+++ b/monitor/src/main/java/netwatch/monitor/entities/ObservationId.java
@@ -0,0 +1,22 @@
+package netwatch.monitor.entities;
+
+import java.io.Serializable;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+// It represents a composite Primary Key for the entity {@link Observation} of the table "observes".
+// It is composed by "address" and "contact" fields. They are both Foreign Keys.
+// Respectively, they are the utility address and its referent contact.
+// @author Antonio Scardace
+// @version 1.0
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Data
+public class ObservationId implements Serializable {
+
+ private String address;
+ private String contact;
+}
\ No newline at end of file
diff --git a/monitor/src/main/java/netwatch/monitor/entities/Utility.java b/monitor/src/main/java/netwatch/monitor/entities/Utility.java
new file mode 100644
index 0000000..7a8bbb2
--- /dev/null
+++ b/monitor/src/main/java/netwatch/monitor/entities/Utility.java
@@ -0,0 +1,22 @@
+package netwatch.monitor.entities;
+
+import java.io.Serializable;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+// This class represents the "utilities" entity in the database.
+// The Primary Key is the field "address".
+// @author Antonio Scardace
+// @version 1.0
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Data
+public class Utility implements Serializable {
+
+ private String address;
+ private String name;
+ private String type;
+}
\ No newline at end of file
diff --git a/monitor/src/main/java/netwatch/monitor/requests/IRequest.java b/monitor/src/main/java/netwatch/monitor/requests/IRequest.java
new file mode 100644
index 0000000..1e4932c
--- /dev/null
+++ b/monitor/src/main/java/netwatch/monitor/requests/IRequest.java
@@ -0,0 +1,9 @@
+package netwatch.monitor.requests;
+
+// Interface defining methods to handle address-related operations.
+// @author Antonio Scardace
+// @version 1.0
+
+public interface IRequest {
+ public Boolean request(String address);
+}
\ No newline at end of file
diff --git a/monitor/src/main/java/netwatch/monitor/requests/PingRequest.java b/monitor/src/main/java/netwatch/monitor/requests/PingRequest.java
new file mode 100644
index 0000000..c6f55ed
--- /dev/null
+++ b/monitor/src/main/java/netwatch/monitor/requests/PingRequest.java
@@ -0,0 +1,34 @@
+package netwatch.monitor.requests;
+
+import java.io.IOException;
+import java.net.InetAddress;
+
+import lombok.extern.java.Log;
+
+// Implementation of {@link IRequest} for handling ping-related operations.
+// It supports IPv4 and IPv6 addresses. The use of their machine name is discouraged.
+// The timeout (the time before the call aborts) is set to 4000ms (4 seconds).
+// @author Antonio Scardace
+// @version 1.0
+
+@Log
+public class PingRequest implements IRequest {
+
+ private final Integer timeoutMs;
+
+ public PingRequest() {
+ this.timeoutMs = 4000;
+ }
+
+ @Override
+ public Boolean request(String ip) {
+ try {
+ InetAddress address = InetAddress.getByName(ip);
+ return address.isReachable(this.timeoutMs);
+ }
+ catch(IOException e) {
+ log.warning(e.getMessage());
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/monitor/src/main/java/netwatch/monitor/requests/RequestCreator.java b/monitor/src/main/java/netwatch/monitor/requests/RequestCreator.java
new file mode 100644
index 0000000..f528cb3
--- /dev/null
+++ b/monitor/src/main/java/netwatch/monitor/requests/RequestCreator.java
@@ -0,0 +1,18 @@
+package netwatch.monitor.requests;
+
+// Factory class to create {@link IRequest} instances based on the type.
+// Factory-Method Design Pattern used to make the Request component modular.
+// @author Antonio Scardace
+// @version 1.0
+
+public class RequestCreator {
+
+ private RequestCreator() {
+
+ }
+
+ public static IRequest getRequest(String type) {
+ if (type.equals("ip")) return new PingRequest();
+ throw new IllegalArgumentException("Unknown Request type " + type);
+ }
+}
\ No newline at end of file
diff --git a/monitor/src/main/java/netwatch/monitor/services/MonitorService.java b/monitor/src/main/java/netwatch/monitor/services/MonitorService.java
new file mode 100644
index 0000000..ea99cd5
--- /dev/null
+++ b/monitor/src/main/java/netwatch/monitor/services/MonitorService.java
@@ -0,0 +1,97 @@
+package netwatch.monitor.services;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestClientException;
+import org.springframework.web.client.RestTemplate;
+
+import lombok.extern.java.Log;
+import netwatch.monitor.entities.Observation;
+import netwatch.monitor.entities.ObservationId;
+import netwatch.monitor.entities.Utility;
+import netwatch.monitor.requests.IRequest;
+import netwatch.monitor.requests.RequestCreator;
+import netwatch.monitor.utils.AlertMessage;
+
+// This class is responsible for monitoring the state of utilities.
+// It scans periodically (each second) a set of utilities and, based on detected events, sends notifications.
+// Notifications are sent to the interested microservices by RabbitMQ.
+// @author Antonio Scardace
+// @version 1.0
+
+@Log
+@Service
+public class MonitorService {
+
+ private static final String SET_NAME = "offline-utilities";
+
+ private final RestTemplate restTemplate;
+ private final RabbitMqProducerService rabbitManager;
+ private final RedisService redisService;
+
+ @Autowired
+ public MonitorService(RestTemplate restTemplate, RabbitMqProducerService rabbitManager, RedisService redisService) {
+ this.restTemplate = restTemplate;
+ this.rabbitManager = rabbitManager;
+ this.redisService = redisService;
+ }
+
+ private Boolean checkUtility(Utility utility) {
+ IRequest req = RequestCreator.getRequest(utility.getType());
+ return req.request(utility.getAddress());
+ }
+
+ private void updateOfflineUtilities(ObservationId observation, Boolean backOnline) {
+ if (Boolean.TRUE.equals(backOnline)) this.redisService.delete(SET_NAME, observation);
+ else this.redisService.insert(SET_NAME, observation);
+ }
+
+ // Fetches utility observations from the external API specified by the MANAGER_API_URL environment variable.
+ // Logs a warning if the API endpoint cannot be reached and return an empty list.
+ // Returns the list of observations, if any.
+
+ private List fetchUtilities() {
+ try {
+ String urlApi = System.getenv("MANAGER_API_URL");
+ ResponseEntity responseEntity = restTemplate.getForEntity(urlApi, Observation[].class);
+ Observation[] observationsArray = responseEntity.getBody();
+ return observationsArray == null ? Collections.emptyList() : Arrays.asList(observationsArray);
+ }
+ catch (RestClientException e) {
+ log.warning("API endpoint cannot be reached.");
+ return Collections.emptyList();
+ }
+ }
+
+ // Performs a single scan for a given utility observation, checking its connectivity status.
+ // If the utility is online and was offline in the previous scans, a Solve Message is send.
+ // If the utility is offline and was not offline in the previous scans, a Resolution Message is send.
+
+ private void singleScan(Observation observation) {
+ Boolean isOnline = this.checkUtility(observation.getUtility());
+ Boolean wasOffline = this.redisService.contains(SET_NAME, observation.getObservationId());
+
+ if (Boolean.compare(isOnline, wasOffline) == 0) {
+ this.rabbitManager.send(AlertMessage.generate(observation, isOnline));
+ this.updateOfflineUtilities(observation.getObservationId(), wasOffline);
+ }
+ }
+
+ // Scheduled method to periodically scan utility observations for connectivity status.
+ // Fetches utility observations and performs a single scan for each observation concurrently.
+
+ @Scheduled(fixedDelay = 1000)
+ public void scanUtilities() {
+ CompletableFuture>[] futures = this.fetchUtilities().stream()
+ .map(utility -> CompletableFuture.runAsync(() -> singleScan(utility)))
+ .toArray(CompletableFuture[]::new);
+ CompletableFuture.allOf(futures).join();
+ }
+}
\ No newline at end of file
diff --git a/monitor/src/main/java/netwatch/monitor/services/RabbitMqProducerService.java b/monitor/src/main/java/netwatch/monitor/services/RabbitMqProducerService.java
new file mode 100644
index 0000000..6846d88
--- /dev/null
+++ b/monitor/src/main/java/netwatch/monitor/services/RabbitMqProducerService.java
@@ -0,0 +1,31 @@
+package netwatch.monitor.services;
+
+import org.springframework.amqp.core.AmqpTemplate;
+import org.springframework.amqp.core.FanoutExchange;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import lombok.extern.java.Log;
+
+// This class is a simple RabbitMQ Producer (Publisher) to a Fanout Exchange for broadcasting to all bound queues.
+// @author Antonio Scardace
+// @version 1.0
+
+@Log
+@Service
+public class RabbitMqProducerService {
+
+ private final AmqpTemplate rabbitTemplate;
+ private final FanoutExchange fanoutExchange;
+
+ @Autowired
+ public RabbitMqProducerService(AmqpTemplate rabbitTemplate, FanoutExchange fanoutExchange) {
+ this.rabbitTemplate = rabbitTemplate;
+ this.fanoutExchange = fanoutExchange;
+ }
+
+ public void send(String message) {
+ rabbitTemplate.convertAndSend(this.fanoutExchange.getName(), "", message);
+ log.info("Message sent: " + message);
+ }
+}
\ No newline at end of file
diff --git a/monitor/src/main/java/netwatch/monitor/services/RedisService.java b/monitor/src/main/java/netwatch/monitor/services/RedisService.java
new file mode 100644
index 0000000..9f58171
--- /dev/null
+++ b/monitor/src/main/java/netwatch/monitor/services/RedisService.java
@@ -0,0 +1,41 @@
+package netwatch.monitor.services;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import netwatch.monitor.entities.ObservationId;
+
+import java.util.Set;
+
+// This class is a service component responsible for managing the interaction with Redis for storing and retrieving data.
+// The Redis data type handled by the class is the Set.
+// @author Antonio Scardace
+// @version 1.0
+
+@Service
+public class RedisService {
+
+ private RedisTemplate redisTemplate;
+
+ @Autowired
+ public RedisService(RedisTemplate redisTemplate) {
+ this.redisTemplate = redisTemplate;
+ }
+
+ public Boolean contains(String setName, ObservationId value) {
+ return this.redisTemplate.opsForSet().isMember(setName, value);
+ }
+
+ public Boolean insert(String setName, ObservationId value) {
+ return this.redisTemplate.opsForSet().add(setName, value) != null;
+ }
+
+ public Boolean delete(String setName, ObservationId value) {
+ return this.redisTemplate.opsForSet().remove(setName, value) != null;
+ }
+
+ public Set getAllByName(String setName) {
+ return this.redisTemplate.opsForSet().members(setName);
+ }
+}
\ No newline at end of file
diff --git a/monitor/src/main/java/netwatch/monitor/utils/AlertMessage.java b/monitor/src/main/java/netwatch/monitor/utils/AlertMessage.java
new file mode 100644
index 0000000..1f52296
--- /dev/null
+++ b/monitor/src/main/java/netwatch/monitor/utils/AlertMessage.java
@@ -0,0 +1,53 @@
+package netwatch.monitor.utils;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+import org.json.JSONObject;
+
+import netwatch.monitor.entities.Observation;
+
+// This static class provides methods for creating the alert message on two events.
+// It can be an error message if the utility goes offline.
+// It can be a resolution message if the utility returns online.
+// This message is then attached with the utility referent contact info.
+// @author Antonio Scardace
+// @version 1.0
+
+public class AlertMessage {
+
+ private AlertMessage() {
+
+ }
+
+ private static String getErrorMessage(String address, String name, String timestamp) {
+ return String.format("Hi 👋🏻, an error occurred on utility %s (%s) on %s ⚠️", name, address, timestamp);
+ }
+
+ private static String getResolutionMessage(String address, String name, String timestamp) {
+ return String.format("Hi 👋🏻, the utility %s (%s) returned online on %s ✅", name, address, timestamp);
+ }
+
+ private static String getUtcTimestamp() {
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ return dateFormat.format(new Date()) + " UTC";
+ }
+
+ public static String generate(Observation observation, Boolean backOnline) {
+ String address = observation.getUtility().getAddress();
+ String name = observation.getUtility().getName();
+ String timestamp = AlertMessage.getUtcTimestamp();
+
+ JSONObject message = new JSONObject();
+ message.put("contact", observation.getContact().getValue());
+ message.put("contact_type", observation.getContact().getType());
+ message.put("message",
+ Boolean.TRUE.equals(backOnline)
+ ? AlertMessage.getResolutionMessage(address, name, timestamp)
+ : AlertMessage.getErrorMessage(address, name, timestamp));
+
+ return message.toString();
+ }
+}
\ No newline at end of file
diff --git a/monitor/src/main/resources/application.properties b/monitor/src/main/resources/application.properties
new file mode 100644
index 0000000..301eaed
--- /dev/null
+++ b/monitor/src/main/resources/application.properties
@@ -0,0 +1,8 @@
+spring.rabbitmq.host=${RABBITMQ_HOST}
+spring.rabbitmq.port=${RABBITMQ_PORT}
+spring.rabbitmq.username=${RABBITMQ_USER}
+spring.rabbitmq.password=${RABBITMQ_PSW}
+
+spring.redis.host=${REDIS_HOST}
+spring.redis.port=${REDIS_PORT}
+spring.redis.password=${REDIS_PSW}
\ No newline at end of file
diff --git a/monitor/src/test/java/netwatch/monitor/requests/PingRequestTest.java b/monitor/src/test/java/netwatch/monitor/requests/PingRequestTest.java
new file mode 100644
index 0000000..16958f6
--- /dev/null
+++ b/monitor/src/test/java/netwatch/monitor/requests/PingRequestTest.java
@@ -0,0 +1,40 @@
+package netwatch.monitor.requests;
+
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+
+// Unit tests for the {@link PingRequest} class.
+// The tests examine both successful and unsuccessful scenarios.
+// @author Antonio Scardace
+// @version 1.0
+
+class PingRequestTest {
+
+ @Test
+ void testRequest_Successful_withLocalhost() {
+ PingRequest pingRequest = new PingRequest();
+ String ipAddress = "127.0.0.1";
+ assertTrue(pingRequest.request(ipAddress));
+ }
+
+ @Test
+ void testRequest_Successful_withName() {
+ PingRequest pingRequest = new PingRequest();
+ String ipAddress = "google.com";
+ assertTrue(pingRequest.request(ipAddress));
+ }
+
+ @Test
+ void testRequest_Unsuccessful_withUnvalidIp() {
+ PingRequest pingRequest = new PingRequest();
+ String invalidIpAddress = "1.1.";
+ assertFalse(pingRequest.request(invalidIpAddress));
+ }
+
+ @Test
+ void testRequest_Unsuccessful_withUnvalidName() {
+ PingRequest pingRequest = new PingRequest();
+ String invalidIpAddress = "https://google.com";
+ assertFalse(pingRequest.request(invalidIpAddress));
+ }
+}
diff --git a/monitor/src/test/java/netwatch/monitor/requests/RequestCreatorTest.java b/monitor/src/test/java/netwatch/monitor/requests/RequestCreatorTest.java
new file mode 100644
index 0000000..3dad7fd
--- /dev/null
+++ b/monitor/src/test/java/netwatch/monitor/requests/RequestCreatorTest.java
@@ -0,0 +1,26 @@
+package netwatch.monitor.requests;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+
+// Unit tests for the {@link RequestCreator} class.
+// The tests examine both successful and unsuccessful scenarios.
+// @author Antonio Scardace
+// @version 1.0
+
+class RequestCreatorTest {
+
+ @Test
+ void testGetRequest_Successful() {
+ IRequest request = RequestCreator.getRequest("ip");
+ assertNotNull(request);
+ assertTrue(request instanceof PingRequest);
+ }
+
+ @Test
+ void testGetRequest_UnknownType_ExceptionThrown() {
+ String unknownType = "unknown";
+ assertThrows(IllegalArgumentException.class, () -> RequestCreator.getRequest(unknownType));
+ }
+}
\ No newline at end of file