Skip to content

Commit 406a246

Browse files
committed
#552 - Improve test coverage
- Improve coverage for terminology - Improve coverage for dse/persistence - Improve coverage for dse/api - Improve coverage for WebSecurityConfig
1 parent aef061f commit 406a246

File tree

18 files changed

+916
-4
lines changed

18 files changed

+916
-4
lines changed

src/main/java/de/numcodex/feasibility_gui_backend/terminology/persistence/Coding.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,12 @@ public class Coding implements Serializable {
1111
private String code;
1212
private String version;
1313

14-
public Coding() {
15-
}
16-
1714
public Coding(String system, String code, String version) {
1815
requireNonNull(system);
1916
requireNonNull(code);
2017
this.system = system;
2118
this.code = code;
19+
this.version = version;
2220
}
2321

2422
@Override

src/test/java/de/numcodex/feasibility_gui_backend/common/api/TermCodeTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,8 @@ public void testEqualsAndHashCode() {
3434

3535
assertEquals(termCode1.hashCode(), termCode2.hashCode());
3636
assertNotEquals(termCode1.hashCode(), termCode3.hashCode());
37+
38+
assertNotEquals(termCode1, null);
39+
assertNotEquals(termCode1, "");
3740
}
3841
}

src/test/java/de/numcodex/feasibility_gui_backend/config/WebSecurityConfigIT.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
controllers = {DataqueryHandlerRestController.class,
4949
TerminologyRestController.class
5050
}
51-
5251
)
5352
class WebSecurityConfigIT {
5453

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package de.numcodex.feasibility_gui_backend.config;
2+
3+
import de.numcodex.feasibility_gui_backend.query.dataquery.DataqueryHandler;
4+
import de.numcodex.feasibility_gui_backend.query.ratelimiting.AuthenticationHelper;
5+
import de.numcodex.feasibility_gui_backend.query.ratelimiting.RateLimitingServiceSpringConfig;
6+
import de.numcodex.feasibility_gui_backend.query.v5.DataqueryHandlerRestController;
7+
import de.numcodex.feasibility_gui_backend.terminology.TerminologyService;
8+
import de.numcodex.feasibility_gui_backend.terminology.es.TerminologyEsService;
9+
import de.numcodex.feasibility_gui_backend.terminology.v5.TerminologyRestController;
10+
import de.numcodex.feasibility_gui_backend.terminology.validation.StructuredQueryValidation;
11+
import org.hamcrest.Matchers;
12+
import org.junit.jupiter.api.Test;
13+
import org.junit.jupiter.api.extension.ExtendWith;
14+
import org.springframework.beans.factory.annotation.Autowired;
15+
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
16+
import org.springframework.context.annotation.Import;
17+
import org.springframework.security.oauth2.jwt.JwtDecoder;
18+
import org.springframework.security.test.context.support.WithMockUser;
19+
import org.springframework.test.context.TestPropertySource;
20+
import org.springframework.test.context.bean.override.mockito.MockitoBean;
21+
import org.springframework.test.context.junit.jupiter.SpringExtension;
22+
import org.springframework.test.web.servlet.MockMvc;
23+
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
24+
25+
import java.net.URI;
26+
27+
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
28+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
29+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
30+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
31+
32+
// This is moved to a separate class to check if ssl enabled is correctly working
33+
@ExtendWith(SpringExtension.class)
34+
@Import({AuthenticationHelper.class,
35+
RateLimitingServiceSpringConfig.class,
36+
WebSecurityConfig.class
37+
})
38+
@WebMvcTest(
39+
controllers = {DataqueryHandlerRestController.class,
40+
TerminologyRestController.class
41+
}
42+
)
43+
@TestPropertySource(properties = {
44+
"server.ssl.enabled=true",
45+
"server.ssl.key-store=classpath:keystore.p12",
46+
"server.ssl.key-store-password=password",
47+
"server.ssl.key-store-type=PKCS12",
48+
"server.ssl.key-alias=tomcat"
49+
})
50+
class WebSecurityConfigSslIT {
51+
52+
@Autowired
53+
private MockMvc mockMvc;
54+
55+
@MockitoBean
56+
private JwtDecoder jwtDecoder;
57+
58+
@MockitoBean
59+
private DataqueryHandler dataqueryHandler;
60+
61+
@MockitoBean
62+
private StructuredQueryValidation structuredQueryValidation;
63+
64+
@MockitoBean
65+
private TerminologyService terminologyService;
66+
67+
@MockitoBean
68+
private TerminologyEsService terminologyEsService;
69+
70+
@Test
71+
void shouldRedirectHttpToHttps() throws Exception {
72+
mockMvc.perform(get(URI.create("/api/v5/query/data")).with(csrf()))
73+
.andExpect(status().is3xxRedirection())
74+
.andExpect(header().string("Location", Matchers.startsWith("https://")));
75+
}
76+
77+
@Test
78+
@WithMockUser(username = "user", roles = "DATAPORTAL_TEST_USER")
79+
void shouldNotRedirectHttps() throws Exception {
80+
mockMvc.perform(get(URI.create("https://localhost/api/v5/query/data")).with(csrf()))
81+
.andExpect(status().isOk());
82+
}
83+
84+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package de.numcodex.feasibility_gui_backend.config;
2+
3+
import org.junit.jupiter.api.Assertions;
4+
import org.junit.jupiter.api.Test;
5+
import org.springframework.security.core.GrantedAuthority;
6+
import org.springframework.security.oauth2.jwt.Jwt;
7+
8+
import java.util.List;
9+
import java.util.Map;
10+
11+
import static org.mockito.Mockito.mock;
12+
import static org.mockito.Mockito.when;
13+
14+
public class WebSecurityConfigTest {
15+
16+
private static final String KEY_REALM_ACCESS = "realm_access";
17+
private static final String KEY_RESOURCE_ACCESS = "resource_access";
18+
private static final String KEY_ROLES = "roles";
19+
private static final String KEY_SPRING_ADDONS_CONFIDENTIAL = "spring-addons-confidential";
20+
private static final String KEY_SPRING_ADDONS_PUBLIC = "spring-addons-public";
21+
22+
@Test
23+
void shouldExtractAllRolesFromJwt() {
24+
Jwt jwt = mock(Jwt.class);
25+
26+
Map<String, Object> realmAccess = Map.of(
27+
KEY_ROLES, List.of("role_realm1", "role_realm2")
28+
);
29+
30+
Map<String, Object> confidentialAccess = Map.of(
31+
KEY_ROLES, List.of("role_conf1")
32+
);
33+
34+
Map<String, Object> publicAccess = Map.of(
35+
KEY_ROLES, List.of("role_pub1", "role_pub2")
36+
);
37+
38+
Map<String, Object> resourceAccess = Map.of(
39+
KEY_SPRING_ADDONS_CONFIDENTIAL, confidentialAccess,
40+
KEY_SPRING_ADDONS_PUBLIC, publicAccess
41+
);
42+
43+
Map<String, Object> claims = Map.of(
44+
KEY_REALM_ACCESS, realmAccess,
45+
KEY_RESOURCE_ACCESS, resourceAccess
46+
);
47+
48+
when(jwt.getClaims()).thenReturn(claims);
49+
50+
var converter = new WebSecurityConfig();
51+
var authoritiesConverter = converter.authoritiesConverter();
52+
List<GrantedAuthority> authorities = (List<GrantedAuthority>) authoritiesConverter.convert(jwt);
53+
54+
55+
Assertions.assertNotNull(authorities);
56+
List<String> roles = authorities.stream()
57+
.map(GrantedAuthority::getAuthority)
58+
.toList();
59+
60+
Assertions.assertEquals(List.of("role_realm1", "role_realm2", "role_conf1", "role_pub1", "role_pub2"), roles);
61+
}
62+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package de.numcodex.feasibility_gui_backend.dse.api;
2+
3+
import de.numcodex.feasibility_gui_backend.common.api.DisplayEntry;
4+
import org.junit.jupiter.api.Test;
5+
6+
import java.util.Collections;
7+
import java.util.List;
8+
9+
import static org.junit.jupiter.api.Assertions.*;
10+
11+
class DseProfileTest {
12+
13+
@Test
14+
void testConstructorWithValues() {
15+
DseProfile dseProfile = DseProfile.builder()
16+
.url("url")
17+
.display(DisplayEntry.builder().build())
18+
.module(DisplayEntry.builder().build())
19+
.fields(List.of(Field.builder().build()))
20+
.filters(List.of(Filter.builder().build()))
21+
.references(List.of(Reference.builder().build()))
22+
.errorCode("error")
23+
.errorCause("123")
24+
.build();
25+
26+
assertNotNull(dseProfile);
27+
assertNotNull(dseProfile.url());
28+
assertNotNull(dseProfile.display());
29+
assertNotNull(dseProfile.module());
30+
assertNotNull(dseProfile.fields());
31+
assertNotNull(dseProfile.filters());
32+
assertNotNull(dseProfile.references());
33+
assertNotNull(dseProfile.errorCode());
34+
assertNotNull(dseProfile.errorCause());
35+
36+
assertNotEquals(dseProfile.fields(), Collections.emptyList());
37+
assertNotEquals(dseProfile.filters(), Collections.emptyList());
38+
assertNotEquals(dseProfile.references(), Collections.emptyList());
39+
}
40+
41+
@Test
42+
public void testConstructorWithNull() {
43+
DseProfile dseProfile = DseProfile.builder()
44+
.url("url")
45+
.display(DisplayEntry.builder().build())
46+
.module(DisplayEntry.builder().build())
47+
.fields(null)
48+
.filters(null)
49+
.references(null)
50+
.errorCode("error")
51+
.errorCause("123")
52+
.build();
53+
54+
assertNotNull(dseProfile);
55+
assertNotNull(dseProfile.url());
56+
assertNotNull(dseProfile.display());
57+
assertNotNull(dseProfile.module());
58+
assertNotNull(dseProfile.fields());
59+
assertNotNull(dseProfile.filters());
60+
assertNotNull(dseProfile.references());
61+
assertNotNull(dseProfile.errorCode());
62+
assertNotNull(dseProfile.errorCause());
63+
64+
assertEquals(dseProfile.fields(), Collections.emptyList());
65+
assertEquals(dseProfile.filters(), Collections.emptyList());
66+
assertEquals(dseProfile.references(), Collections.emptyList());
67+
}
68+
69+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package de.numcodex.feasibility_gui_backend.dse.api;
2+
3+
import de.numcodex.feasibility_gui_backend.common.api.DisplayEntry;
4+
import org.junit.jupiter.api.Test;
5+
6+
import java.util.Collections;
7+
import java.util.List;
8+
9+
import static org.junit.jupiter.api.Assertions.*;
10+
11+
class DseProfileTreeNodeTest {
12+
13+
@Test
14+
void testConstructorWithValues() {
15+
DseProfileTreeNode childNode = DseProfileTreeNode.builder()
16+
.id("childid")
17+
.children(null)
18+
.name(null)
19+
.display(null)
20+
.fields(null)
21+
.module(null)
22+
.url(null)
23+
.leaf(false)
24+
.selectable(false)
25+
.build();
26+
27+
DseProfileTreeNode parentNode = DseProfileTreeNode.builder()
28+
.id("id")
29+
.children(List.of(childNode))
30+
.name("name")
31+
.display(DisplayEntry.builder().build())
32+
.fields(FieldDisplayEntry.builder().build())
33+
.module("module")
34+
.url("http://url")
35+
.leaf(true)
36+
.selectable(true)
37+
.build();
38+
39+
assertNotNull(parentNode);
40+
assertNotNull(childNode);
41+
assertNotEquals(Collections.emptyList(), parentNode.children());
42+
assertEquals(childNode.id(), parentNode.children().get(0).id());
43+
}
44+
45+
@Test
46+
public void testConstructorWithNull() {
47+
DseProfileTreeNode dseProfileTreeNode = DseProfileTreeNode.builder()
48+
.id(null)
49+
.children(null)
50+
.name(null)
51+
.display(null)
52+
.fields(null)
53+
.module(null)
54+
.url(null)
55+
.leaf(false)
56+
.selectable(false)
57+
.build();
58+
59+
assertNotNull(dseProfileTreeNode);
60+
assertNotNull(dseProfileTreeNode.children());
61+
assertEquals(Collections.emptyList(), dseProfileTreeNode.children());
62+
}
63+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package de.numcodex.feasibility_gui_backend.dse.api;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import java.util.Collections;
6+
import java.util.List;
7+
8+
import static org.junit.jupiter.api.Assertions.*;
9+
10+
class FieldDisplayEntryTest {
11+
12+
@Test
13+
public void testConstructorWithValues() {
14+
List<String> original = List.of("original-value1", "original-value2");
15+
List<LocalizedValueList> translations = List.of(LocalizedValueList.builder()
16+
.language("de-De")
17+
.value(List.of("value-value"))
18+
.build());
19+
20+
FieldDisplayEntry fieldDisplayEntry = FieldDisplayEntry.builder()
21+
.original(original)
22+
.translations(translations)
23+
.build();
24+
25+
assertNotNull(fieldDisplayEntry);
26+
assertEquals(fieldDisplayEntry.original(), original);
27+
assertEquals(fieldDisplayEntry.translations().size(), translations.size());
28+
assertEquals(fieldDisplayEntry.translations().get(0), translations.get(0));
29+
}
30+
31+
@Test
32+
public void testConstructorWithNulls() {
33+
FieldDisplayEntry fieldDisplayEntry = FieldDisplayEntry.builder()
34+
.original(null)
35+
.translations(null)
36+
.build();
37+
38+
assertNotNull(fieldDisplayEntry);
39+
assertNotNull(fieldDisplayEntry.original());
40+
assertNotNull(fieldDisplayEntry.translations());
41+
assertEquals(fieldDisplayEntry.original(), Collections.emptyList());
42+
assertEquals(fieldDisplayEntry.translations(), Collections.emptyList());
43+
}
44+
45+
}

0 commit comments

Comments
 (0)