puzhibing
2026-08-28 e92cd56bb56b111c1afe9922191f9897215ff6b0
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
package com.sinata.appointment.service;
 
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
 
import com.sinata.appointment.config.LocalFileUploadProperties;
import com.sinata.appointment.mapper.MpStaffGroupMapper;
import com.sinata.appointment.mapper.MpStaffGroupMemberMapper;
import com.sinata.appointment.mapper.MpUserMapper;
import com.sinata.appointment.mapper.SysDeptMapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
 
class UploadStreamCloseTest {
 
    @Test
    void localImageUploadClosesMultipartInputStream() throws Exception {
        LocalFileUploadProperties properties = new LocalFileUploadProperties();
        ReflectionTestUtils.setField(properties, "fileUploadPath", Files.createTempDirectory("image-upload").toString());
        ReflectionTestUtils.setField(properties, "pictureServerAddress", "https://example.test/resources");
        LocalImageUploadService service = new LocalImageUploadService(properties);
        CloseTrackingMultipartFile file = new CloseTrackingMultipartFile("photo.png", "image/png");
 
        service.uploadImage(file);
 
        assertThat(file.lastStreamClosed()).isTrue();
    }
 
    @Test
    void staffAvatarUploadClosesMultipartInputStream() throws Exception {
        String previousUserDir = System.getProperty("user.dir");
        System.setProperty("user.dir", Files.createTempDirectory("staff-avatar-upload").toString());
        RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(new MockHttpServletRequest()));
        try {
            StaffManageApplicationService service =
                    new StaffManageApplicationService(
                            mock(MpUserMapper.class),
                            mock(SysDeptMapper.class),
                            mock(MpStaffGroupMemberMapper.class),
                            mock(MpStaffGroupMapper.class));
            CloseTrackingMultipartFile file = new CloseTrackingMultipartFile("avatar.jpg", "image/jpeg");
 
            service.uploadAvatar(file);
 
            assertThat(file.lastStreamClosed()).isTrue();
        } finally {
            RequestContextHolder.resetRequestAttributes();
            System.setProperty("user.dir", previousUserDir);
        }
    }
 
    private static final class CloseTrackingMultipartFile implements MultipartFile {
        private final String originalFilename;
        private final String contentType;
        private CloseTrackingInputStream lastStream;
 
        private CloseTrackingMultipartFile(String originalFilename, String contentType) {
            this.originalFilename = originalFilename;
            this.contentType = contentType;
        }
 
        boolean lastStreamClosed() {
            return lastStream != null && lastStream.closed;
        }
 
        @Override
        public String getName() {
            return "file";
        }
 
        @Override
        public String getOriginalFilename() {
            return originalFilename;
        }
 
        @Override
        public String getContentType() {
            return contentType;
        }
 
        @Override
        public boolean isEmpty() {
            return false;
        }
 
        @Override
        public long getSize() {
            return 4;
        }
 
        @Override
        public byte[] getBytes() {
            return new byte[] {1, 2, 3, 4};
        }
 
        @Override
        public InputStream getInputStream() {
            lastStream = new CloseTrackingInputStream(getBytes());
            return lastStream;
        }
 
        @Override
        public void transferTo(java.io.File dest) throws IOException, IllegalStateException {
            Files.write(dest.toPath(), getBytes());
        }
    }
 
    private static final class CloseTrackingInputStream extends ByteArrayInputStream {
        private boolean closed;
 
        private CloseTrackingInputStream(byte[] buf) {
            super(buf);
        }
 
        @Override
        public void close() throws IOException {
            closed = true;
            super.close();
        }
    }
}