SuperX-Kernmodul
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

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
}
}
}