Skip to content

Commit

Permalink
fix import with cache clear
Browse files Browse the repository at this point in the history
Signed-off-by: Antoine MAZEAS <[email protected]>
  • Loading branch information
antoinemzs committed Jan 20, 2025
1 parent 60c6534 commit cd7cf52
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import io.openbas.utils.fixtures.composers.*;
import io.openbas.utils.mockUser.WithMockAdminUser;
import jakarta.annotation.Resource;

import java.io.ByteArrayInputStream;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.*;
Expand Down Expand Up @@ -106,8 +108,9 @@ private Exercise getExercise() {
.withTag(tagComposer.forTag(TagFixture.getTagWithText("Challenge tag")))))
.withDocument(
documentComposer
.forDocument(DocumentFixture.getDocumentJpeg())
.withTag(tagComposer.forTag(TagFixture.getTagWithText("Document tag"))))
.forDocument(DocumentFixture.getDocumentTxt(FileFixture.getPlainTextFileContent()))
.withTag(tagComposer.forTag(TagFixture.getTagWithText("Document tag")))
.withInMemoryFile(FileFixture.getPlainTextFileContent()))
.withObjective(objectiveComposer.forObjective(ObjectiveFixture.getObjective()))
.withTag(tagComposer.forTag(TagFixture.getTagWithText("Exercise tag")))
.withVariable(variableComposer.forVariable(VariableFixture.getVariable()))
Expand All @@ -129,7 +132,7 @@ public void given_a_valid_simulation_the_export_file_is_found_in_zip_and_correct
.getResponse()
.getContentAsByteArray();

String actualJson = ZipUtils.getZipEntryAsString(response, "%s.json".formatted(ex.getName()));
String actualJson = ZipUtils.getZipEntry(response, "%s.json".formatted(ex.getName()), ZipUtils::streamToString);
ObjectMapper exportMapper = mapper.copy();
String expectedJson =
exportMapper.writeValueAsString(
Expand Down Expand Up @@ -158,7 +161,7 @@ public void given_a_valid_simulation_the_export_file_is_found_in_zip_and_correct
.getResponse()
.getContentAsByteArray();

String actualJson = ZipUtils.getZipEntryAsString(response, "%s.json".formatted(ex.getName()));
String actualJson = ZipUtils.getZipEntry(response, "%s.json".formatted(ex.getName()), ZipUtils::streamToString);
ObjectMapper exportMapper = mapper.copy();
String expectedJson =
exportMapper.writeValueAsString(
Expand All @@ -182,7 +185,7 @@ public void given_a_valid_simulation_and_default_options_exported_tags_are_corre
.getResponse()
.getContentAsByteArray();

String actualJson = ZipUtils.getZipEntryAsString(response, "%s.json".formatted(ex.getName()));
String actualJson = ZipUtils.getZipEntry(response, "%s.json".formatted(ex.getName()), ZipUtils::streamToString);

objectMapper.addMixIn(Tag.class, ExerciseExportMixins.Tag.class);
List<Tag> expectedTags =
Expand Down Expand Up @@ -217,7 +220,7 @@ public void given_a_valid_simulation_and_default_options_exported_objectives_are
.getResponse()
.getContentAsByteArray();

String actualJson = ZipUtils.getZipEntryAsString(response, "%s.json".formatted(ex.getName()));
String actualJson = ZipUtils.getZipEntry(response, "%s.json".formatted(ex.getName()), ZipUtils::streamToString);

objectMapper.addMixIn(Objective.class, ExerciseExportMixins.Objective.class);
String objectiveJson = objectMapper.writeValueAsString(objectiveComposer.generatedItems);
Expand All @@ -243,7 +246,7 @@ public void given_a_valid_simulation_and_default_options_exported_challenges_are
.getResponse()
.getContentAsByteArray();

String actualJson = ZipUtils.getZipEntryAsString(response, "%s.json".formatted(ex.getName()));
String actualJson = ZipUtils.getZipEntry(response, "%s.json".formatted(ex.getName()), ZipUtils::streamToString);

objectMapper.addMixIn(Challenge.class, ExerciseExportMixins.Challenge.class);
String challengeJson = objectMapper.writeValueAsString(challengeComposer.generatedItems);
Expand All @@ -269,7 +272,7 @@ public void given_a_valid_simulation_and_default_options_exported_articles_are_c
.getResponse()
.getContentAsByteArray();

String actualJson = ZipUtils.getZipEntryAsString(response, "%s.json".formatted(ex.getName()));
String actualJson = ZipUtils.getZipEntry(response, "%s.json".formatted(ex.getName()), ZipUtils::streamToString);

objectMapper.addMixIn(Article.class, ExerciseExportMixins.Article.class);
String articleJson = objectMapper.writeValueAsString(articleComposer.generatedItems);
Expand All @@ -295,7 +298,7 @@ public void given_a_valid_simulation_and_default_options_exported_channels_are_c
.getResponse()
.getContentAsByteArray();

String actualJson = ZipUtils.getZipEntryAsString(response, "%s.json".formatted(ex.getName()));
String actualJson = ZipUtils.getZipEntry(response, "%s.json".formatted(ex.getName()), ZipUtils::streamToString);

objectMapper.addMixIn(Channel.class, ExerciseExportMixins.Channel.class);
String channelJson = objectMapper.writeValueAsString(channelComposer.generatedItems);
Expand All @@ -321,7 +324,7 @@ public void given_a_valid_simulation_and_default_options_exported_documents_are_
.getResponse()
.getContentAsByteArray();

String actualJson = ZipUtils.getZipEntryAsString(response, "%s.json".formatted(ex.getName()));
String actualJson = ZipUtils.getZipEntry(response, "%s.json".formatted(ex.getName()), ZipUtils::streamToString);

objectMapper.addMixIn(Document.class, ExerciseExportMixins.Document.class);
String documentJson = objectMapper.writeValueAsString(documentComposer.generatedItems);
Expand All @@ -347,7 +350,7 @@ public void given_a_valid_simulation_and_default_options_exported_exercise_info_
.getResponse()
.getContentAsByteArray();

String actualJson = ZipUtils.getZipEntryAsString(response, "%s.json".formatted(ex.getName()));
String actualJson = ZipUtils.getZipEntry(response, "%s.json".formatted(ex.getName()), ZipUtils::streamToString);

objectMapper.addMixIn(Exercise.class, ExerciseExportMixins.Exercise.class);
String exerciseJson = objectMapper.writeValueAsString(ex);
Expand All @@ -373,7 +376,7 @@ public void given_a_valid_simulation_and_default_options_exported_variables_have
.getResponse()
.getContentAsByteArray();

String actualJson = ZipUtils.getZipEntryAsString(response, "%s.json".formatted(ex.getName()));
String actualJson = ZipUtils.getZipEntry(response, "%s.json".formatted(ex.getName()), ZipUtils::streamToString);

objectMapper.addMixIn(Variable.class, VariableMixin.class);
String variableJson = objectMapper.writeValueAsString(variableComposer.generatedItems);
Expand Down Expand Up @@ -403,7 +406,7 @@ public void given_a_valid_simulation_and_default_options_exported_variables_have
.getResponse()
.getContentAsByteArray();

String actualJson = ZipUtils.getZipEntryAsString(response, "%s.json".formatted(ex.getName()));
String actualJson = ZipUtils.getZipEntry(response, "%s.json".formatted(ex.getName()), ZipUtils::streamToString);

objectMapper.addMixIn(Variable.class, VariableWithValueMixin.class);
String variableJson = objectMapper.writeValueAsString(variableComposer.generatedItems);
Expand All @@ -428,7 +431,7 @@ public void given_a_valid_simulation_and_default_options_exported_teams_is_empty
.getResponse()
.getContentAsByteArray();

String actualJson = ZipUtils.getZipEntryAsString(response, "%s.json".formatted(ex.getName()));
String actualJson = ZipUtils.getZipEntry(response, "%s.json".formatted(ex.getName()), ZipUtils::streamToString);

assertThatJson(actualJson).when(IGNORING_ARRAY_ORDER).node("exercise_teams").isEqualTo("[]");
}
Expand All @@ -452,7 +455,7 @@ public void given_a_valid_simulation_and_default_options_exported_teams_is_empty
.getResponse()
.getContentAsByteArray();

String actualJson = ZipUtils.getZipEntryAsString(response, "%s.json".formatted(ex.getName()));
String actualJson = ZipUtils.getZipEntry(response, "%s.json".formatted(ex.getName()), ZipUtils::streamToString);

objectMapper.addMixIn(Team.class, ExerciseExportMixins.EmptyTeam.class);
String teamsJson = objectMapper.writeValueAsString(teamComposer.generatedItems);
Expand All @@ -479,7 +482,7 @@ public void given_a_valid_simulation_and_default_options_exported_users_is_absen
.getResponse()
.getContentAsByteArray();

String actualJson = ZipUtils.getZipEntryAsString(response, "%s.json".formatted(ex.getName()));
String actualJson = ZipUtils.getZipEntry(response, "%s.json".formatted(ex.getName()), ZipUtils::streamToString);

assertThatJson(actualJson).when(IGNORING_ARRAY_ORDER).node("exercise_users").isAbsent();
}
Expand All @@ -503,7 +506,7 @@ public void given_a_valid_simulation_and_default_options_exported_users_is_absen
.getResponse()
.getContentAsByteArray();

String actualJson = ZipUtils.getZipEntryAsString(response, "%s.json".formatted(ex.getName()));
String actualJson = ZipUtils.getZipEntry(response, "%s.json".formatted(ex.getName()), ZipUtils::streamToString);

objectMapper.addMixIn(User.class, ExerciseExportMixins.User.class);
String usersJson = objectMapper.writeValueAsString(userComposer.generatedItems);
Expand All @@ -529,7 +532,7 @@ public void given_a_valid_simulation_and_default_options_exported_organisations_
.getResponse()
.getContentAsByteArray();

String actualJson = ZipUtils.getZipEntryAsString(response, "%s.json".formatted(ex.getName()));
String actualJson = ZipUtils.getZipEntry(response, "%s.json".formatted(ex.getName()), ZipUtils::streamToString);

assertThatJson(actualJson).when(IGNORING_ARRAY_ORDER).node("exercise_users").isAbsent();
}
Expand All @@ -553,7 +556,7 @@ public void given_a_valid_simulation_and_default_options_exported_organisations_
.getResponse()
.getContentAsByteArray();

String actualJson = ZipUtils.getZipEntryAsString(response, "%s.json".formatted(ex.getName()));
String actualJson = ZipUtils.getZipEntry(response, "%s.json".formatted(ex.getName()), ZipUtils::streamToString);

objectMapper.addMixIn(Organization.class, ExerciseExportMixins.Organization.class);
String orgJson = objectMapper.writeValueAsString(organizationComposer.generatedItems);
Expand All @@ -563,4 +566,35 @@ public void given_a_valid_simulation_and_default_options_exported_organisations_
.node("exercise_organizations")
.isEqualTo(orgJson);
}

@DisplayName(
"Given documents are provided, exported archive contains the documents")
@Test
@WithMockAdminUser
public void
given_documents_are_provided_exported_archive_contains_the_documents()
throws Exception {
ObjectMapper objectMapper = mapper.copy();
Exercise ex = getExercise();
byte[] response =
mvc.perform(
get(EXERCISE_URI + "/" + ex.getId() + "/export")
.queryParam("isWithPlayers", "true")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().is2xxSuccessful())
.andReturn()
.getResponse()
.getContentAsByteArray();

List<Document> docs = documentComposer.generatedItems;

for (Document document : docs) {
try(ByteArrayInputStream fis = new ByteArrayInputStream(FileFixture.getPlainTextFileContent().getContentBytes())) {
byte[] docFromZip = ZipUtils.getZipEntry(response, document.getTarget(), ZipUtils::streamToBytes);
byte[] docFromDisk = fis.readAllBytes();

Assertions.assertArrayEquals(docFromZip, docFromDisk);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,21 @@

import io.openbas.IntegrationTest;
import io.openbas.database.model.Exercise;
import io.openbas.database.repository.DocumentRepository;
import io.openbas.database.repository.ExerciseRepository;
import io.openbas.database.repository.TeamRepository;
import io.openbas.rest.exercise.exports.ExportOptions;
import io.openbas.rest.exercise.service.ExportService;
import io.openbas.utils.ZipUtils;
import io.openbas.utils.fixtures.*;
import io.openbas.utils.fixtures.composers.*;
import io.openbas.utils.mockUser.WithMockAdminUser;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Optional;

import jakarta.persistence.EntityManager;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
Expand All @@ -30,6 +35,7 @@ public class ExerciseApiImportTest extends IntegrationTest {
@Autowired private MockMvc mvc;
@Autowired private ExerciseComposer exerciseComposer;
@Autowired private ExerciseRepository exerciseRepository;
@Autowired private DocumentRepository documentRepository;

@Autowired private TeamRepository teamRepository;
@Autowired private ArticleComposer articleComposer;
Expand All @@ -46,9 +52,10 @@ public class ExerciseApiImportTest extends IntegrationTest {
@Autowired private DocumentComposer documentComposer;
@Autowired private TagComposer tagComposer;
@Autowired private ExportService exportService;
@Autowired private EntityManager entityManager;

private static int DEFAULT_EXPORT_OPTIONS = ExportOptions.mask(false, false, false);
private static int FULL_EXPORT_OPTIONS = ExportOptions.mask(true, true, true);
private static final int DEFAULT_EXPORT_OPTIONS = ExportOptions.mask(false, false, false);
private static final int FULL_EXPORT_OPTIONS = ExportOptions.mask(true, true, true);

@BeforeEach
void before() {
Expand Down Expand Up @@ -106,8 +113,9 @@ private ExerciseComposer.Composer getExercise() {
.withTag(tagComposer.forTag(TagFixture.getTagWithText("Challenge tag")))))
.withDocument(
documentComposer
.forDocument(DocumentFixture.getDocumentJpeg())
.withTag(tagComposer.forTag(TagFixture.getTagWithText("Document tag"))))
.forDocument(DocumentFixture.getDocumentTxt(FileFixture.getPlainTextFileContent()))
.withTag(tagComposer.forTag(TagFixture.getTagWithText("Document tag")))
.withInMemoryFile(FileFixture.getPlainTextFileContent()))
.withObjective(objectiveComposer.forObjective(ObjectiveFixture.getObjective()))
.withTag(tagComposer.forTag(TagFixture.getTagWithText("Exercise tag")))
.withVariable(variableComposer.forVariable(VariableFixture.getVariable()));
Expand All @@ -120,11 +128,6 @@ public void testImport() throws Exception {
ExerciseComposer.Composer exerciseWrapper = getExercise();
Exercise exercise = exerciseWrapper.persist().get();
byte[] zipBytes = exportService.exportExerciseToZip(exercise, FULL_EXPORT_OPTIONS);
File outputFile = new File("/home/antoinemzs/testExercise.zip");
try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
outputStream.write(zipBytes);
}
String json = ZipUtils.getZipEntryAsString(zipBytes, "%s.json".formatted(exercise.getName()));
exerciseWrapper.delete();

MockMultipartFile mmf = new MockMultipartFile("file", zipBytes);
Expand All @@ -135,6 +138,16 @@ public void testImport() throws Exception {
.contentType(MediaType.MULTIPART_FORM_DATA))
.andExpect(status().is2xxSuccessful());

Assertions.assertEquals(exerciseRepository.findAll().getFirst(), exercise);
// force hibernate to clear its cache to not pollute fetch operations
// TODO: make this automatic somehow, perhaps within Composers
entityManager.clear();

Optional<Exercise> exerciseFromDb = exerciseRepository.findAll().stream().findFirst();
if (exerciseFromDb.isEmpty()) {
Assertions.fail();
}
Exercise imported = exerciseFromDb.get();

Assertions.assertEquals(imported, exercise);
}
}
38 changes: 29 additions & 9 deletions openbas-api/src/test/java/io/openbas/utils/ZipUtils.java
Original file line number Diff line number Diff line change
@@ -1,29 +1,49 @@
package io.openbas.utils;


import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.function.Function;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class ZipUtils {
// not this only works
public static String getZipEntryAsString(byte[] zipBlob, String entryName) throws IOException {
public static <T> T getZipEntry(byte[] zipBlob, String entryName, Function<InputStream, T> readFunc) throws IOException {
try (ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(zipBlob))) {
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
if (entry.getName().equals(entryName)) {
StringBuilder sb = new StringBuilder();
byte[] buffer = new byte[1024];
int read = 0;
while ((read = zis.read(buffer, 0, 1024)) >= 0) {
sb.append(new String(buffer, 0, read));
}
// force exit of test since we have found the correct entry
return sb.toString();
return readFunc.apply(zis);
}
}
// no zip entry corresponding to expected json
throw new IOException("Zip entry '%s' not found".formatted(entryName));
}
}

public static String streamToString(InputStream is) {
StringBuilder sb = new StringBuilder();
byte[] buffer = new byte[1024];
int read = 0;
while (true) {
try {
if (!((read = is.read(buffer, 0, 1024)) >= 0)) break;
} catch (IOException e) {
throw new RuntimeException(e);
}
sb.append(new String(buffer, 0, read));
}
// force exit of test since we have found the correct entry
return sb.toString();
}

public static byte[] streamToBytes(InputStream is) {
try {
return is.readAllBytes();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
package io.openbas.utils.fixtures;

import io.openbas.database.model.Document;
import io.openbas.utils.fixtures.files.BaseFile;

public class DocumentFixture {

public static final String DOCUMENT_NAME = "A document";
public static final String TXT_DOCUMENT_NAME = "My text document";

public static Document getDocumentJpeg() {
Document document = new Document();
document.setName(DOCUMENT_NAME);
document.setType("image/jpeg");
return document;
}

public static Document getDocumentTxt(BaseFile<String> plainTextFile) {
Document document = new Document();
document.setName(TXT_DOCUMENT_NAME);
document.setType(plainTextFile.getMimeType());
document.setTarget(plainTextFile.getFileName());
return document;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.openbas.utils.fixtures;


import io.openbas.utils.fixtures.files.PlainTextFile;


public class FileFixture {
public static String DEFAULT_PLAIN_TEXT_CONTENT = "default plain text content";
public static String DEFAULT_PLAIN_TEXT_FILENAME = "plain_text.txt";

public static PlainTextFile getPlainTextFileContent() {
return new PlainTextFile(DEFAULT_PLAIN_TEXT_CONTENT, DEFAULT_PLAIN_TEXT_FILENAME);
}
}
Loading

0 comments on commit cd7cf52

Please sign in to comment.