You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
382 lines
17 KiB
382 lines
17 KiB
package de.superx.rest; |
|
|
|
import org.junit.After; |
|
import org.junit.Assert; |
|
import org.junit.Before; |
|
import org.junit.Test; |
|
import org.springframework.beans.factory.annotation.Autowired; |
|
import org.springframework.http.MediaType; |
|
import org.springframework.jdbc.core.JdbcTemplate; |
|
import org.springframework.test.web.servlet.MvcResult; |
|
|
|
import com.fasterxml.jackson.core.type.TypeReference; |
|
import com.fasterxml.jackson.databind.ObjectMapper; |
|
|
|
import de.superx.BaseWebTest; |
|
import de.superx.bianalysis.metadata.Identifier; |
|
import de.superx.bianalysis.metadata.MetadataImporter; |
|
import de.superx.bianalysis.models.Condition; |
|
import de.superx.bianalysis.models.CriteriaGroup; |
|
import de.superx.bianalysis.repository.DimensionAttributeRepository; |
|
import de.superx.bianalysis.repository.DimensionRepository; |
|
import de.superx.bianalysis.repository.dto.AttributeDto; |
|
import de.superx.bianalysis.repository.dto.DimensionDto; |
|
import de.superx.bianalysis.service.DbMetaAdapter; |
|
import static org.junit.Assert.assertEquals; |
|
import static org.junit.Assert.assertNotNull; |
|
import static org.junit.Assert.assertTrue; |
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; |
|
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; |
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
|
import java.nio.charset.StandardCharsets; |
|
import java.sql.DatabaseMetaData; |
|
import java.sql.ResultSet; |
|
import java.sql.SQLException; |
|
import java.util.ArrayList; |
|
import java.util.List; |
|
import java.util.Optional; |
|
|
|
public class BiAnalysisAdminApiTest extends BaseWebTest { |
|
|
|
private static final String ADMIN_BASE_ROUTE = "/api/bianalysis/admin"; |
|
private static final String ATTRIBUTE_GROUP_ROUTE = ADMIN_BASE_ROUTE + "/attribute-group"; |
|
private static final String ATTRIBUTE_GROUP_VALIDATE = ATTRIBUTE_GROUP_ROUTE + "/validate"; |
|
|
|
@Autowired |
|
DbMetaAdapter dbMetaAdapter; |
|
|
|
@Autowired |
|
DimensionAttributeRepository dimensionAttrRepo; |
|
|
|
@Autowired |
|
DimensionRepository dimensionRepository; |
|
|
|
@After |
|
public void cleanup() { |
|
JdbcTemplate jt = new JdbcTemplate(dataSource); |
|
String sqlCleanup = """ |
|
DELETE FROM metadata.facttable WHERE namespace = 'dummy_api'; |
|
DELETE FROM metadata.dimension WHERE namespace = 'dummy_api' OR namespace = 'conf_dummy'; |
|
DELETE FROM metadata.dimension_attribute WHERE namespace = 'dummy_api' OR namespace = 'conf_dummy'; |
|
DELETE FROM metadata.dimension_attribute WHERE id like 'custom%'; |
|
DROP TABLE IF EXISTS presentation.dim_person_dummy; |
|
"""; |
|
jt.execute(sqlCleanup); |
|
} |
|
|
|
@Before |
|
public void init() { |
|
assertEquals(0, getCustomAttributes().size()); // sanity check |
|
String dummyConformedDimension = """ |
|
{ |
|
"namespace" : "conf_dummy", |
|
"conformed_dimensions" : [ |
|
{ |
|
"id" : "conf_dummy:1", |
|
"caption" : "Person", |
|
"dimension" : "dim_person_dummy", |
|
"fact_column" : "person_id", |
|
"attributes" : [ |
|
{ |
|
"id" : "conf_dummy:2", |
|
"caption" : "Geburtsjahr", |
|
"dim_column" : "year_of_birth" |
|
} |
|
] |
|
} |
|
] |
|
} |
|
"""; |
|
|
|
String dummyFacttable = """ |
|
{ |
|
"namespace" : "dummy_api", |
|
"facts" : [ |
|
{ |
|
"id" : "dummy_api:2", |
|
"caption" : "Publikationsstern", |
|
"facttable" : "fact_publication_dummy", |
|
"dimensions" : [ |
|
{ |
|
"id" : "dummy_api:3", |
|
"caption" : "Dozent", |
|
"ref_to" : "dim_person_dummy", |
|
"fact_column" : "person_id", |
|
"attributes" : [ |
|
{ |
|
"id" : "dummy_api:4", |
|
"ref_to" : "year_of_birth" |
|
} |
|
] |
|
} |
|
], |
|
"measures" : [] |
|
}, |
|
{ |
|
"id" : "dummy_api:5", |
|
"caption" : "Bewerberstern", |
|
"facttable" : "fact_applicant_dummy", |
|
"dimensions" : [ |
|
{ |
|
"id" : "dummy_api:6", |
|
"caption" : "Bewerber", |
|
"ref_to" : "dim_person_dummy", |
|
"fact_column" : "person_id", |
|
"attributes" : [ |
|
{ |
|
"id" : "dummy_api:7", |
|
"ref_to" : "year_of_birth" |
|
} |
|
] |
|
} |
|
], |
|
"measures" : [] |
|
} |
|
] |
|
} |
|
"""; |
|
|
|
JdbcTemplate jt = new JdbcTemplate(dataSource); |
|
MetadataImporter importer = new MetadataImporter(); |
|
importer.deserializeMetadataFromStrings(dummyConformedDimension, dummyFacttable); |
|
String upserts = String.join("\n", importer.getAllUpsertStrings(false)); |
|
jt.execute(upserts); |
|
jt.execute("CREATE TABLE presentation.dim_person_dummy" |
|
+ " (id SERIAL PRIMARY KEY, year_of_birth varchar NOT NULL);"); |
|
String sql = "INSERT INTO presentation.dim_person_dummy (year_of_birth) VALUES (?)"; |
|
for (int year = 1990; year <= 2015; year++) { |
|
jt.update(sql, String.valueOf(year)); |
|
} |
|
// TODO fix pre authorization guard for tests |
|
//user.getRightsMap().put("RIGHT_CS_BIA_ANALYSIS_MANAGE_METADATA", null); |
|
} |
|
|
|
|
|
@Test |
|
public void testCreationAndDeletionOfAttributeGroup() throws Exception { |
|
MvcResult result = mockMvc.perform(put(ATTRIBUTE_GROUP_ROUTE) |
|
.contentType(MediaType.APPLICATION_JSON) |
|
.characterEncoding("UTF-8") |
|
.param("dimension_id", "dummy_api:6") |
|
.content(getAttributeJson("Neue Geburtsjahrgaenge", "").getBytes(StandardCharsets.UTF_8))) |
|
.andDo(print()) |
|
.andExpect(status().isOk()) |
|
.andReturn(); |
|
|
|
String responseBody = result.getResponse().getContentAsString(); |
|
Identifier id = new ObjectMapper().readValue(responseBody, Identifier.class); |
|
assertNotNull(id); |
|
|
|
Optional<AttributeDto> attributeOpt = this.dimensionAttrRepo.findById(id); |
|
assertTrue(attributeOpt.isPresent()); |
|
|
|
AttributeDto attribute = attributeOpt.get(); |
|
Optional<DimensionDto> dimensionOpt = this.dimensionRepository.findById(attribute.dimensionId); |
|
assertTrue(dimensionOpt.isPresent()); |
|
DimensionDto dimension = dimensionOpt.get(); |
|
assertEquals(new Identifier("dummy_api:6"), dimension.id); |
|
|
|
List<AttributeDto> customAttributes = getCustomAttributes(); |
|
assertEquals(3, customAttributes.size()); |
|
|
|
AttributeDto applicantRolePlaying = this.dimensionAttrRepo.findByIdOrThrow(new Identifier("custom:1")); |
|
AttributeDto teacherRolePlaying = this.dimensionAttrRepo.findByIdOrThrow(new Identifier("custom:3")); |
|
AttributeDto personConformed = this.dimensionAttrRepo.findByIdOrThrow(new Identifier("custom:2")); |
|
|
|
assertEquals("Neue Geburtsjahrgaenge", personConformed.caption); |
|
assertEquals("custom_neue_geburtsjahrgaenge", personConformed.columnname); |
|
assertNotNull(personConformed.criteriaGroups); |
|
assertEquals("my description", personConformed.description); |
|
assertTrue(personConformed.attrConformedId == null); |
|
assertTrue(personConformed.isHidden.booleanValue()); |
|
|
|
assertEquals("Neue Geburtsjahrgaenge", applicantRolePlaying.caption); |
|
assertEquals("custom_neue_geburtsjahrgaenge", applicantRolePlaying.columnname); |
|
assertEquals("custom_neue_geburtsjahrgaenge", applicantRolePlaying.columnname); |
|
assertEquals("my description", applicantRolePlaying.description); |
|
assertEquals("custom:2", applicantRolePlaying.attrConformedId); |
|
assertEquals("dummy_api:6", applicantRolePlaying.dimensionId.composedId); |
|
assertNotNull(applicantRolePlaying.criteriaGroups); |
|
assertTrue(!applicantRolePlaying.isHidden.booleanValue()); |
|
|
|
assertEquals("Neue Geburtsjahrgaenge", teacherRolePlaying.caption); |
|
assertEquals("custom_neue_geburtsjahrgaenge", teacherRolePlaying.columnname); |
|
assertEquals("custom_neue_geburtsjahrgaenge", teacherRolePlaying.columnname); |
|
assertEquals("my description", teacherRolePlaying.description); |
|
assertEquals("custom:2", teacherRolePlaying.attrConformedId); |
|
assertEquals("dummy_api:3", teacherRolePlaying.dimensionId.composedId); |
|
assertNotNull(teacherRolePlaying.criteriaGroups); |
|
assertTrue(teacherRolePlaying.isHidden.booleanValue()); |
|
|
|
List<CriteriaGroup> criteriaGroups = attribute.readCriteriaGroups(); |
|
assertEquals(criteriaGroups.size(), 3); |
|
for (CriteriaGroup criteriaGroup : criteriaGroups) { |
|
if(criteriaGroup.caption.equals("2001 - 2005")) { |
|
assertEquals(List.of("2001", "2002", "2003", "2004", "2005"), |
|
Condition.fromMap(criteriaGroup.conditions.get(0)).values); |
|
} else if(criteriaGroup.caption.equals("2006 - 2010")) { |
|
assertEquals(List.of("2006", "2007", "2008", "2009"), |
|
Condition.fromMap(criteriaGroup.conditions.get(0)).values); |
|
} else if(criteriaGroup.caption.equals("n.a")) { |
|
assertTrue(criteriaGroup.isElse); |
|
} else { |
|
Assert.fail("Wrong criteria group: " + criteriaGroup.caption); |
|
} |
|
} |
|
|
|
assertTrue(columnExists("presentation", dimension.tablename, "custom_neue_geburtsjahrgaenge")); |
|
assertTrue(columnExists("presentation", dimension.tablename, "custom_neue_geburtsjahrgaenge_sort_order")); |
|
|
|
result = mockMvc.perform(put(ATTRIBUTE_GROUP_ROUTE) |
|
.contentType(MediaType.APPLICATION_JSON) |
|
.characterEncoding("UTF-8") |
|
.param("dimension_id", "dummy_api:6") |
|
.content(getAttributeJson("Umbenannte Caption", "\"id\": \"custom:1\",").getBytes(StandardCharsets.UTF_8))) |
|
.andDo(print()) |
|
.andExpect(status().isOk()) |
|
.andReturn(); |
|
|
|
applicantRolePlaying = this.dimensionAttrRepo.findByIdOrThrow(new Identifier("custom:1")); |
|
teacherRolePlaying = this.dimensionAttrRepo.findByIdOrThrow(new Identifier("custom:3")); |
|
personConformed = this.dimensionAttrRepo.findByIdOrThrow(new Identifier("custom:2")); |
|
|
|
assertEquals("Umbenannte Caption", personConformed.caption); |
|
assertEquals("custom_umbenannte_caption", personConformed.columnname); |
|
assertEquals("custom_umbenannte_caption_sort_order", personConformed.sortOrderColumn); |
|
assertNotNull(personConformed.criteriaGroups); |
|
assertEquals("my description", personConformed.description); |
|
assertTrue(personConformed.attrConformedId == null); |
|
assertTrue(personConformed.isHidden.booleanValue()); |
|
|
|
assertEquals("Umbenannte Caption", applicantRolePlaying.caption); |
|
assertEquals("custom_umbenannte_caption", applicantRolePlaying.columnname); |
|
assertEquals("custom_umbenannte_caption_sort_order", applicantRolePlaying.sortOrderColumn); |
|
assertEquals("my description", applicantRolePlaying.description); |
|
assertEquals("custom:2", applicantRolePlaying.attrConformedId); |
|
assertEquals("dummy_api:6", applicantRolePlaying.dimensionId.composedId); |
|
assertNotNull(applicantRolePlaying.criteriaGroups); |
|
assertTrue(!applicantRolePlaying.isHidden.booleanValue()); |
|
|
|
assertEquals("Umbenannte Caption", teacherRolePlaying.caption); |
|
assertEquals("custom_umbenannte_caption", teacherRolePlaying.columnname); |
|
assertEquals("custom_umbenannte_caption_sort_order", teacherRolePlaying.sortOrderColumn); |
|
assertEquals("my description", teacherRolePlaying.description); |
|
assertEquals("custom:2", teacherRolePlaying.attrConformedId); |
|
assertEquals("dummy_api:3", teacherRolePlaying.dimensionId.composedId); |
|
assertNotNull(teacherRolePlaying.criteriaGroups); |
|
assertTrue(teacherRolePlaying.isHidden.booleanValue()); |
|
|
|
this.dbMetaAdapter.deleteAttributeGroupById(id); |
|
|
|
assertEquals(0, getCustomAttributes().size()); |
|
assertTrue(!columnExists("presentation", dimension.tablename, "custom_umbenannte_caption")); |
|
assertTrue(!columnExists("presentation", dimension.tablename, "custom_umbenannte_caption_sort_order")); |
|
assertTrue(!columnExists("presentation", dimension.tablename, "custom_neue_geburtsjahrgaenge")); |
|
assertTrue(!columnExists("presentation", dimension.tablename, "custom_neue_geburtsjahrgaenge_sort_order")); |
|
assertTrue(this.dimensionAttrRepo.findById(attribute.id).isEmpty()); |
|
} |
|
|
|
@Test |
|
public void testValidation() throws Exception { |
|
String json = """ |
|
{ |
|
"caption" : "Altersgruppe", |
|
"description": "my description", |
|
"criteriaGroups" : [ |
|
{ |
|
"caption" : "Unter 18", |
|
"conditions" : [ |
|
{ "column" : "age", "operator" : "<", "value" : "25" } |
|
] |
|
}, |
|
{ |
|
"caption" : "Ab 18 bis 50", |
|
"logic" : "AND", |
|
"conditions" : [ |
|
{ "column" : "age", "operator" : ">=", "value" : "18" }, |
|
{ "column" : "age", "operator" : "<=", "value" : "50" } |
|
] |
|
}, |
|
{ |
|
"caption":"n.a", |
|
"isElse" : true |
|
} |
|
] |
|
} |
|
|
|
"""; |
|
|
|
MvcResult result = mockMvc.perform(put(ATTRIBUTE_GROUP_VALIDATE) |
|
.contentType(MediaType.APPLICATION_JSON) |
|
.characterEncoding("UTF-8") |
|
.param("dimension_id", "app_basic:5") |
|
.content(json.getBytes(StandardCharsets.UTF_8))) |
|
.andDo(print()) |
|
.andExpect(status().isOk()) |
|
.andReturn(); |
|
|
|
String responseBody = result.getResponse().getContentAsString(); |
|
assertNotNull(responseBody); |
|
assertTrue(responseBody.length() > 0); |
|
|
|
ObjectMapper mapper = new ObjectMapper(); |
|
List<String> stringList = mapper.readValue(responseBody, new TypeReference<List<String>>(){}); |
|
assertTrue(!stringList.isEmpty()); |
|
} |
|
|
|
public String getAttributeJson(String caption, String id) { |
|
String json = """ |
|
{ |
|
%s |
|
"caption": "%s", |
|
"description": "my description", |
|
"criteriaGroups":[ |
|
{ |
|
"caption":"2001 - 2005", |
|
"conditions": [ |
|
{ |
|
"column" : "year_of_birth", |
|
"operator": "IN", |
|
"values": [ "2001", "2002", "2003", "2004", "2005" ] |
|
} |
|
] |
|
}, |
|
{ |
|
"caption":"2006 - 2010", |
|
"conditions": [ |
|
{ |
|
"column" : "year_of_birth", |
|
"operator": "IN", |
|
"values": [ "2006", "2007", "2008", "2009" ] |
|
} |
|
] |
|
}, |
|
{ |
|
"caption":"n.a", |
|
"isElse" : true |
|
} |
|
] |
|
} |
|
""".formatted(id, caption); |
|
return json; |
|
} |
|
|
|
private List<AttributeDto> getCustomAttributes() { |
|
List<AttributeDto> customAttributes = new ArrayList<>(); |
|
for (AttributeDto attributeDto : this.dimensionAttrRepo.findAll()) { |
|
if(attributeDto.isCustom.booleanValue()) { |
|
customAttributes.add(attributeDto); |
|
} |
|
} |
|
return customAttributes; |
|
} |
|
|
|
boolean columnExists(String schema, String tableName, String columnName) throws SQLException { |
|
DatabaseMetaData meta = dbMetaAdapter.getDataSource().getConnection().getMetaData(); |
|
try (ResultSet rs = meta.getColumns(null, schema, tableName, columnName)) { |
|
return rs.next(); // true if at least one matching column |
|
} |
|
} |
|
|
|
|
|
} |