Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AA Work #4

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions fiu-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@
<version>${project.version}</version>
<scope>compile</scope>
</dependency>

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

<build>
Expand Down
12 changes: 12 additions & 0 deletions fiu-api/src/main/java/com/rupeesense/fi/APIConstants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.rupeesense.fi;

public class APIConstants {

public static final String ACCOUNT_AGGREGATOR_BASE_PATH = "/v1/account_aggregator";

public static final String RAISE_PERIODIC_CONSENT_PATH = "/consent/periodic";

public static final String PLACE_DATA_REQUEST_PATH = "/data/request/{userId}";

public static final String AA_CONSENT_NOTIFICATION = "/aa/Consent/Notification";
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.rupeesense.fi;

import java.util.TimeZone;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
Expand All @@ -9,7 +10,7 @@
public class FIUServiceApplication {

public static void main(String[] args) {
System.setProperty("user.timezone", "UTC");
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
SpringApplication.run(FIUServiceApplication.class, args);
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.rupeesense.fi.controllers;

import static com.rupeesense.fi.APIConstants.ACCOUNT_AGGREGATOR_BASE_PATH;
import static com.rupeesense.fi.APIConstants.PLACE_DATA_REQUEST_PATH;
import static com.rupeesense.fi.APIConstants.RAISE_PERIODIC_CONSENT_PATH;

import com.rupeesense.fi.aa.AccountAggregatorOrchestratorService;
import com.rupeesense.fi.api.request.ConsentRequest;
import com.rupeesense.fi.api.response.ConsentResponse;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* Controller that exposes endpoints to interact with Account Aggregators.
*/
@RestController
@RequestMapping(ACCOUNT_AGGREGATOR_BASE_PATH)
public class AAOrchestrationController {

private final AccountAggregatorOrchestratorService accountAggregatorOrchestratorService;

@Autowired
public AAOrchestrationController(AccountAggregatorOrchestratorService accountAggregatorOrchestratorService) {
this.accountAggregatorOrchestratorService = accountAggregatorOrchestratorService;
}

@PostMapping(path = RAISE_PERIODIC_CONSENT_PATH,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public ConsentResponse initiatePeriodicConsentRequest(@RequestBody @Valid ConsentRequest request) {
return accountAggregatorOrchestratorService.initiateConsent(request);
}

@PostMapping(path = PLACE_DATA_REQUEST_PATH,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public void placeDataRequestForUser(@PathVariable("userId") @NotBlank String userId) {
accountAggregatorOrchestratorService.placeDataRequest(userId);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.rupeesense.fi.controllers;

import static com.rupeesense.fi.APIConstants.AA_CONSENT_NOTIFICATION;

import com.rupeesense.fi.api.request.ConsentNotificationRequest;
import com.rupeesense.fi.fiu.FIUService;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
Expand All @@ -13,7 +16,7 @@
* Controller to act as an FIU
*/
@RestController
@RequestMapping("/v1/fiu")
@RequestMapping
public class FIUController {

private final FIUService fiuService;
Expand All @@ -23,10 +26,10 @@ public FIUController(FIUService fiuService) {
this.fiuService = fiuService;
}

@PostMapping(path = "/notification/consent",
@PostMapping(path = AA_CONSENT_NOTIFICATION,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public void receiveConsentNotification(@RequestBody ConsentNotificationRequest consentNotificationRequest) {
public void receiveConsentNotification(@RequestBody @Valid ConsentNotificationRequest consentNotificationRequest) {
fiuService.updateConsentAndHandleFromNotification(consentNotificationRequest);
}
}
2 changes: 1 addition & 1 deletion fiu-api/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ spring.datasource.url=jdbc:mysql://localhost:3306/fiu_datastore
spring.datasource.username=root
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=update
app.fiu.fiu-id=RUP0328
app.fiu.fiu-id=RUP0328
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package com.rupeesense.fi.controllers;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.rupeesense.fi.APIConstants;
import com.rupeesense.fi.aa.AccountAggregatorOrchestratorService;
import com.rupeesense.fi.api.request.ConsentRequest;
import com.rupeesense.fi.api.response.ConsentResponse;
import com.rupeesense.fi.model.AAIdentifier;
import com.rupeesense.fi.model.ConsentHandleStatus;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

@SpringBootTest
@AutoConfigureMockMvc
@ExtendWith(SpringExtension.class)
public class AAOrchestrationControllerTest {

@Autowired
private MockMvc mockMvc;

@MockBean
private AccountAggregatorOrchestratorService accountAggregatorOrchestratorService;

@Autowired
private WebApplicationContext webApplicationContext;

@BeforeEach
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}

@Test
public void testInitiatePeriodicConsentRequest() throws Exception {
ConsentRequest consentRequest = new ConsentRequest("test@onemoney", AAIdentifier.ONEMONEY);
ConsentResponse consentResponse = new ConsentResponse("test@onemoney",
AAIdentifier.ONEMONEY, "requestId", ConsentHandleStatus.PENDING);

when(accountAggregatorOrchestratorService.initiateConsent(any(ConsentRequest.class)))
.thenReturn(consentResponse);

mockMvc.perform(post(APIConstants.ACCOUNT_AGGREGATOR_BASE_PATH + APIConstants.RAISE_PERIODIC_CONSENT_PATH)
.content(asJsonString(consentRequest))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().json(asJsonString(consentResponse)));
}

@Test
public void testInitiatePeriodicConsentRequestWithInvalidRequest() throws Exception {
ConsentRequest consentRequest = new ConsentRequest();
ConsentResponse consentResponse = new ConsentResponse("test@onemoney",
AAIdentifier.ONEMONEY, "requestId", ConsentHandleStatus.PENDING);

when(accountAggregatorOrchestratorService.initiateConsent(any(ConsentRequest.class)))
.thenReturn(consentResponse);

mockMvc.perform(post(APIConstants.ACCOUNT_AGGREGATOR_BASE_PATH + APIConstants.RAISE_PERIODIC_CONSENT_PATH)
.content(asJsonString(consentRequest))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isBadRequest());
}

@Test
public void testPlaceDataRequestForUser_Success() throws Exception {
String userId = "123";

mockMvc.perform(MockMvcRequestBuilders.post(APIConstants.ACCOUNT_AGGREGATOR_BASE_PATH + APIConstants.PLACE_DATA_REQUEST_PATH, userId)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());

verify(accountAggregatorOrchestratorService).placeDataRequest(userId);
}


public static String asJsonString(final Object obj) {
try {
return new ObjectMapper().writeValueAsString(obj);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.rupeesense.fi.controllers;

import static org.mockito.Mockito.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.rupeesense.fi.APIConstants;
import com.rupeesense.fi.api.request.ConsentNotificationRequest;
import com.rupeesense.fi.fiu.FIUService;
import com.rupeesense.fi.model.ConsentStatus;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

public class FIUControllerTest {

private MockMvc mockMvc;

@Mock
private FIUService fiuService;

private FIUController fiuController;

@BeforeEach
public void setup() {
MockitoAnnotations.openMocks(this);
fiuController = new FIUController(fiuService);
mockMvc = MockMvcBuilders.standaloneSetup(fiuController).build();
}

@Test
public void testReceiveConsentNotificationWithInvalidRequest() throws Exception {
ConsentNotificationRequest notificationRequest = new ConsentNotificationRequest();

mockMvc.perform(MockMvcRequestBuilders.post("/aa/Consent/Notification")
.contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(notificationRequest)))
.andExpect(status().isBadRequest());

verify(fiuService, never()).updateConsentAndHandleFromNotification(any(ConsentNotificationRequest.class));
}

@Test
public void testReceiveConsentNotification_Success() throws Exception {
ConsentNotificationRequest dummyRequest = new ConsentNotificationRequest();

dummyRequest.setVer("1.0");
dummyRequest.setTimestamp("2023-07-07T10:00:00Z");
dummyRequest.setTxnid("123456");

ConsentNotificationRequest.Notifier notifier = new ConsentNotificationRequest.Notifier("email", "[email protected]");
dummyRequest.setNotifier(notifier);

ConsentNotificationRequest.ConsentStatusNotification consentStatusNotification = new ConsentNotificationRequest.ConsentStatusNotification("consent123", "handle123",
ConsentStatus.ACTIVE);
dummyRequest.setConsentStatusNotification(consentStatusNotification);

mockMvc.perform(MockMvcRequestBuilders.post(APIConstants.AA_CONSENT_NOTIFICATION)
.contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(dummyRequest)))
.andExpect(status().isOk());

verify(fiuService, times(1)).updateConsentAndHandleFromNotification(any(ConsentNotificationRequest.class));
}

// Helper method to convert object to JSON string
private static String asJsonString(Object obj) {
try {
return new ObjectMapper().writeValueAsString(obj);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
13 changes: 13 additions & 0 deletions fiu-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@
<scope>compile</scope>
</dependency>

<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>mockwebserver</artifactId>
<version>4.0.1</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
Expand Down
2 changes: 2 additions & 0 deletions fiu-core/src/main/java/com/rupeesense/fi/CoreModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public class CoreModule {

public static final String ONE_MONEY_CLIENT_NAME = "one-money-web-client";

public static final String SETU_CLIENT_NAME = "setu-web-client";

//TODO: make this config driven
@Bean(name = ONE_MONEY_CLIENT_NAME)
public WebClient getOneMoneyWebClient() {
Expand Down
Loading