aboutsummaryrefslogtreecommitdiffstats
path: root/poi-ooxml/src/test/java/org/apache/poi/util/tests/TestTempFileThreaded.java
blob: 4110ef456b31b063f7dee0af9c95d1ca31481a5f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/* ====================================================================
   Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed with
   this work for additional information regarding copyright ownership.
   The ASF licenses this file to You under the Apache License, Version 2.0
   (the "License"); you may not use this file except in compliance with
   the License.  You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
==================================================================== */
package org.apache.poi.util.tests;

import static org.apache.poi.util.DefaultTempFileCreationStrategy.POIFILES;
import static org.apache.poi.util.TempFile.JAVA_IO_TMPDIR;
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.util.SuppressForbidden;
import org.apache.poi.util.TempFile;
import org.apache.poi.util.TempFileCreationStrategy;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class TestTempFileThreaded {
    private static final int NUMBER_OF_THREADS = 10;
    private static final int NUMBER_OF_TESTS = 200;

    private volatile Throwable exception;
    private int[] executions;

    // the actual thread-safe temp-file strategy
    private static TempFileCreationStrategy createTempFileCreationStrategy(File poiTempFileDirectory) {
        return new TempFileCreationStrategy() {
            @SuppressForbidden("Thread.getId() is deprecated and replaced with threadId() in JDK 19+")
            @Override
            public File createTempFile(String prefix, String suffix) throws IOException {
                long threadId = Thread.currentThread().getId();
                File threadDir = new File(poiTempFileDirectory, Long.toString(threadId));
                if (!threadDir.exists()) {
                    if (!threadDir.mkdirs()) {
                        throw new IOException("mkdir of " + threadDir + " failed");
                    }
                }

                File file = File.createTempFile(prefix, suffix, threadDir);
                file.deleteOnExit();
                return file;
            }

            @Override
            public File createTempDirectory(String prefix) {
                throw new UnsupportedOperationException("createTempDirectory");
            }
        };
    }

    @BeforeAll
    public static void setUpClass() throws IOException {
        String tmpDir = System.getProperty(JAVA_IO_TMPDIR);
        if (tmpDir == null) {
            throw new IOException("System's temporary directory not defined - set the -D" + JAVA_IO_TMPDIR + " jvm property!");
        }

        TempFile.setTempFileCreationStrategy(createTempFileCreationStrategy(
                Paths.get(tmpDir, POIFILES, "TestTempFileThreaded").toFile()));
    }

    @BeforeEach
    void setUp() {
        // Initialize array to allow to summarize afterwards
        executions = new int[NUMBER_OF_THREADS];
    }

    @Test
    void runTest() throws Throwable {
        List<Thread> threads = new LinkedList<>();

        // start all threads
        for (int i = 0; i < NUMBER_OF_THREADS; i++) {
            Thread t = startThread(i, new TestRunnable());
            threads.add(t);
        }

        // wait for all threads
        for (int i = 0; i < NUMBER_OF_THREADS; i++) {
            threads.get(i).join();
        }

        // report exceptions if there were any
        if (exception != null) {
            throw exception;
        }

        // make sure the resulting number of executions is correct
        for (int i = 0; i < NUMBER_OF_THREADS; i++) {
            // check if enough items were performed
            assertEquals(NUMBER_OF_TESTS, executions[i], "Thread " + i + " did not execute all iterations");
        }
    }

    private static class TestRunnable {
        Map<Integer, List<File>> files = new HashMap<>();

        public TestRunnable() {
            for (int i = 0; i < NUMBER_OF_THREADS; i++) {
                files.put(i, new ArrayList<>());
            }
        }

        void doEnd(int threadNum) {
            for (File file : files.get(threadNum)) {
                if (!file.exists()) {
                    throw new IllegalStateException("File " + file + " does not exist");
                }
                if (!file.delete()) {
                    throw new IllegalStateException("Deletion of " + file + " failed");
                }
            }
        }

        void run(int threadNum, int iter) throws Exception {
            try (SXSSFWorkbook wb = new SXSSFWorkbook()) {
                SXSSFSheet sheet = wb.createSheet("test");

                for (int i = 0; i < 100; i++) {
                    Row row = sheet.createRow(i);
                    for (int j = 0; j < 10; j++) {
                        Cell cell = row.createCell(j);
                        cell.setCellValue("123");
                    }
                }

                File file = TempFile.createTempFile("TestTempFile-" + threadNum + "-" + iter + "-", ".xlsx");
                try (OutputStream outputStream = new FileOutputStream(file)) {
                    wb.write(outputStream);
                }

                files.get(threadNum).add(file);
            }
        }
    }

    private Thread startThread(final int threadNum, final TestRunnable run) {
        Thread t1 = new Thread(() -> {
            try {
                for (int iter = 0; iter < NUMBER_OF_TESTS && exception == null; iter++) {
                    // call the actual test-code
                    run.run(threadNum, iter);

                    executions[threadNum]++;
                }

                // do end-work here, we don't do this in a finally as we log
                // Exception
                // then anyway
                run.doEnd(threadNum);
            } catch (Throwable e) {
                exception = e;
            }

        }, "ThreadTestHelper-Thread " + threadNum + ": " + run.getClass().getName());

        t1.start();

        return t1;
    }
}