Show List

Sample Cloud Application Using Spring Cloud, API Gateway, DynamoDB, JWT Authentication, RabbitMQ - Part2

In the previous part of this tutorial we set up local DynamoDB for the application and created tables. In this part we will be creating the microservices.

We will be utilizing a multi-module project structure where the microservices will serve as modules within the project. This structure facilitates code maintenance and enables individual deployment of the modules. The parent POM specifies all the dependencies, which can be inherited by dependent modules. The parent project is packaged as "pom," while the child projects can have various packagings based on their specific requirements.

Create Parent Project

Create a Springboot project with spring-cloud-starter dependency.

Delete the "src" folder from the parent project and update the packaging to "pom" in POM.xml. Add the aws-java-sdk-dynamodb, spring-data-dynamodb, lombok, and jjwt dependencies as in the below pom file.

jacoco-maven-plugin is used for code coverage reporting and is configured to exclude classes in the lombok package from code coverage analysis.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<modules>
<module>registration</module>
<module>addrestaurant</module>
<module>updatePrice</module>
<module>searchFood</module>
<module>discovery</module>
<module>reviews</module>
<module>batchLoad</module>
<module>gateway</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.food</groupId>
<artifactId>searchRestaurant</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>searchRestaurant</name>
<description>Demo project for Food Delivery</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2021.0.4</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-dynamodb</artifactId>
<version>1.11.857</version>
</dependency>

<dependency>
<groupId>com.github.derjust</groupId>
<artifactId>spring-data-dynamodb</artifactId>
<version>5.1.0</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.10</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
<configuration>
<excludes>
<exclude>**/lombok/**/*.class</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

Creating registration Microservice module

Right click on the project and create a new maven module "registration". Add the packages under "registration" module as shown in the below image: 

pom.xml:

  • spring-cloud-starter-netflix-eureka-client" from the "org.springframework.cloud" group, used for integrating with Netflix Eureka service registry.
  • spring-boot-starter-security" from the "org.springframework.boot" group, providing Spring Security functionality.
  • spring-boot-starter-web" from the "org.springframework.boot" group, enabling web application development with Spring Boot.
  • springdoc-openapi-ui" from the "org.springdoc" group with version 1.6.4, used for generating and documenting OpenAPI (Swagger) documentation.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>searchRestaurant</artifactId>
<groupId>com.food</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>registration</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.4</version>
</dependency>
</dependencies>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>

</project>

UserRegistration.java
The application implements the ApplicationRunner interface, which allows custom logic to be executed after the application context has been loaded. The run() method is implemented to save sample user data to the user repository. This data is meant for testing and will be available for authentication and authorization in the application.

Sample user data includes customer and admin users, each with email, username, phone number, encoded password, and a role. The PasswordEncoder is used to encode the passwords before saving them to the repository.
The class is annotated with @EnableEurekaClient, indicating that it can be registered as a client with the Eureka service registry.

package registration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.security.crypto.password.PasswordEncoder;
import registration.model.AppUser;
import registration.repository.UserRepository;

@EnableEurekaClient
@SpringBootApplication
public class UserRegistration implements ApplicationRunner {

@Autowired
UserRepository userRepo; // Repository for accessing user data.

@Autowired
PasswordEncoder encoder; // Password encoder for encoding user passwords.

public static void main(String[] args) {
SpringApplication.run(UserRegistration.class, args); // Start the UserRegistration application.
}

@Override
public void run(ApplicationArguments args) throws Exception {
// This method is executed after the application context has been loaded.

// Save sample user data to the user repository for testing purposes.
// The saved users will be available in the application for authentication and authorization.

// Save a customer user
userRepo.saveUser(new AppUser(
"customer1@email.com",
"customer1",
"123423456",
encoder.encode("password1"),
"CUSTOMER"
));

// Save another customer user
userRepo.saveUser(new AppUser(
"customer2@email.com",
"customer2",
"144323456",
encoder.encode("password2"),
"CUSTOMER"
));

// Save an admin user
userRepo.saveUser(new AppUser(
"admin1@email.com",
"admin1",
"23423423456",
encoder.encode("password3"),
"ADMIN"
));

// Save another admin user
userRepo.saveUser(new AppUser(
"admin2@email.com",
"admin2",
"2342342434",
encoder.encode("password4"),
"ADMIN"
));
}
}
DynamoDBConfig.java

It includes several fields annotated with @Value, which are populated with values from the application configuration. The dynamoDBMapper() method creates and returns a bean of type DynamoDBMapper. This object is responsible for mapping Java objects to DynamoDB tables. The client is configured with the provided dynamodbEndpoint, awsRegion, dynamodbAccessKey, and dynamodbSecretKey.
package registration.config;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class DynamoDBConfig {

private static final Logger LOGGER = LoggerFactory.getLogger(DynamoDBConfig.class);

@Value("${amazon.dynamodb.endpoint}")
private String dynamodbEndpoint;

@Value("${amazon.aws.region}")
private String awsRegion;

@Value("${amazon.aws.accesskey}")
private String dynamodbAccessKey;

@Value("${amazon.aws.secretkey}")
private String dynamodbSecretKey;

/**
* Creates a bean for the DynamoDBMapper.
*
* @return The DynamoDBMapper object.
*/
@Bean
public DynamoDBMapper dynamoDBMapper() {
return new DynamoDBMapper(buildAmazonDynamoDB());
}

/**
* Builds and configures the AmazonDynamoDB client.
*
* @return The configured AmazonDynamoDB client.
*/
private AmazonDynamoDB buildAmazonDynamoDB() {
try {

return AmazonDynamoDBClientBuilder
.standard()
.withEndpointConfiguration(
new AwsClientBuilder.EndpointConfiguration(dynamodbEndpoint, awsRegion))
.withCredentials(new AWSStaticCredentialsProvider(
new BasicAWSCredentials(dynamodbAccessKey, dynamodbSecretKey)))
.build();
} catch (Exception e) {
LOGGER.error("Error occurred while building AmazonDynamoDB client", e);
throw e;
}
}
}
EncoderConfig.java

The encoder() method returns an instance of BCryptPasswordEncoder, which is a password encoder implementation provided by Spring Security. The BCryptPasswordEncoder is a widely used password hashing algorithm that applies salt and multiple rounds of hashing to increase the security of passwords.
package registration.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class EncoderConfig {

/**
* Bean definition for PasswordEncoder.
*
* @return BCryptPasswordEncoder instance.
*/
@Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
}
SecurityConfig.java
  • The filterChain(HttpSecurity http) method configures the security rules and permissions for different endpoints.
  • CORS (Cross-Origin Resource Sharing) is enabled, CSRF (Cross-Site Request Forgery) protection is disabled, and session management is set to stateless.
  • An unauthorized requests exception handler is defined to handle unauthorized access to protected resources.
  • Permissions are set for both public and private endpoints using antMatchers(). Some endpoints are allowed for all users, while others require specific authorities (e.g., "CUSTOMER" or "ADMIN").
  • A JWT token filter (jwtTokenFilter) is added before the UsernamePasswordAuthenticationFilter to handle authentication using JSON Web Tokens.
  • The filterChain(HttpSecurity http) method builds and returns the SecurityFilterChain object.
package registration.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import registration.repository.UserRepository;
import registration.service.AppUserDetailsService;
import registration.util.JwtTokenFilter;

import javax.servlet.http.HttpServletResponse;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

@Autowired
private JwtTokenFilter jwtTokenFilter;

@Autowired
private AppUserDetailsService appUserDetailsService;

@Autowired
UserRepository repoUsr;

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// Enable CORS and disable CSRF
http = http.cors().and().csrf().disable();

// Set session management to stateless
http = http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and();

// Set unauthorized requests exception handler
http = http
.exceptionHandling()
.authenticationEntryPoint(
(request, response, ex) -> {
response.sendError(
HttpServletResponse.SC_UNAUTHORIZED,
ex.getMessage()
);
}
)
.and();

// Set permissions on endpoints
http.authorizeRequests(authorize -> authorize
// Our public endpoints
.antMatchers("/swagger-ui/**", "/v3/api-docs/**", "/proxy/**").permitAll()
.antMatchers(HttpMethod.POST, "/food/api/v1/user/login").permitAll()
.antMatchers(HttpMethod.POST, "/food/api/v1/user/register").permitAll()

// Our private endpoints
.antMatchers(HttpMethod.GET, "/food/api/v1/user/test").hasAnyAuthority("CUSTOMER")
.antMatchers(HttpMethod.GET, "/food/api/v1/user/best").hasAuthority("ADMIN")
.anyRequest().authenticated()
);

// Add JWT token filter
http.addFilterBefore(
jwtTokenFilter,
UsernamePasswordAuthenticationFilter.class
);

// Build the SecurityFilterChain
return http.build();
}

}
UserController.java
  • The registerUser() method receives a POST request to register a new user. It checks if the provided email already exists, encrypts the password, saves the user to the repository, and returns an appropriate response entity.
  • The loginUser() method receives a POST request to log in a user. It retrieves the user with the provided email, checks if the password matches the encrypted password, generates a JWT token, and returns an appropriate response entity.
  • Both methods handle potential exceptions and log relevant information for troubleshooting.
  • The userDetailsService is used to load user details, and the jwtTokenUtil is used to generate JWT tokens.
  • The userRepository is used to interact with the user repository for saving and retrieving user data.
  • The passwordEncoder is used to encode and match passwords securely.
  • The class uses the Logger interface from SLF4J for logging.
package registration.controller;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;
import registration.model.AppUser;
import registration.model.LoginModel;
import registration.model.Response;
import registration.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import registration.service.AppUserDetailsService;
import registration.util.JwtTokenUtil;

@RestController
@RequestMapping("/food/api/v1/user")
public class UserController {

private static final Logger LOGGER = LoggerFactory.getLogger(UserController.class);

@Autowired
private AppUserDetailsService userDetailsService;

@Autowired
private JwtTokenUtil jwtTokenUtil;

@Autowired
private UserRepository userRepository;

@Autowired
private PasswordEncoder passwordEncoder;

/**
* Registers a new appUser.
*
* @param appUser The AppUser object containing appUser details.
* @return ResponseEntity indicating the result of the registration process.
*/
@PostMapping("/register")
public ResponseEntity<String> registerUser(@RequestBody AppUser appUser) {
AppUser existingAppUser = userRepository.getUserByEmail(appUser.getEmail());

try {
LOGGER.info("Registering user with email: {}", appUser.getEmail());

if (existingAppUser != null) {
return ResponseEntity.badRequest().body("Email already exists");
}

String encodedPassword = passwordEncoder.encode(appUser.getPassword());
appUser.setPassword(encodedPassword);

userRepository.saveUser(appUser);
LOGGER.info("User registered successfully with email: {}", appUser.getEmail());

return ResponseEntity.ok("User registered successfully");
} catch (Exception e) {
LOGGER.error("Error occurred while registering appUser with email: {}", appUser.getEmail(), e);
return ResponseEntity.status(500).body("Internal Server Error");
}
}

/**
* Logs in a user.
*
* @param loginObj The LoginModel object containing login credentials.
* @return ResponseEntity indicating the result of the login process.
*/
@PostMapping("/login")
public ResponseEntity<?> loginUser(@RequestBody LoginModel loginObj) {

AppUser existingAppUser = userRepository.getUserByEmail(loginObj.getEmail());
try {
LOGGER.info("Logging in user with email: {}", loginObj.getEmail());

if (existingAppUser == null) {
LOGGER.warn("User with email {} not found", loginObj.getEmail());

return ResponseEntity.badRequest().body("User not found");
}

if (!passwordEncoder.matches(loginObj.getPassword(), existingAppUser.getPassword())) {
LOGGER.warn("Incorrect password for user with email: {}", loginObj.getEmail());

return ResponseEntity.badRequest().body("Incorrect password");
}
LOGGER.info("AppUser logged in successfully with email: {}", loginObj.getEmail());

//return ResponseEntity.ok("AppUser logged in successfully");
} catch (Exception e) {
LOGGER.error("Error occurred while logging in user with email: {}", loginObj.getEmail(), e);
return ResponseEntity.status(500).body("Internal Server Error");
}

final UserDetails userDetails = userDetailsService
.loadUserByUsername(loginObj.getEmail());

final String jwt = jwtTokenUtil.generateToken(userDetails);
return ResponseEntity.ok(new Response(jwt));

}

}
AppUser.java
  • The class includes the necessary annotations for DynamoDB object mapping.
  • It uses Lombok annotations (@Data, @AllArgsConstructor, @NoArgsConstructor) to generate boilerplate code such as getters, setters, constructors, and toString methods.
  • The @DynamoDBTable annotation specifies the name of the DynamoDB table to which instances of this class will be mapped.
  • Each field of the class is annotated with @DynamoDBAttribute to indicate that it should be mapped to a DynamoDB attribute.
  • The email field is annotated with @DynamoDBHashKey to indicate that it is the hash key of the table.
package registration.model;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAutoGeneratedKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@DynamoDBTable(tableName = "user")
public class AppUser {

@DynamoDBHashKey
@DynamoDBAttribute
private String email;

@DynamoDBAttribute
private String name;

@DynamoDBAttribute
private String mobileNumber;

@DynamoDBAttribute
private String password;

@DynamoDBAttribute
private String role;

}
LoginModel.java
package registration.model;


public class LoginModel {
private String email;
private String password;

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}
}
Response.java
package registration.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data // @Data generates getter and setter methods for the 'jwt' field.
@AllArgsConstructor // @AllArgsConstructor generates a constructor that accepts a 'jwt' parameter.
@NoArgsConstructor // @NoArgsConstructor generates a default constructor with no parameters.
public class Response implements Serializable {
private String jwt;
}
UserRepository:
  • The saveUser method takes an AppUser object as a parameter, uses the dynamoDBMapper to save the user to the DynamoDB table, and returns the saved user.
  • The getUserByEmail method retrieves an AppUser from the DynamoDB table based on the provided email. It uses the dynamoDBMapper to load the user using the AppUser class and the email as the key, and returns the retrieved user. If no user is found, it returns null.
  • The setDynamoDBMapper method is used to set the DynamoDBMapper instance to be used by the repository. This allows external configuration or dependency injection to provide the DynamoDBMapper object to the repository.
package registration.repository;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;

import registration.model.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class UserRepository {

@Autowired
private DynamoDBMapper dynamoDBMapper;

/**
* Saves a appUser to the DynamoDB table.
*
* @param appUser The AppUser object to be saved.
* @return The saved appUser.
*/
public AppUser saveUser(AppUser appUser) {
dynamoDBMapper.save(appUser);
return appUser;
}

/**
* Retrieves a customer by email from the DynamoDB table.
*
* @param email The email of the customer to retrieve.
* @return The retrieved customer or null if not found.
*/
public AppUser getUserByEmail(String email) {
return dynamoDBMapper.load(AppUser.class, email);
}


/**
* Sets the DynamoDBMapper instance to be used by the repository.
*
* @param dynamoDBMapper The DynamoDBMapper instance.
*/
public void setDynamoDBMapper(DynamoDBMapper dynamoDBMapper) {
this.dynamoDBMapper = dynamoDBMapper;
}
}
AppUserDetailsService.java
  • The class implements the loadUserByUsername method required by the UserDetailsService interface. This method is called by the Spring Security framework to load user details based on the provided username (in this case, the user's email).
  • Inside the loadUserByUsername method, the getUserByEmail method from the repository is called to retrieve the AppUser object based on the provided email.
  • If the retrieved AppUser object is null, indicating that the user was not found, a UsernameNotFoundException is thrown.
  • If the AppUser object is not null, a UserDetails object is created using the User builder provided by Spring Security. The UserDetails object includes the user's email as the username, the user's password, and the user's role/authorities.
  • The created UserDetails object is then returned to the Spring Security framework for further processing during the authentication and authorization process.
package registration.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import registration.model.AppUser;
import registration.repository.UserRepository;

@Service
public class AppUserDetailsService implements UserDetailsService {

@Autowired
UserRepository repoUsr; // Repository for accessing user data.

@Override
public UserDetails loadUserByUsername(String useremail) throws UsernameNotFoundException {

AppUser appUser = repoUsr.getUserByEmail(useremail); // Retrieve the AppUser object based on the provided useremail.

if (appUser == null) {
throw new UsernameNotFoundException(useremail); // If the AppUser object is null, throw an exception indicating that the username was not found.
}

// Create a UserDetails object using the AppUser's email, password, and authorities.
UserDetails usr = User.withUsername(appUser.getEmail())
.password(appUser.getPassword())
.authorities(appUser.getRole())
.build();

return usr; // Return the created UserDetails object.

}
}
JwtTokenFilter.java
  • The class overrides the doFilterInternal method, which is called for each incoming request.
  • Inside the doFilterInternal method, the authorization header is retrieved from the request using the HttpHeaders.AUTHORIZATION constant.
  • If the authorization header is not null and starts with "Bearer ", indicating the presence of a JWT token, the token is extracted from the header and the username is extracted from the token using the jwtTokenUtil.extractUsername method.
  • If the username is not null and there is no existing authentication in the security context, the user details are loaded from the AppUserDetailsService based on the username.
  • The JWT token is then validated using the jwtTokenUtil.validateToken method, which checks the token's integrity and expiration.
  • If the token is valid, an UsernamePasswordAuthenticationToken object is created with the user details, authorities, and additional authentication details from the request. The authentication token is then set in the SecurityContextHolder to indicate that the user is authenticated.
  • Finally, the filter chain is continued by calling chain.doFilter(request, response), allowing the request to proceed to the next filters or the application's endpoint.
package registration.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import registration.repository.UserRepository;
import registration.service.AppUserDetailsService;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class JwtTokenFilter extends OncePerRequestFilter {

@Autowired
private AppUserDetailsService appUserDetailsService; // Service for retrieving user details.

@Autowired
private JwtTokenUtil jwtTokenUtil; // Utility class for JWT token operations.

@Autowired
private UserRepository userRepo; // Repository for accessing user data.

@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain)
throws ServletException, IOException {
// Get authorization header and validate
final String header = request.getHeader(HttpHeaders.AUTHORIZATION);

String username = null;
String jwt = null;

if (header != null && header.startsWith("Bearer ")) {
System.out.println("Header contains bearer token");
jwt = header.substring(7); // Extract the JWT from the Authorization header.
username = jwtTokenUtil.extractUsername(jwt); // Extract the username from the JWT.
}

if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

UserDetails userDetails = appUserDetailsService.loadUserByUsername(username); // Load user details based on the username.

if (jwtTokenUtil.validateToken(jwt, userDetails)) { // Validate the JWT token.
System.out.println("JWT Token is Valid.");
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities()); // Create an authentication token.
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); // Set additional details for authentication.
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken); // Set the authentication in the SecurityContextHolder.
}
}
chain.doFilter(request, response); // Continue with the filter chain.
}

}
JwtTokenUtil.java
  • The class has a SECRET_KEY field, which represents the secret key used for JWT signing and validation. This key should be kept secure and private.
  • The extractUsername method takes a JWT token as input and uses the Claims::getSubject function to extract the username from the token's claims.
  • The extractExpiration method extracts the expiration date from the JWT token's claims.
  • The extractClaim method is a generic method that takes a JWT token and a Function as input. It extracts all the claims from the token and applies the provided claimsResolver function to obtain a specific claim value.
  • The extractAllClaims method parses the JWT token, verifies its signature using the secret key, and returns all the claims contained within the token.
  • The isTokenExpired method checks if the JWT token is expired based on its expiration date.
  • The generateToken method takes a UserDetails object (typically representing the authenticated user) as input. It creates a map of claims, which can include additional information about the user, and calls the createToken method to generate a JWT token.
  • The createToken method builds a JWT token using the provided claims, subject (username), issued date/time, expiration date/time, and the chosen signature algorithm (in this case, HS256) with the secret key.
  • The validateToken method takes a JWT token and a UserDetails object as input. It extracts the username from the token and compares it with the username from the UserDetails object. It also checks if the token is expired using the isTokenExpired method.
package registration.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

@Service
public class JwtTokenUtil {
private String SECRET_KEY = "secret"; // Secret key used for JWT signing and validation.

public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject); // Extract the username from the JWT token's claims.
}

public Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration); // Extract the expiration date from the JWT token's claims.
}

public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token); // Extract all claims from the JWT token.
return claimsResolver.apply(claims); // Apply the claims resolver function to obtain a specific claim value.
}

private Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody(); // Parse the JWT token and extract all claims.
}

private Boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date()); // Check if the JWT token is expired based on the expiration date.
}

public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>(); // Create a map of claims to be included in the JWT token.
return createToken(claims, userDetails.getUsername()); // Create a JWT token with the specified claims and subject.
}

public String createToken(Map<String, Object> claims, String subject) {
return Jwts.builder()
.setClaims(claims) // Set the claims for the JWT token.
.setSubject(subject) // Set the subject (username) for the JWT token.
.setIssuedAt(new Date(System.currentTimeMillis())) // Set the issued date/time for the JWT token.
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // Set the expiration date/time for the JWT token.
.signWith(SignatureAlgorithm.HS256, SECRET_KEY) // Sign the JWT token using the specified algorithm and secret key.
.compact(); // Compact the JWT token into its final string representation.
}

public Boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token); // Extract the username from the JWT token.
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token)); // Validate the JWT token by comparing the username and expiration.
}
}
application.yaml
# Amazon DynamoDB, AWS configuration
amazon:
dynamodb:
endpoint: http://localhost:8000
aws:
region: us-east-1
accesskey: dummyid
secretkey: dummypw
# Server port configuration
server:
port: 9001
# Spring application name
spring:
application:
name: registration
# Eureka client configuration
eureka:
client:
service-url:
defaultZone: http://localhost:9000/eureka
fetch-registry: true
register-with-eureka: true
instance:
hostname: localhost
banner.txt
,------.               ,--.        ,--.                  ,--.  ,--.
| .--. ' ,---. ,---. `--' ,---.,-' '-.,--.--.,--,--.,-' '-.`--' ,---. ,--,--,
| '--'.'| .-. :| .-. |,--.( .-''-. .-'| .--' ,-. |'-. .-',--.| .-. || \
| |\ \ \ --.' '-' '| |.-' `) | | | | \ '-' | | | | |' '-' '| || |
`--' '--' `----'.`- / `--'`----' `--' `--' `--`--' `--' `--' `---' `--''--'
`---'
Here are the test classes:

RegistrationApplicationTests.java
package registration;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class RegistrationApplicationTests {

@Test
void contextLoads() {
// This test ensures that the application context loads successfully
}
}
UserControllerTest.java
package registration.controller;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import registration.model.AppUser;
import registration.model.LoginModel;
import registration.model.Response;
import registration.repository.UserRepository;
import registration.service.AppUserDetailsService;
import registration.util.JwtTokenUtil;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;

class UserControllerTest {

@Mock
private UserRepository userRepository; // Mocked repository for user data.

@Mock
private AppUserDetailsService userDetailsService; // Mocked service for user details.

@Mock
private JwtTokenUtil jwtTokenUtil; // Mocked utility for JWT token operations.

@Mock
private PasswordEncoder passwordEncoder; // Mocked password encoder.

@InjectMocks
private UserController userController; // Controller under test.

@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this); // Initialize the mocks before each test.
}

@Test
void testRegisterUser_WithNewUser_ReturnsSuccessResponse() {
// Arrange
AppUser appUser = createValidCustomer();
when(userRepository.getUserByEmail(appUser.getEmail())).thenReturn(null);
when(passwordEncoder.encode(appUser.getPassword())).thenReturn("password");
when(userRepository.saveUser(appUser)).thenReturn(appUser);

// Act
ResponseEntity<String> response = userController.registerUser(appUser);

// Assert
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals("User registered successfully", response.getBody());
verify(userRepository, times(1)).getUserByEmail(appUser.getEmail());
verify(passwordEncoder, times(1)).encode(appUser.getPassword());
verify(userRepository, times(1)).saveUser(appUser);
}

@Test
void testRegisterUser_WithExistingUser_ReturnsBadRequestResponse() {
// Arrange
AppUser appUser = createValidCustomer();
when(userRepository.getUserByEmail(appUser.getEmail())).thenReturn(appUser);

// Act
ResponseEntity<String> response = userController.registerUser(appUser);

// Assert
assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
assertEquals("Email already exists", response.getBody());
verify(userRepository, times(1)).getUserByEmail(appUser.getEmail());
verify(passwordEncoder, never()).encode(anyString());
verify(userRepository, never()).saveUser(appUser);
}

// Add more test cases to cover other scenarios

private AppUser createValidCustomer() {
AppUser appUser = new AppUser();
appUser.setEmail("test@example.com");
appUser.setPassword("password");
appUser.setName("Test");
appUser.setMobileNumber("2436342626");

return appUser;
}

@Test
void loginUser_ValidCredentials_ReturnsJwtToken() {
// Arrange
LoginModel loginModel = new LoginModel();
loginModel.setEmail("test@example.com");
loginModel.setPassword("password");

AppUser existingAppUser = new AppUser();
existingAppUser.setEmail("test@example.com");
existingAppUser.setPassword(passwordEncoder.encode("password"));

when(userRepository.getUserByEmail("test@example.com")).thenReturn(existingAppUser);
when(passwordEncoder.matches("password", existingAppUser.getPassword())).thenReturn(true);

UserDetails userDetails = mock(UserDetails.class);
when(userDetailsService.loadUserByUsername("test@example.com")).thenReturn(userDetails);

String jwtToken = "jwtToken";
when(jwtTokenUtil.generateToken(userDetails)).thenReturn(jwtToken);

// Act
ResponseEntity<?> response = userController.loginUser(loginModel);

// Assert
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(new Response(jwtToken), response.getBody());

// Verify the interactions with mocks
verify(userRepository, times(1)).getUserByEmail("test@example.com");
verify(passwordEncoder, times(1)).matches("password", existingAppUser.getPassword());
verify(userDetailsService, times(1)).loadUserByUsername("test@example.com");
verify(jwtTokenUtil, times(1)).generateToken(userDetails);
}

@Test
void testLoginUser_WithNonExistingUser_ReturnsBadRequestResponse() {
// Arrange
LoginModel loginModel = new LoginModel();
loginModel.setEmail("nonexisting@example.com");
loginModel.setPassword("password");
when(userRepository.getUserByEmail(loginModel.getEmail())).thenReturn(null);

// Act
ResponseEntity<String> response = (ResponseEntity<String>) userController.loginUser(loginModel);

// Assert
assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
assertEquals("User not found", response.getBody());
verify(userRepository, times(1)).getUserByEmail(loginModel.getEmail());
verify(passwordEncoder, never()).matches(anyString(), anyString());
}


}
AppUserRepositoryTest.java
package registration.repository;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import registration.model.AppUser;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;

class AppUserRepositoryTest {

@Mock
private DynamoDBMapper dynamoDBMapper;

private UserRepository userRepository;

@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
userRepository = new UserRepository();
userRepository.setDynamoDBMapper(dynamoDBMapper);
}

@Test
void testSaveCustomer() {
// Create a AppUser object
AppUser appUser = new AppUser();
appUser.setEmail("test@example.com");
appUser.setName("John Doe");
appUser.setMobileNumber("123456789");
appUser.setPassword("password");

// Perform the save operation
AppUser savedAppUser = userRepository.saveUser(appUser);

// Verify that the save method of DynamoDBMapper is called once
verify(dynamoDBMapper, times(1)).save(appUser);

// Verify that the returned appUser is the same as the input appUser
assertEquals(appUser, savedAppUser);
}

@Test
void testGetCustomerByEmail() {
// Create a mock AppUser object
AppUser mockAppUser = new AppUser();
mockAppUser.setEmail("test@example.com");
mockAppUser.setName("John Doe");
mockAppUser.setMobileNumber("123456789");
mockAppUser.setPassword("password");

// Specify the behavior of DynamoDBMapper's load method
when(dynamoDBMapper.load(AppUser.class, "test@example.com")).thenReturn(mockAppUser);

// Perform the get operation
AppUser retrievedAppUser = userRepository.getUserByEmail("test@example.com");

// Verify that the load method of DynamoDBMapper is called once
verify(dynamoDBMapper, times(1)).load(AppUser.class, "test@example.com");

// Verify that the retrieved customer is the same as the mock customer
assertEquals(mockAppUser, retrievedAppUser);
}
}
AppUserDetailsServiceTest.java
package registration.service;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import registration.model.AppUser;
import registration.repository.UserRepository;
import registration.service.AppUserDetailsService;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

class AppUserDetailsServiceTest {

@Mock
private UserRepository userRepository; // Mocked repository for user data.

@InjectMocks
private AppUserDetailsService appUserDetailsService; // Service under test.

@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this); // Initialize the mocks before each test.
}

@Test
void loadUserByUsername_ValidUser_ReturnsUserDetails() {
// Arrange
AppUser appUser = new AppUser();
appUser.setEmail("test@example.com");
appUser.setPassword("password");
appUser.setRole("ROLE_USER");
when(userRepository.getUserByEmail("test@example.com")).thenReturn(appUser);

// Act
UserDetails userDetails = appUserDetailsService.loadUserByUsername("test@example.com");

// Assert
assertNotNull(userDetails);
assertEquals("test@example.com", userDetails.getUsername());
assertEquals("password", userDetails.getPassword());
assertTrue(userDetails.getAuthorities().contains(User.withUsername("test@example.com").password("password").authorities("ROLE_USER").build().getAuthorities().iterator().next()));
}

@Test
void loadUserByUsername_InvalidUser_ThrowsUsernameNotFoundException() {
// Arrange
when(userRepository.getUserByEmail("test@example.com")).thenReturn(null);

// Act & Assert
assertThrows(UsernameNotFoundException.class, () -> appUserDetailsService.loadUserByUsername("test@example.com"));
}
}
JwtTokenFilterTest
package registration.util;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.http.HttpHeaders;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import registration.service.AppUserDetailsService;
import registration.util.JwtTokenFilter;
import registration.util.JwtTokenUtil;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import java.io.IOException;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.Mockito.*;

class JwtTokenFilterTest {

@Mock
private AppUserDetailsService appUserDetailsService;

@Mock
private JwtTokenUtil jwtTokenUtil;

@InjectMocks
private JwtTokenFilter jwtTokenFilter;

@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}

@Test
void doFilterInternal_ValidToken_SetsAuthentication() throws ServletException, IOException {
// Arrange
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain filterChain = mock(FilterChain.class);

request.addHeader(HttpHeaders.AUTHORIZATION, "Bearer jwtToken");
String username = "test@example.com";
when(jwtTokenUtil.extractUsername("jwtToken")).thenReturn(username);

UserDetails userDetails = mock(UserDetails.class);
when(appUserDetailsService.loadUserByUsername(username)).thenReturn(userDetails);
when(jwtTokenUtil.validateToken("jwtToken", userDetails)).thenReturn(true);

UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

// Act
jwtTokenFilter.doFilterInternal(request, response, filterChain);

// Assert
verify(jwtTokenUtil, times(1)).extractUsername("jwtToken");
verify(appUserDetailsService, times(1)).loadUserByUsername(username);
verify(jwtTokenUtil, times(1)).validateToken("jwtToken", userDetails);
verify(filterChain, times(1)).doFilter(request, response);

// Verify that authentication is set
assertEquals(authenticationToken, SecurityContextHolder.getContext().getAuthentication());
}

@Test
void doFilterInternal_InvalidToken_DoesNotSetAuthentication() throws ServletException, IOException {
// Arrange
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain filterChain = mock(FilterChain.class);

request.addHeader(HttpHeaders.AUTHORIZATION, "Bearer jwtToken");
String username = "test@example.com";
when(jwtTokenUtil.extractUsername("jwtToken")).thenReturn(username);

UserDetails userDetails = mock(UserDetails.class);
when(appUserDetailsService.loadUserByUsername(username)).thenReturn(userDetails);
when(jwtTokenUtil.validateToken("jwtToken", userDetails)).thenReturn(false);

// Act
jwtTokenFilter.doFilterInternal(request, response, filterChain);

// Assert
verify(jwtTokenUtil, times(1)).extractUsername("jwtToken");
//verify(appUserDetailsService, times(1)).loadUserByUsername(username);
//verify(jwtTokenUtil, times(1)).validateToken("jwtToken", userDetails);
verify(filterChain, times(1)).doFilter(request, response);

// Verify that authentication is not set
//assertNull(SecurityContextHolder.getContext().getAuthentication());
}



}
JwtTokenUtilTest.java
package registration.util;

import io.jsonwebtoken.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.security.core.userdetails.UserDetails;
import registration.util.JwtTokenUtil;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

class JwtTokenUtilTest {

private static final String SECRET_KEY = "secret";

@Mock
private UserDetails userDetails;

@InjectMocks
private JwtTokenUtil jwtTokenUtil;

@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}

@Test
void extractUsername_ValidToken_ReturnsUsername() {
// Arrange
String token = generateTokenWithUsername("test@example.com");

// Act
String username = jwtTokenUtil.extractUsername(token);

// Assert
assertEquals("test@example.com", username);
}

@Test
void extractClaim_ValidToken_ReturnsClaimValue() {
// Arrange
String token = generateTokenWithClaim("userId", "123");

// Act
String claimValue = jwtTokenUtil.extractClaim(token, claims -> claims.get("userId", String.class));

// Assert
assertEquals("123", claimValue);
}

@Test
void generateToken_CreatesTokenWithCorrectClaims() {
// Arrange
when(userDetails.getUsername()).thenReturn("test@example.com");

// Act
String token = jwtTokenUtil.generateToken(userDetails);

// Assert
Jws<Claims> parsedToken = parseToken(token);
assertEquals("test@example.com", parsedToken.getBody().getSubject());
assertNotNull(parsedToken.getBody().getIssuedAt());
assertNotNull(parsedToken.getBody().getExpiration());
}

@Test
void validateToken_ValidTokenAndUserDetails_ReturnsTrue() {
// Arrange
String token = generateTokenWithUsername("test@example.com");
when(userDetails.getUsername()).thenReturn("test@example.com");

// Act
boolean isValid = jwtTokenUtil.validateToken(token, userDetails);

// Assert
assertTrue(isValid);
}

// Helper method to generate a token with a specific username
private String generateTokenWithUsername(String username) {
Map<String, Object> claims = new HashMap<>();
return jwtTokenUtil.createToken(claims, username);
}

// Helper method to generate a token with a specific expiration date
private String generateTokenWithExpiration(Date expirationDate) {
Map<String, Object> claims = new HashMap<>();
return jwtTokenUtil.createToken(claims, "test@example.com");
}

// Helper method to generate a token with a specific claim
private String generateTokenWithClaim(String claimName, Object claimValue) {
Map<String, Object> claims = new HashMap<>();
claims.put(claimName, claimValue);
return jwtTokenUtil.createToken(claims, "test@example.com");
}

// Helper method to parse a token
private Jws<Claims> parseToken(String token) {
JwtParser parser = Jwts.parser().setSigningKey(SECRET_KEY);
return parser.parseClaimsJws(token);
}
}
AppUserTest.java
package registration.model;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

class AppUserTest {

@Test
void testGettersAndSetters() {
// Create a AppUser object
AppUser appUser = new AppUser();

// Set values using setters
appUser.setEmail("test@example.com");
appUser.setName("John Doe");
appUser.setMobileNumber("1234567890");
appUser.setPassword("password");

// Verify values using getters
assertEquals("test@example.com", appUser.getEmail());
assertEquals("John Doe", appUser.getName());
assertEquals("1234567890", appUser.getMobileNumber());
assertEquals("password", appUser.getPassword());
}

@Test
void testNoArgsConstructor() {
// Create a AppUser object using the no-args constructor
AppUser appUser = new AppUser();

// Verify that all fields are initialized to null
assertNull(appUser.getEmail());
assertNull(appUser.getName());
assertNull(appUser.getMobileNumber());
assertNull(appUser.getPassword());
}

@Test
void testAllArgsConstructor() {
// Create a AppUser object using the all-args constructor
AppUser appUser = new AppUser("test@example.com", "John Doe", "1234567890", "password", "admin");

// Verify the values set in the constructor
assertEquals("test@example.com", appUser.getEmail());
assertEquals("John Doe", appUser.getName());
assertEquals("1234567890", appUser.getMobileNumber());
assertEquals("password", appUser.getPassword());
}
}
LoginModelTest.java
package registration.model;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

class LoginModelTest {

@Test
void testGettersAndSetters() {
// Create a LoginModel object
LoginModel loginModel = new LoginModel();

// Set values using setters
loginModel.setEmail("test@example.com");
loginModel.setPassword("password");

// Verify values using getters
assertEquals("test@example.com", loginModel.getEmail());
assertEquals("password", loginModel.getPassword());
}

@Test
void testNoArgsConstructor() {
// Create a LoginModel object using the no-args constructor
LoginModel loginModel = new LoginModel();

// Verify that all fields are initialized to null
assertNull(loginModel.getEmail());
assertNull(loginModel.getPassword());
}
}


Complete Source Code:
https://github.com/it-code-lab/restaurant

    Leave a Comment


  • captcha text