Skip to content

Commit c0ffeeb

Browse files
EPA-265: Increase test coverage
1 parent 178e9e2 commit c0ffeeb

10 files changed

Lines changed: 909 additions & 19 deletions

File tree

epa4all-client/src/main/java/com/oviva/telematik/epa4all/client/internal/Epa4AllClientFactory.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,17 @@ public static Epa4AllClientFactory create(
6060
KonnektorService konnektorService,
6161
InetSocketAddress konnektorProxyAddress,
6262
Environment environment,
63-
KeyStore trustStore,
63+
KeyStore tiTrustStore,
6464
String telematikId) {
6565

66-
var telematikSslContext = SslContextBuilder.buildSslContext(trustStore);
67-
var outerHttpClientTelematik = buildOuterHttpClient(konnektorProxyAddress, telematikSslContext);
66+
var telematikSslContext = SslContextBuilder.buildSslContext(tiTrustStore);
67+
var outerHttpClientTelematik =
68+
buildOuterHttpClientWithTlsContext(konnektorProxyAddress, telematikSslContext);
6869

6970
var informationService = buildInformationService(environment, outerHttpClientTelematik);
7071

7172
var proxyServer =
72-
buildVauProxy(environment, konnektorProxyAddress, trustStore, telematikSslContext);
73+
buildVauProxy(environment, konnektorProxyAddress, tiTrustStore, telematikSslContext);
7374

7475
var serverInfo = proxyServer.start();
7576
var vauProxyServerListener = serverInfo.listenAddress();
@@ -83,7 +84,8 @@ public static Epa4AllClientFactory create(
8384
var outerHttpClient = buildOuterHttpClient(konnektorProxyAddress);
8485

8586
var authorizationService =
86-
buildAuthorizationService(innerVauClient, outerHttpClient, konnektorService, card);
87+
buildAuthorizationService(
88+
tiTrustStore, innerVauClient, outerHttpClient, konnektorService, card);
8789

8890
var client =
8991
new SoapClientFactory(
@@ -99,6 +101,7 @@ public Epa4AllClient newClient() {
99101
}
100102

101103
private static AuthorizationService buildAuthorizationService(
104+
KeyStore telematikTrustStore,
102105
com.oviva.telematik.vau.httpclient.HttpClient innerVauClient,
103106
HttpClient outerHttpClient,
104107
KonnektorService konnektorService,
@@ -107,7 +110,9 @@ private static AuthorizationService buildAuthorizationService(
107110
var signer = new EccSignatureAdapter(konnektorService, card);
108111

109112
var authnChallengeResponder =
110-
new AuthnChallengeResponder(signer, new OidcClient(outerHttpClient));
113+
new AuthnChallengeResponder(
114+
signer,
115+
new OidcClient(outerHttpClient, new OidcDiscoveryValidatorImpl(telematikTrustStore)));
111116
var authnClientAttester = new AuthnClientAttester(signer);
112117
return new AuthorizationService(
113118
innerVauClient, outerHttpClient, authnChallengeResponder, authnClientAttester);
@@ -203,13 +208,13 @@ private static com.oviva.telematik.vau.httpclient.HttpClient buildInnerHttpClien
203208

204209
private static HttpClient buildOuterHttpClient(InetSocketAddress konnektorProxyAddress) {
205210
try {
206-
return buildOuterHttpClient(konnektorProxyAddress, SSLContext.getDefault());
211+
return buildOuterHttpClientWithTlsContext(konnektorProxyAddress, SSLContext.getDefault());
207212
} catch (NoSuchAlgorithmException e) {
208213
throw new ClientException("failed creating client", e);
209214
}
210215
}
211216

212-
private static HttpClient buildOuterHttpClient(
217+
private static HttpClient buildOuterHttpClientWithTlsContext(
213218
InetSocketAddress konnektorProxyAddress, SSLContext sslContext) {
214219

215220
return HttpClient.newBuilder()

epa4all-client/src/test/java/com/oviva/telematik/epa4all/client/internal/Epa4AllClientFactoryTest.java

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,17 @@
55

66
import com.oviva.epa.client.KonnektorService;
77
import com.oviva.epa.client.model.SmcbCard;
8+
import com.oviva.telematik.epa4all.client.Environment;
89
import com.oviva.telematik.epaapi.SoapClientFactory;
910
import com.oviva.telematik.vau.epa4all.client.Epa4AllClientException;
1011
import com.oviva.telematik.vau.epa4all.client.authz.AuthorizationService;
1112
import com.oviva.telematik.vau.epa4all.client.info.InformationService;
1213
import com.oviva.telematik.vau.proxy.VauProxy;
14+
import java.net.InetSocketAddress;
15+
import java.security.KeyStore;
16+
import java.security.NoSuchAlgorithmException;
1317
import java.util.List;
18+
import javax.net.ssl.SSLContext;
1419
import org.junit.jupiter.api.BeforeEach;
1520
import org.junit.jupiter.api.Test;
1621
import org.junit.jupiter.api.extension.ExtendWith;
@@ -128,4 +133,122 @@ void findSmcBCard_shouldThrowWhenTelematikIdNotFound() {
128133
.getMessage()
129134
.contains("no SMC-B card found for telematikId [ nonexistintent-telematik-id ]"));
130135
}
136+
137+
@Test
138+
void findSmcBCard_singleCard_nullTelematikId_returnsCard() {
139+
when(konnektorService.listSmcbCards()).thenReturn(List.of(mockCard1));
140+
141+
var result = Epa4AllClientFactory.findSmcBCard(konnektorService, null);
142+
143+
assertEquals(mockCard1, result);
144+
}
145+
146+
@Test
147+
void findSmcBCard_shouldSelectSecondCardByTelematikId() {
148+
when(konnektorService.listSmcbCards()).thenReturn(List.of(mockCard1, mockCard2));
149+
150+
var result = Epa4AllClientFactory.findSmcBCard(konnektorService, "test-telematik-id-2");
151+
152+
assertEquals(mockCard2, result);
153+
}
154+
155+
@Test
156+
void findSmcBCard_notFound_errorMessageContainsAvailableCardDetails() {
157+
when(konnektorService.listSmcbCards()).thenReturn(List.of(mockCard1, mockCard2));
158+
159+
var exception =
160+
assertThrows(
161+
Epa4AllClientException.class,
162+
() -> Epa4AllClientFactory.findSmcBCard(konnektorService, "unknown-id"));
163+
164+
var msg = exception.getMessage();
165+
assertTrue(msg.contains("'test-telematik-id-1' (Test Holder)"));
166+
assertTrue(msg.contains("'test-telematik-id-2' (Test Holder)"));
167+
}
168+
169+
@Test
170+
void create_noCardsFound_throwsEpa4AllClientException() throws NoSuchAlgorithmException {
171+
var proxyAddr = new InetSocketAddress("127.0.0.1", 9999);
172+
var ks = mock(KonnektorService.class);
173+
when(ks.listSmcbCards()).thenReturn(List.of());
174+
var trustStore = mock(KeyStore.class);
175+
var proxyListenAddr = new InetSocketAddress("127.0.0.1", 18080);
176+
177+
try (var sslMock = mockStatic(SslContextBuilder.class);
178+
var ignored =
179+
mockConstruction(
180+
VauProxy.class,
181+
(proxy, ctx) ->
182+
when(proxy.start()).thenReturn(new VauProxy.ServerInfo(proxyListenAddr)))) {
183+
sslMock
184+
.when(() -> SslContextBuilder.buildSslContext(any()))
185+
.thenReturn(SSLContext.getDefault());
186+
187+
assertThrows(
188+
Epa4AllClientException.class,
189+
() -> Epa4AllClientFactory.create(ks, proxyAddr, Environment.RU, trustStore, null));
190+
}
191+
}
192+
193+
@Test
194+
void create_withSingleCard_returnsFactory() throws NoSuchAlgorithmException {
195+
var proxyAddr = new InetSocketAddress("127.0.0.1", 9999);
196+
var ks = mock(KonnektorService.class);
197+
var card = mock(SmcbCard.class);
198+
when(ks.listSmcbCards()).thenReturn(List.of(card));
199+
when(card.telematikId()).thenReturn("test-id");
200+
var trustStore = mock(KeyStore.class);
201+
var proxyListenAddr = new InetSocketAddress("127.0.0.1", 18080);
202+
203+
try (var sslMock = mockStatic(SslContextBuilder.class);
204+
var ignored =
205+
mockConstruction(
206+
VauProxy.class,
207+
(proxy, ctx) ->
208+
when(proxy.start()).thenReturn(new VauProxy.ServerInfo(proxyListenAddr)));
209+
var ignored2 = mockConstruction(SoapClientFactory.class)) {
210+
sslMock
211+
.when(() -> SslContextBuilder.buildSslContext(any()))
212+
.thenReturn(SSLContext.getDefault());
213+
214+
// When
215+
var result =
216+
Epa4AllClientFactory.create(ks, proxyAddr, Environment.RU, trustStore, "test-id");
217+
218+
// Then
219+
assertNotNull(result);
220+
assertInstanceOf(Epa4AllClientFactory.class, result);
221+
}
222+
}
223+
224+
@Test
225+
void create_withTelematikId_selectsMatchingCard() throws NoSuchAlgorithmException {
226+
var proxyAddr = new InetSocketAddress("127.0.0.1", 9999);
227+
var ks = mock(KonnektorService.class);
228+
var card1 = mock(SmcbCard.class);
229+
var card2 = mock(SmcbCard.class);
230+
when(card1.telematikId()).thenReturn("id-1");
231+
when(card2.telematikId()).thenReturn("id-2");
232+
when(ks.listSmcbCards()).thenReturn(List.of(card1, card2));
233+
var trustStore = mock(KeyStore.class);
234+
var proxyListenAddr = new InetSocketAddress("127.0.0.1", 18080);
235+
236+
try (var sslMock = mockStatic(SslContextBuilder.class);
237+
var ignored =
238+
mockConstruction(
239+
VauProxy.class,
240+
(proxy, ctx) ->
241+
when(proxy.start()).thenReturn(new VauProxy.ServerInfo(proxyListenAddr)));
242+
var ignored2 = mockConstruction(SoapClientFactory.class)) {
243+
sslMock
244+
.when(() -> SslContextBuilder.buildSslContext(any()))
245+
.thenReturn(SSLContext.getDefault());
246+
247+
// When
248+
var result = Epa4AllClientFactory.create(ks, proxyAddr, Environment.RU, trustStore, "id-2");
249+
250+
// Then
251+
assertNotNull(result);
252+
}
253+
}
131254
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package com.oviva.telematik.epa4all.client.internal;
2+
3+
import static org.junit.jupiter.api.Assertions.*;
4+
5+
import java.security.Security;
6+
import java.security.cert.X509Certificate;
7+
import javax.net.ssl.X509TrustManager;
8+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
9+
import org.junit.jupiter.api.BeforeAll;
10+
import org.junit.jupiter.api.Test;
11+
12+
class TelematikTrustRootsTest {
13+
14+
@BeforeAll
15+
static void setUp() {
16+
Security.addProvider(new BouncyCastleProvider());
17+
}
18+
19+
@Test
20+
void loadRuTrustStore_returnsNonEmptyKeyStore() throws Exception {
21+
var ks = TelematikTrustRoots.loadRuTrustStore();
22+
23+
assertNotNull(ks);
24+
assertTrue(ks.size() > 0, "RU trust store must contain at least one certificate");
25+
}
26+
27+
@Test
28+
void loadPuTrustStore_returnsNonEmptyKeyStore() throws Exception {
29+
var ks = TelematikTrustRoots.loadPuTrustStore();
30+
31+
assertNotNull(ks);
32+
assertTrue(ks.size() > 0, "PU trust store must contain at least one certificate");
33+
}
34+
35+
@Test
36+
void loadRuTrustStore_containsX509Certificates() throws Exception {
37+
var ks = TelematikTrustRoots.loadRuTrustStore();
38+
39+
var aliases = ks.aliases();
40+
while (aliases.hasMoreElements()) {
41+
var alias = aliases.nextElement();
42+
assertInstanceOf(X509Certificate.class, ks.getCertificate(alias));
43+
}
44+
}
45+
46+
@Test
47+
void loadPuTrustStore_containsX509Certificates() throws Exception {
48+
var ks = TelematikTrustRoots.loadPuTrustStore();
49+
50+
var aliases = ks.aliases();
51+
while (aliases.hasMoreElements()) {
52+
var alias = aliases.nextElement();
53+
assertInstanceOf(X509Certificate.class, ks.getCertificate(alias));
54+
}
55+
}
56+
57+
@Test
58+
void createRuTrustManager_returnsNonNull() {
59+
var tm = TelematikTrustRoots.createRuTrustManager();
60+
61+
assertNotNull(tm);
62+
}
63+
64+
@Test
65+
void createPuTrustManager_returnsNonNull() {
66+
var tm = TelematikTrustRoots.createPuTrustManager();
67+
68+
assertNotNull(tm);
69+
}
70+
71+
@Test
72+
void createRuTrustManager_hasAcceptedIssuers() {
73+
var tm = (X509TrustManager) TelematikTrustRoots.createRuTrustManager();
74+
75+
var issuers = tm.getAcceptedIssuers();
76+
assertNotNull(issuers);
77+
assertTrue(issuers.length > 0, "RU trust manager must have accepted issuers");
78+
}
79+
80+
@Test
81+
void createPuTrustManager_hasAcceptedIssuers() {
82+
var tm = (X509TrustManager) TelematikTrustRoots.createPuTrustManager();
83+
84+
var issuers = tm.getAcceptedIssuers();
85+
assertNotNull(issuers);
86+
assertTrue(issuers.length > 0, "PU trust manager must have accepted issuers");
87+
}
88+
}

0 commit comments

Comments
 (0)