Skip to content

Commit 84f33f4

Browse files
committed
fix: add null iterations
1 parent 29a0ee1 commit 84f33f4

5 files changed

Lines changed: 235 additions & 25 deletions

File tree

src/main/java/fr/insee/genesis/controller/rest/responses/ResponseController.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import fr.insee.genesis.exceptions.ReviewDisabledException;
3535
import fr.insee.genesis.infrastructure.utils.FileUtils;
3636
import fr.insee.modelefiliere.RawResponseDto;
37+
import io.swagger.v3.oas.annotations.Hidden;
3738
import io.swagger.v3.oas.annotations.Operation;
3839
import io.swagger.v3.oas.annotations.Parameter;
3940
import io.swagger.v3.oas.annotations.media.Schema;
@@ -333,7 +334,7 @@ public ResponseEntity<SurveyUnitSimplifiedDto> getLatestByInterrogationOneObject
333334
@Operation(summary = "Returns the response with the latest variables for a collectionInstrument, mode and " +
334335
"interrogation")
335336
@GetMapping(path = "/{collectionInstrumentId}/{mode}/{interrogationId}")
336-
@PreAuthorize("hasRole('USER_KRAFTWERK')")
337+
@PreAuthorize("hasRole('ADMIN')")
337338
public ResponseEntity<SurveyUnitSimplifiedDto> getResponseByCollectionInstrumentAndInterrogation(
338339
@PathVariable("collectionInstrumentId") String collectionInstrumentId,
339340
@PathVariable("interrogationId") String interrogationId,
@@ -407,6 +408,7 @@ public ResponseEntity<List<SurveyUnitSimplifiedDto>> getLatestForInterrogationLi
407408
return ResponseEntity.ok(results);
408409
}
409410

411+
//Kraftwerk uses this
410412
@Operation(summary = "Retrieve responses for a collection instrument and a list of interrogations",
411413
description = "Return the latest state for each variable for the given interrogationIds and a given collection instrument (formerly questionnaire).<br>" +
412414
"For a given id, the endpoint returns a document by collection mode (if there is more than one)<br>" +
@@ -696,6 +698,7 @@ private static String getSuccessMessage(boolean isAnyDataSaved) {
696698
*/
697699
//TODO Unused for now, reuse code for optimizations, also move it to service
698700
@Deprecated
701+
@Hidden
699702
@Operation(summary = "Retrieve all responses for a questionnaire and a list of UE",
700703
description = "Return the latest state for each variable for the given ids and a given questionnaire.<br>" +
701704
"For a given id, the endpoint returns a document by collection mode (if there is more than one).")

src/main/java/fr/insee/genesis/domain/service/surveyunit/SurveyUnitService.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,13 @@ private List<SurveyUnitModel> getLatestSurveyUnitModels(List<SurveyUnitModel> su
115115
List<SurveyUnitModel> latestUpdatesByVariables = new ArrayList<>();
116116

117117
List<Mode> modes = getDistinctsModes(surveyUnitModels);
118-
modes.forEach(mode ->{
118+
modes.forEach(mode -> {
119119
List<SurveyUnitModel> suByMode = surveyUnitModels.stream()
120120
.filter(surveyUnitModel -> surveyUnitModel.getMode().equals(mode))
121121
.sorted((o1, o2) -> o2.getRecordDate().compareTo(o1.getRecordDate())) //Sorting update by date (latest updates first by date of upload in database)
122122
.toList();
123123

124-
//We had all the variables of the oldest update
124+
//We add all the variables of the latest update
125125
latestUpdatesByVariables.add(suByMode.getFirst());
126126
//We keep the name of already added variables to skip them in older updates
127127
Set<VarIdScopeTuple> addedVariables = new HashSet<>();
@@ -142,7 +142,7 @@ private List<SurveyUnitModel> getLatestSurveyUnitModels(List<SurveyUnitModel> su
142142
;
143143

144144
suByMode.forEach(surveyUnitModel -> {
145-
//Get non null usualSurveyUnitId
145+
//Get non-null usualSurveyUnitId
146146
if (surveyUnitModel.getUsualSurveyUnitId() != null){
147147
latestUpdate.setUsualSurveyUnitId(surveyUnitModel.getUsualSurveyUnitId());
148148
}
@@ -173,9 +173,8 @@ private List<SurveyUnitModel> getLatestSurveyUnitModels(List<SurveyUnitModel> su
173173

174174
// If there are new variables, we add the update to the list of latest updates
175175
if (!collectedVariablesToKeep.isEmpty() || !externalVariablesToKeep.isEmpty()){
176-
surveyUnitModel.setCollectedVariables(collectedVariablesToKeep);
177-
surveyUnitModel.setExternalVariables(externalVariablesToKeep);
178-
latestUpdatesByVariables.add(surveyUnitModel);
176+
latestUpdate.getCollectedVariables().addAll(collectedVariablesToKeep);
177+
latestUpdate.getExternalVariables().addAll(externalVariablesToKeep);
179178
}
180179
});
181180
});

src/test/java/fr/insee/genesis/controller/rest/responses/RawResponseControllerIT.java

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import java.util.Set;
4545

4646
import static fr.insee.genesis.domain.utils.JsonUtils.jsonToMap;
47+
import static org.assertj.core.api.Assertions.assertThat;
4748
import static org.mockito.ArgumentMatchers.any;
4849
import static org.mockito.ArgumentMatchers.anyList;
4950
import static org.mockito.ArgumentMatchers.argThat;
@@ -518,6 +519,90 @@ void process_raw_response_keep_null_test(boolean isNullSurveyUnitValues) {
518519
Assertions.assertThat(variableDocument.getValue()).isNull();
519520
}
520521

522+
@ParameterizedTest
523+
@ValueSource(booleans = {false, true})
524+
@WithMockUser(roles = "SCHEDULER")
525+
@DisplayName("Filiere model raw data null values should be added if iterations already exists")
526+
@SneakyThrows
527+
void process_raw_response_add_null_iterations_test(boolean isNullSurveyUnitValues) {
528+
//GIVEN
529+
String collectionInstrumentId = "TESTQUEST";
530+
Mode mode = Mode.WEB;
531+
List<String> interrogationIds = List.of("INTERRO1");
532+
533+
//Raw response with absent variables
534+
String variableName = "VAR1";
535+
String collectedValue = "value1";
536+
Map<String, String> collectedVariablesAndValues = new HashMap<>();
537+
538+
String externalVariableName = "EXTVAR1";
539+
String externalValue = "externalvalue1";
540+
Map<String, String> externalVariablesAndValues = new HashMap<>();
541+
542+
setFiliereModelTestMockBehaviour(
543+
collectionInstrumentId,
544+
mode,
545+
interrogationIds,
546+
collectedVariablesAndValues,
547+
externalVariablesAndValues,
548+
true
549+
);
550+
551+
//Survey unit that already exists for first interrogation with null values or not
552+
SurveyUnitDocument alreadyPresentSurveyUnitDocument = getSurveyUnitDocumentWithIterations(
553+
collectionInstrumentId,
554+
interrogationIds.getFirst(),
555+
variableName,
556+
isNullSurveyUnitValues ? null : collectedValue,
557+
externalVariableName,
558+
isNullSurveyUnitValues ? null : externalValue
559+
);
560+
561+
when(surveyUnitMongoDBRepository.findByCollectionInstrumentIdAndInterrogationIds(collectionInstrumentId, interrogationIds))
562+
.thenReturn(List.of(alreadyPresentSurveyUnitDocument));
563+
564+
// WHEN
565+
mockMvc.perform(post("/raw-responses/%s/process".formatted(collectionInstrumentId))
566+
.with(csrf())
567+
.contentType(MediaType.APPLICATION_JSON))
568+
.andExpect(status().isOk());
569+
570+
//THEN
571+
@SuppressWarnings("unchecked")
572+
ArgumentCaptor<List<SurveyUnitDocument>> listArgumentCaptor =
573+
ArgumentCaptor.forClass(List.class);
574+
verify(surveyUnitMongoDBRepository, times(1))
575+
.insert(listArgumentCaptor.capture());
576+
577+
//Document must have null variables values
578+
List<SurveyUnitDocument> savedDocuments = listArgumentCaptor.getValue();
579+
Assertions.assertThat(savedDocuments).isNotNull().hasSize(interrogationIds.size());
580+
SurveyUnitDocument savedDocument = savedDocuments.stream().filter(
581+
surveyUnitDocument ->
582+
surveyUnitDocument.getInterrogationId().equals(interrogationIds.getFirst()))
583+
.toList().getFirst();
584+
585+
Assertions.assertThat(savedDocument.getCollectedVariables())
586+
.isNotNull()
587+
.hasSize(3)
588+
.allSatisfy(v -> {
589+
assertThat(v.getVarId()).isEqualTo(variableName);
590+
assertThat(v.getValue()).isNull();
591+
})
592+
.extracting(VariableDocument::getIteration)
593+
.containsExactlyInAnyOrder(1, 2, 3);
594+
595+
Assertions.assertThat(savedDocument.getExternalVariables())
596+
.isNotNull()
597+
.hasSize(3)
598+
.allSatisfy(v -> {
599+
assertThat(v.getVarId()).isEqualTo(externalVariableName);
600+
assertThat(v.getValue()).isNull();
601+
})
602+
.extracting(VariableDocument::getIteration)
603+
.containsExactlyInAnyOrder(1, 2, 3);
604+
}
605+
521606
@Test
522607
@WithMockUser(roles = "SCHEDULER")
523608
@DisplayName("Filiere model raw data shouldn't overwrite with null if not existent before")
@@ -1289,5 +1374,41 @@ private SurveyUnitDocument getSurveyUnitDocument(
12891374
return alreadyPresentSurveyUnitDocument;
12901375
}
12911376

1377+
private SurveyUnitDocument getSurveyUnitDocumentWithIterations(
1378+
String collectionInstrumentId,
1379+
String interrogationId,
1380+
String variableName,
1381+
String collectedValue,
1382+
String externalVariableName,
1383+
String externalValue
1384+
) {
1385+
SurveyUnitDocument alreadyPresentSurveyUnitDocument = new SurveyUnitDocument();
1386+
alreadyPresentSurveyUnitDocument.setCollectionInstrumentId(collectionInstrumentId);
1387+
alreadyPresentSurveyUnitDocument.setInterrogationId(interrogationId);
1388+
alreadyPresentSurveyUnitDocument.setMode(Mode.WEB.getModeName());
1389+
alreadyPresentSurveyUnitDocument.setState("COLLECTED");
1390+
1391+
alreadyPresentSurveyUnitDocument.setCollectedVariables(new ArrayList<>());
1392+
for(int i = 1; i <= 3; i++) {
1393+
VariableDocument oldVariable = new VariableDocument();
1394+
oldVariable.setVarId(variableName);
1395+
oldVariable.setIteration(i);
1396+
oldVariable.setValue(collectedValue);
1397+
oldVariable.setScope(Constants.ROOT_GROUP_NAME);
1398+
alreadyPresentSurveyUnitDocument.getCollectedVariables().add(oldVariable);
1399+
}
1400+
1401+
alreadyPresentSurveyUnitDocument.setExternalVariables(new ArrayList<>());
1402+
for(int i = 1; i <= 3; i++) {
1403+
VariableDocument oldVariable = new VariableDocument();
1404+
oldVariable.setVarId(externalVariableName);
1405+
oldVariable.setIteration(i);
1406+
oldVariable.setValue(externalValue);
1407+
oldVariable.setScope(Constants.ROOT_GROUP_NAME);
1408+
alreadyPresentSurveyUnitDocument.getExternalVariables().add(oldVariable);
1409+
}
1410+
return alreadyPresentSurveyUnitDocument;
1411+
}
1412+
12921413
//TODO GET tests
12931414
}

src/test/java/fr/insee/genesis/domain/converter/rawdata/RawDataConverterTest.java

Lines changed: 85 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import org.junit.jupiter.api.Nested;
1212
import org.junit.jupiter.api.Test;
1313
import org.junit.jupiter.api.extension.ExtendWith;
14+
import org.junit.jupiter.params.ParameterizedTest;
15+
import org.junit.jupiter.params.provider.ValueSource;
1416
import org.mockito.ArgumentCaptor;
1517
import org.mockito.InjectMocks;
1618
import org.mockito.Mock;
@@ -154,6 +156,7 @@ void bigDecimalIntegerDouble() {
154156
@Nested
155157
class convertCollectedVariablesTests{
156158
@Test
159+
@DisplayName("Should no nothing if no COLLECTED in payload and no last SU")
157160
void convertCollectedVariables_shouldDoNothing_whenNoCollectedKeyAndNoLastSurveyUnit() {
158161
Map<String, Object> payload = new HashMap<>();
159162

@@ -176,12 +179,13 @@ void convertCollectedVariables_shouldDoNothing_whenNoCollectedKeyAndNoLastSurvey
176179
}
177180

178181
@Test
182+
@DisplayName("Should no nothing if no COLLECTED in payload and last SU does not match datastate")
179183
void convertCollectedVariables_shouldDoNothing_whenNoCollectedKeyAndLastSurveyUnitStateDoesNotMatch() {
180-
Map<String, Object> payload = new HashMap<>(); // pas de clé "COLLECTED"
184+
Map<String, Object> payload = new HashMap<>();
181185

182186
SurveyUnitModel lastSurveyUnit = SurveyUnitModel.builder()
183187
.interrogationId("INT1")
184-
.state(DataState.FORCED) // différent de DataState.COLLECTED
188+
.state(DataState.FORCED)
185189
.collectedVariables(List.of(
186190
VariableModel.builder().varId("VAR1").value("val").iteration(1).build()
187191
))
@@ -206,12 +210,13 @@ void convertCollectedVariables_shouldDoNothing_whenNoCollectedKeyAndLastSurveyUn
206210
}
207211

208212
@Test
213+
@DisplayName("Should add null variable if no COLLECTED in payload and last SU has the variable")
209214
void convertCollectedVariables_shouldAddNullVariable_whenNoCollectedKeyAndLastSurveyUnitHasSingleVariable() {
210-
Map<String, Object> payload = new HashMap<>(); // pas de clé "COLLECTED"
215+
Map<String, Object> payload = new HashMap<>();
211216

212217
SurveyUnitModel lastSurveyUnit = SurveyUnitModel.builder()
213218
.interrogationId("INT1")
214-
.state(DataState.COLLECTED) // même état que dataState attendu
219+
.state(DataState.COLLECTED)
215220
.collectedVariables(List.of(
216221
VariableModel.builder().varId("VAR1").value("oldVal").iteration(1).build()
217222
))
@@ -242,9 +247,17 @@ void convertCollectedVariables_shouldAddNullVariable_whenNoCollectedKeyAndLastSu
242247
});
243248
}
244249

245-
@Test
246-
void convertCollectedVariables_shouldAddNullVariablesForEachIteration_whenNoCollectedKeyAndLastSurveyUnitHasMultipleIterations() {
247-
Map<String, Object> payload = new HashMap<>(); // pas de clé "COLLECTED"
250+
@ParameterizedTest
251+
@ValueSource(booleans = {false, true})
252+
@DisplayName("Should add null iterations if variable or COLLECED key absent in payload and last SU has the variable with iterations")
253+
void convertCollectedVariables_shouldAddNullVariablesForEachIteration_whenLastSurveyUnitHasMultipleIterations(
254+
boolean isCollectedKeyPresentInPayload
255+
) {
256+
Map<String, Object> payload = new HashMap<>();
257+
if(isCollectedKeyPresentInPayload) {
258+
Map<String, Object> dataMap = new HashMap<>();
259+
payload.put("COLLECTED", dataMap);
260+
}
248261

249262
SurveyUnitModel lastSurveyUnit = SurveyUnitModel.builder()
250263
.interrogationId("INT1")
@@ -280,14 +293,78 @@ void convertCollectedVariables_shouldAddNullVariablesForEachIteration_whenNoColl
280293
.extracting(VariableModel::iteration)
281294
.containsExactlyInAnyOrder(1, 2, 3);
282295
}
296+
297+
@Test
298+
@DisplayName("Should add null iterations that are absent in payload")
299+
void convertCollectedVariables_shouldAddNullIterations_whenLastSurveyUnitHasMultipleIterations() {
300+
//GIVEN
301+
String variableName = "VAR1";
302+
303+
Map<String, Object> dataMap = new HashMap<>();
304+
List<String> newValues = new ArrayList<>();
305+
newValues.add(null); //Null raw value on first iteration
306+
newValues.addAll(List.of("new2", "new3"));
307+
dataMap.put(variableName, Map.of("COLLECTED", newValues));
308+
Map<String, Object> payload = new HashMap<>();
309+
payload.put("COLLECTED", dataMap);
310+
311+
SurveyUnitModel lastSurveyUnit = SurveyUnitModel.builder()
312+
.interrogationId("INT1")
313+
.state(DataState.COLLECTED)
314+
.collectedVariables(List.of(
315+
VariableModel.builder().varId(variableName).value("old1").iteration(1).build(),
316+
VariableModel.builder().varId(variableName).value("old2").iteration(2).build(),
317+
VariableModel.builder().varId(variableName).value("old3").iteration(3).build()
318+
))
319+
.build();
320+
321+
SurveyUnitModel dst = SurveyUnitModel.builder()
322+
.interrogationId("INT1")
323+
.collectedVariables(new ArrayList<>())
324+
.build();
325+
326+
//WHEN
327+
rawDataConverterTestImpl.convertCollectedVariables(
328+
payload,
329+
"INT1",
330+
lastSurveyUnit,
331+
dst,
332+
DataState.COLLECTED,
333+
RawDataModelType.FILIERE,
334+
variablesMap
335+
);
336+
337+
assertThat(dst.getCollectedVariables())
338+
.hasSize(3)
339+
.extracting(VariableModel::iteration)
340+
.containsExactlyInAnyOrder(1, 2, 3);
341+
342+
//First iteration present and null
343+
assertThat(dst.getCollectedVariables())
344+
.filteredOn(variableModel -> variableModel.varId().equals(variableName)
345+
&& variableModel.iteration().equals(1))
346+
.extracting(VariableModel::value)
347+
.containsOnlyNulls();
348+
349+
//Other iterations
350+
assertThat(dst.getCollectedVariables())
351+
.filteredOn(variableModel ->
352+
variableModel.iteration().equals(2) || variableModel.iteration().equals(3))
353+
.hasSize(2)
354+
.allSatisfy(v -> {
355+
assertThat(v.varId()).isEqualTo("VAR1");
356+
})
357+
.extracting(VariableModel::value)
358+
.containsExactlyInAnyOrder("new2","new3");
359+
}
283360
}
284361

285362
@DisplayName("convertExternalVariables tests")
286363
@Nested
287364
class convertExternalVariablesTests {
288365
@Test
289366
void convertExternalVariables_shouldDoNothing_whenNoExternalKeyAndNoLastSurveyUnit() {
290-
Map<String, Object> payload = new HashMap<>(); // pas de clé "EXTERNAL"
367+
Map<String, Object> payload = new HashMap<>();
291368

292369
SurveyUnitModel dst = SurveyUnitModel.builder()
293370
.interrogationId("INT1")

0 commit comments

Comments
 (0)