Skip to content

Commit

Permalink
Merge pull request #260 from catenax-ng/feature/TRI-1213-use-real-dis…
Browse files Browse the repository at this point in the history
…covery-service

feat(ess):[TRI-1213] Switch to real discovery service implementation
  • Loading branch information
ds-jhartmann authored Apr 26, 2023
2 parents b218852 + ed7fcdf commit 6eec5b8
Show file tree
Hide file tree
Showing 14 changed files with 175 additions and 30 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Changed
- Replaced Discovery Service mock with real implementation

### Known knowns
- PLACEHOLDER REMOVE IF EMPTY: risks that were introduced or discovered in the release and are known but not resolved

Expand Down
4 changes: 4 additions & 0 deletions charts/irs-helm/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- New config entries for portal user, used to call discovery service
- `portal.oauth2.clientId`
- `portal.oauth2.clientSecret`

## [5.1.1] - 2023-04-17
### Fixed
Expand Down
6 changes: 6 additions & 0 deletions charts/irs-helm/templates/configmap-spring-app-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,14 @@ data:
keycloak:
client-id: "${KEYCLOAK_OAUTH2_CLIENT_ID}" # taken from secret ENV
client-secret: "${KEYCLOAK_OAUTH2_CLIENT_SECRET}" # taken from secret ENV
portal:
client-id: ${PORTAL_OAUTH2_CLIENT_ID} # taken from secret ENV
client-secret: ${PORTAL_OAUTH2_CLIENT_SECRET} # taken from secret ENV
provider:
keycloak:
token-uri: {{ tpl (.Values.keycloak.oauth2.clientTokenUri | default "http://localhost") . | quote }}
portal:
token-uri: {{ tpl (.Values.keycloak.oauth2.clientTokenUri | default "http://localhost") . | quote }}
resourceserver:
jwt:
jwk-set-uri: {{ tpl (.Values.keycloak.oauth2.jwkSetUri | default "http://localhost") . | quote }}
Expand Down Expand Up @@ -101,6 +106,7 @@ data:
url: {{ tpl (.Values.irsUrl | default "") . | quote }}
discovery:
endpoint: {{ tpl (.Values.discovery.endpoint | default "") . | quote }}
oAuthClientId: {{ .Values.discovery.oAuthClientId | default "portal" }}
{{- if .Values.discovery.mockEdcAddress }}
mockEdcAddress:
{{- tpl (toYaml .Values.discovery.mockEdcAddress) . | nindent 10 }}
Expand Down
10 changes: 10 additions & 0 deletions charts/irs-helm/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ spec:
secretKeyRef:
name: {{ template "irs.secretName" . }}
key: keycloakClientSecret
- name: PORTAL_OAUTH2_CLIENT_ID
valueFrom:
secretKeyRef:
name: {{ template "irs.secretName" . }}
key: portalClientId
- name: PORTAL_OAUTH2_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: {{ template "irs.secretName" . }}
key: portalClientSecret
- name: EDC_API_KEY_SECRET
valueFrom:
secretKeyRef:
Expand Down
2 changes: 2 additions & 0 deletions charts/irs-helm/templates/secrets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ data:
minioPassword: {{ .Values.minioPassword | default "minioPass" | b64enc | quote }}
keycloakClientId: {{ .Values.keycloak.oauth2.clientId | default "keycloakClientId" | b64enc | quote }}
keycloakClientSecret: {{ .Values.keycloak.oauth2.clientSecret | default "keycloakClientSecret" | b64enc | quote }}
portalClientId: {{ .Values.portal.oauth2.clientId | default "portalClientId" | b64enc | quote }}
portalClientSecret: {{ .Values.portal.oauth2.clientSecret | default "portalClientSecret" | b64enc | quote }}
edcApiSecret: {{ .Values.edc.controlplane.apikey.secret | default "" | b64enc | quote }}
{{- if .Values.grafana.enabled }}
grafanaUser: {{ .Values.grafana.user | default "grafana" | b64enc | quote }}
Expand Down
5 changes: 5 additions & 0 deletions charts/irs-helm/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ keycloak:
clientSecret: # <keycloak-client-secret>
clientTokenUri: # <keycloak-token-uri>
jwkSetUri: # <keycloak-jwkset-uri>
portal:
oauth2:
clientId: # <portal-client-id>
clientSecret: # <portal-client-secret>
edc:
provider:
host: # EDC Provider Host URL
Expand Down Expand Up @@ -172,6 +176,7 @@ edc:
discovery:
endpoint: # EDC Discovery Service endpoint
mockEdcAddress: # Map of BPNs and EDC Provider URLs - this overrides any real Discovery Service for the given BPN
oAuthClientId: portal # ID of the OAuth2 client registration to use, see config spring.security.oauth2.client

ess:
mockEdcResult: # Map of BPNs and YES/NO strings - this configures the ESS mock response in case it called to investigate a BPN
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@
package org.eclipse.tractusx.ess.discovery;

import java.util.Collections;
import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
Expand All @@ -38,17 +40,21 @@ interface EdcDiscoveryClient {

/**
* Lookup EDC Address for BPN number
*
* @param bpn number
* @return EDC addresses
*/
EdcAddressResponse getEdcBaseUrl(String bpn);
EdcAddressResponse[] getEdcBaseUrl(String bpn);

}

/**
* EDC Discovery Service Rest Client Stub used in local environment
*/
@Service
@Profile({ "local",
"stubtest"
})
class EdcDiscoveryClientLocalStub implements EdcDiscoveryClient {

private final EdcDiscoveryMockConfig edcDiscoveryMockConfig;
Expand All @@ -58,23 +64,23 @@ class EdcDiscoveryClientLocalStub implements EdcDiscoveryClient {
}

@Override
public EdcAddressResponse getEdcBaseUrl(final String bpn) {
final Optional<String> connectorEndpoint = Optional.ofNullable(
public EdcAddressResponse[] getEdcBaseUrl(final String bpn) {
final Optional<List<String>> connectorEndpoint = Optional.ofNullable(
this.edcDiscoveryMockConfig.getMockEdcAddress().get(bpn));

return EdcAddressResponse.builder()
.bpn(bpn)
.connectorEndpoint(connectorEndpoint
.map(Collections::singletonList)
.orElseGet(Collections::emptyList))
.build();
return new EdcAddressResponse[] { EdcAddressResponse.builder()
.bpn(bpn)
.connectorEndpoint(connectorEndpoint.orElseGet(
Collections::emptyList)).build()
};
}

}

/**
* EDC Discovery Service Rest Client Implementation
*/
@Service
@Profile({ "!local && !stubtest" })
class EdcDiscoveryClientImpl implements EdcDiscoveryClient {

private final RestTemplate restTemplate;
Expand All @@ -87,9 +93,10 @@ class EdcDiscoveryClientImpl implements EdcDiscoveryClient {
}

@Override
public EdcAddressResponse getEdcBaseUrl(final String bpn) {
public EdcAddressResponse[] getEdcBaseUrl(final String bpn) {
final UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(discoveryAddressUrl);

return restTemplate.postForObject(uriBuilder.build().toUri(), Collections.singletonList(bpn), EdcAddressResponse.class);
return restTemplate.postForObject(uriBuilder.build().toUri(), Collections.singletonList(bpn),
EdcAddressResponse[].class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,23 @@ public class EdcDiscoveryFacade {

/**
* Returns EDC base url or empty
*
* @param bpn number
* @return address
*/
public Optional<String> getEdcBaseUrl(final String bpn) {
final EdcAddressResponse edcAddressResponse = edcDiscoveryClient.getEdcBaseUrl(bpn);
log.info("Requesting EDC URLs for BPN '{}'", bpn);
final EdcAddressResponse[] edcBaseUrl = edcDiscoveryClient.getEdcBaseUrl(bpn);
final List<EdcAddressResponse> edcAddressResponse;
if (edcBaseUrl == null) {
return Optional.empty();
} else {
edcAddressResponse = List.of(edcBaseUrl);
}

final List<String> endpoints = edcAddressResponse.getConnectorEndpoint();
final List<String> endpoints = edcAddressResponse.stream()
.flatMap(response -> response.getConnectorEndpoint().stream())
.toList();

return endpoints.stream()
.filter(StringUtils::isNotBlank)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
********************************************************************************/
package org.eclipse.tractusx.ess.discovery;

import java.util.List;
import java.util.Map;

import lombok.Data;
Expand All @@ -36,6 +37,6 @@
@ConfigurationProperties("ess.discovery")
@Data
public class EdcDiscoveryMockConfig {
private Map<String, String> mockEdcAddress;
private Map<String, List<String>> mockEdcAddress;
private Map<String, SupplyChainImpacted> mockEdcResult;
}
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ private void sendNotifications(final Jobs completedJob, final BpnInvestigationJo
final Map<String, List<String>> bpns) {
bpns.forEach((bpn, globalAssetIds) -> {
final Optional<String> edcBaseUrl = edcDiscoveryFacade.getEdcBaseUrl(bpn);
log.info("Received EDC URL for BPN '{}': '{}'", bpn, edcBaseUrl);
edcBaseUrl.ifPresentOrElse(url -> {
try {
final String notificationId = sendEdcNotification(bpn, url,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,74 @@
import static org.mockito.Mockito.verify;

import java.util.Collections;
import java.util.List;

import org.junit.jupiter.api.Test;
import org.springframework.web.client.RestTemplate;

class EdcDiscoveryClientImplTest {

private final RestTemplate restTemplate = mock(RestTemplate.class);
private final EdcDiscoveryClient bpdmClient = new EdcDiscoveryClientImpl(restTemplate, "url/api/administration/connectors/discovery");
private final EdcDiscoveryClient edcDiscoveryClient = new EdcDiscoveryClientImpl(restTemplate,
"url/api/administration/connectors/discovery");

@Test
void shouldCallExternalServiceOnceAndGetEdcAddressResponse() {
// Arrange
final String bpn = "BPNS000000000DDD";
final EdcAddressResponse mockResponse = EdcAddressResponse.builder().bpn(bpn).connectorEndpoint(Collections.singletonList("http://edc-address.com")).build();
doReturn(mockResponse).when(restTemplate).postForObject(any(), any(), eq(EdcAddressResponse.class));
final EdcAddressResponse[] mockResponse = new EdcAddressResponse[] { EdcAddressResponse.builder()
.bpn(bpn)
.connectorEndpoint(
Collections.singletonList(
"http://edc-address.com")).build()
};
doReturn(mockResponse).when(restTemplate).postForObject(any(), any(), eq(EdcAddressResponse[].class));

final EdcAddressResponse edcAddressResponse = bpdmClient.getEdcBaseUrl(bpn);
// Act
final List<EdcAddressResponse> edcAddressResponse = List.of(edcDiscoveryClient.getEdcBaseUrl(bpn));

assertThat(edcAddressResponse).isNotNull();
assertThat(edcAddressResponse.getBpn()).isEqualTo(bpn);
assertThat(edcAddressResponse.getConnectorEndpoint()).isNotEmpty();
verify(this.restTemplate, times(1)).postForObject(any(), any(), eq(EdcAddressResponse.class));
// Assert
assertThat(edcAddressResponse).isNotNull().hasSize(1);
assertThat(edcAddressResponse.get(0).getBpn()).isEqualTo(bpn);
assertThat(edcAddressResponse.get(0).getConnectorEndpoint()).isNotEmpty();
verify(this.restTemplate, times(1)).postForObject(any(), any(), eq(EdcAddressResponse[].class));
}

@Test
void shouldCallExternalServiceWithTwoEndpointsOnceAndGetEdcAddressResponse() {
// Arrange
final String bpn = "BPNS000000000DDD";
final EdcAddressResponse[] mockResponse = new EdcAddressResponse[] { EdcAddressResponse.builder()
.bpn(bpn)
.connectorEndpoint(
List.of("http://edc-address.com",
"http://edc-address1.com")).build()
};
doReturn(mockResponse).when(restTemplate).postForObject(any(), any(), eq(EdcAddressResponse[].class));

// Act
final List<EdcAddressResponse> edcAddressResponse = List.of(edcDiscoveryClient.getEdcBaseUrl(bpn));

// Assert
assertThat(edcAddressResponse).isNotNull().hasSize(1);
assertThat(edcAddressResponse.get(0).getBpn()).isEqualTo(bpn);
assertThat(edcAddressResponse.get(0).getConnectorEndpoint()).hasSize(2);
assertThat(edcAddressResponse.get(0).getConnectorEndpoint().get(0)).isEqualTo("http://edc-address.com");
assertThat(edcAddressResponse.get(0).getConnectorEndpoint().get(1)).isEqualTo("http://edc-address1.com");
verify(this.restTemplate, times(1)).postForObject(any(), any(), eq(EdcAddressResponse[].class));
}

@Test
void shouldReturnNullWhenRestTemplateReturnsNull() {
// Arrange
final String bpn = "BPNS000000000DDD";
doReturn(null).when(restTemplate).postForObject(any(), any(), eq(EdcAddressResponse[].class));

// Act
final EdcAddressResponse[] edcBaseUrl = edcDiscoveryClient.getEdcBaseUrl(bpn);

// Assert
assertThat(edcBaseUrl).isNull();
verify(this.restTemplate, times(1)).postForObject(any(), any(), eq(EdcAddressResponse[].class));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,37 +23,74 @@
package org.eclipse.tractusx.ess.discovery;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

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

import org.junit.jupiter.api.Test;

class EdcDiscoveryFacadeTest {

private final EdcDiscoveryMockConfig edcDiscoveryMockConfig = mock(
EdcDiscoveryMockConfig.class);
private final EdcDiscoveryFacade edcDiscoveryFacade = new EdcDiscoveryFacade(new EdcDiscoveryClientLocalStub(edcDiscoveryMockConfig));
private final EdcDiscoveryMockConfig edcDiscoveryMockConfig = mock(EdcDiscoveryMockConfig.class);
private final EdcDiscoveryFacade edcDiscoveryFacade = new EdcDiscoveryFacade(
new EdcDiscoveryClientLocalStub(edcDiscoveryMockConfig));

@Test
void shouldReturnEdcBaseUrl() {
// Arrange
final String bpn = "BPNS000000000DDD";
final String url = "http://edc-url";
when(edcDiscoveryMockConfig.getMockEdcAddress()).thenReturn(Map.of(bpn, url));
when(edcDiscoveryMockConfig.getMockEdcAddress()).thenReturn(Map.of(bpn, List.of(url)));

// Act
final Optional<String> edcBaseUrl = edcDiscoveryFacade.getEdcBaseUrl(bpn);

// Assert
assertThat(edcBaseUrl).isNotEmpty().contains(url);
}

@Test
void shouldReturnEdcBaseUrls() {
// Arrange
final String bpn = "BPNS000000000DDD";
final String url1 = "http://edc-url1";
final String url2 = "http://edc-url2";
when(edcDiscoveryMockConfig.getMockEdcAddress()).thenReturn(Map.of(bpn, List.of(url1, url2)));

// Act
final Optional<String> edcBaseUrl = edcDiscoveryFacade.getEdcBaseUrl(bpn);

// Assert
assertThat(edcBaseUrl).isNotEmpty().contains(url1);
}

@Test
void shouldReturnResponseWithEmptyConnectorEndpointList() {
// Arrange
when(edcDiscoveryMockConfig.getMockEdcAddress()).thenReturn(Map.of());

// Act
final Optional<String> edcBaseUrl = edcDiscoveryFacade.getEdcBaseUrl("not_existing");

// Assert
assertThat(edcBaseUrl).isEmpty();
}

@Test
void shouldReturnEmptyOptionalWhenClientReturnsNull() {
// Arrange
final EdcDiscoveryClientLocalStub clientMock = mock(EdcDiscoveryClientLocalStub.class);
final EdcDiscoveryFacade edcDiscoveryFacade = new EdcDiscoveryFacade(clientMock);
when(clientMock.getEdcBaseUrl(anyString())).thenReturn(null);

// Act
final Optional<String> edcBaseUrl = edcDiscoveryFacade.getEdcBaseUrl("not_existing");

// Assert
assertThat(edcBaseUrl).isEmpty();
}

Expand Down
Loading

0 comments on commit 6eec5b8

Please sign in to comment.