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.

TestXSSFMemoryLeak.java 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.xssf;
  16. import static org.junit.jupiter.api.Assertions.assertNull;
  17. import static org.junit.jupiter.api.Assertions.assertSame;
  18. import static org.junit.jupiter.api.Assertions.assertThrows;
  19. import java.io.File;
  20. import java.io.IOException;
  21. import java.io.OutputStream;
  22. import java.util.ArrayList;
  23. import java.util.List;
  24. import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream;
  25. import org.apache.poi.ooxml.POIXMLException;
  26. import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
  27. import org.apache.poi.openxml4j.opc.OPCPackage;
  28. import org.apache.poi.util.MemoryLeakVerifier;
  29. import org.apache.poi.xssf.usermodel.XSSFCell;
  30. import org.apache.poi.xssf.usermodel.XSSFRow;
  31. import org.apache.poi.xssf.usermodel.XSSFSheet;
  32. import org.apache.poi.xssf.usermodel.XSSFWorkbook;
  33. import org.junit.jupiter.api.AfterEach;
  34. import org.junit.jupiter.api.Test;
  35. import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell;
  36. /**
  37. * A test which uses {@link MemoryLeakVerifier} to ensure that certain
  38. * objects are not left over in memory after the test.
  39. *
  40. * E.g. verifies that objects are freed when stuff is removed from sheets or rows
  41. */
  42. public class TestXSSFMemoryLeak {
  43. private final MemoryLeakVerifier verifier = new MemoryLeakVerifier();
  44. // keep some items in memory, so checks in tearDown() actually
  45. // verify that they do not keep certain objects in memory,
  46. // e.g. nested CT... objects which should be released
  47. @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
  48. private final List<Object> references = new ArrayList<>();
  49. @AfterEach
  50. void tearDown() {
  51. verifier.assertGarbageCollected();
  52. }
  53. @Test
  54. void testWriteRow() throws IOException {
  55. try (XSSFWorkbook wb = new XSSFWorkbook()) {
  56. final XSSFSheet sheet1 = wb.createSheet("Sheet1");
  57. final XSSFRow row = sheet1.createRow(0);
  58. final XSSFCell cell = row.createCell(0);
  59. cell.setCellValue("hello");
  60. // Cannot check the CTCell here as it is reused now and thus
  61. // not freed until we free up the Cell itself
  62. //verifier.addObject(ctCell);
  63. try (OutputStream out = new UnsynchronizedByteArrayOutputStream(8192)) {
  64. wb.write(out);
  65. }
  66. CTCell ctCell = cell.getCTCell();
  67. assertSame(cell.getCTCell(), ctCell, "The CTCell should not be replaced");
  68. assertSame(row.getCTRow().getCArray(0), ctCell, "The CTCell in the row should not be replaced");
  69. }
  70. }
  71. @Test
  72. void testRemoveCellFromRow() throws IOException {
  73. try (XSSFWorkbook wb = new XSSFWorkbook()) {
  74. final XSSFSheet sheet1 = wb.createSheet("Sheet1");
  75. final XSSFRow rowToCheck = sheet1.createRow(0);
  76. references.add(rowToCheck);
  77. XSSFCell cell = rowToCheck.createCell(0);
  78. cell.setCellValue("hello");
  79. // previously the CTCell was still referenced in the CTRow, verify that it is freed
  80. verifier.addObject(cell);
  81. verifier.addObject(cell.getCTCell());
  82. rowToCheck.removeCell(cell);
  83. assertNull(rowToCheck.getCell(0));
  84. }
  85. }
  86. @Test
  87. void testRemove2CellsFromRow() throws IOException {
  88. try (XSSFWorkbook wb = new XSSFWorkbook()) {
  89. final XSSFSheet sheet1 = wb.createSheet("Sheet1");
  90. final XSSFRow rowToCheck = sheet1.createRow(0);
  91. references.add(rowToCheck);
  92. XSSFCell cell1 = rowToCheck.createCell(0);
  93. cell1.setCellValue("hello");
  94. XSSFCell cell2 = rowToCheck.createCell(1);
  95. cell2.setCellValue("world");
  96. // previously the CTCell was still referenced in the CTRow, verify that it is freed
  97. verifier.addObject(cell1);
  98. verifier.addObject(cell1.getCTCell());
  99. verifier.addObject(cell2);
  100. verifier.addObject(cell2.getCTCell());
  101. rowToCheck.removeCell(cell2);
  102. rowToCheck.removeCell(cell1);
  103. assertNull(rowToCheck.getCell(0));
  104. assertNull(rowToCheck.getCell(1));
  105. }
  106. }
  107. @Test
  108. void testRemoveRowFromSheet() throws IOException {
  109. try (XSSFWorkbook wb1 = new XSSFWorkbook()) {
  110. final XSSFSheet sheetToCheck = wb1.createSheet("Sheet1");
  111. references.add(sheetToCheck);
  112. final XSSFRow row = sheetToCheck.createRow(0);
  113. final XSSFCell cell = row.createCell(0);
  114. cell.setCellValue(1);
  115. // ensure that the row-data is not kept somewhere in another member
  116. verifier.addObject(row.getCTRow());
  117. verifier.addObject(row);
  118. verifier.addObject(cell.getCTCell());
  119. verifier.addObject(cell);
  120. sheetToCheck.removeRow(row);
  121. assertNull(sheetToCheck.getRow(0));
  122. }
  123. }
  124. @Test
  125. void testFileLeak() {
  126. File file = XSSFTestDataSamples.getSampleFile("xlsx-corrupted.xlsx");
  127. verifier.addObject(file);
  128. assertThrows(POIXMLException.class, () -> new XSSFWorkbook(file), "Should catch exception as the file is corrupted");
  129. }
  130. @Test
  131. void testFileLeak2() throws IOException, InvalidFormatException {
  132. File file = XSSFTestDataSamples.getSampleFile("xlsx-corrupted.xlsx");
  133. verifier.addObject(file);
  134. try (OPCPackage pkg = OPCPackage.open(file)) {
  135. assertThrows(POIXMLException.class, () -> new XSSFWorkbook(pkg), "Should catch exception as the file is corrupted");
  136. }
  137. }
  138. }