1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.bremersee.minio;
18
19 import static org.awaitility.Awaitility.await;
20 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
21 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
22 import static org.junit.jupiter.api.Assertions.assertEquals;
23 import static org.junit.jupiter.api.Assertions.assertFalse;
24 import static org.junit.jupiter.api.Assertions.assertNotNull;
25 import static org.junit.jupiter.api.Assertions.assertThrows;
26 import static org.junit.jupiter.api.Assertions.assertTrue;
27 import static org.junit.jupiter.api.Assertions.fail;
28 import static org.mockito.ArgumentMatchers.any;
29 import static org.mockito.Mockito.mock;
30 import static org.mockito.Mockito.when;
31
32 import io.minio.BucketExistsArgs;
33 import io.minio.CloseableIterator;
34 import io.minio.ComposeObjectArgs;
35 import io.minio.CopyObjectArgs;
36 import io.minio.DeleteBucketCorsArgs;
37 import io.minio.DeleteBucketEncryptionArgs;
38 import io.minio.DeleteBucketLifecycleArgs;
39 import io.minio.DeleteBucketNotificationArgs;
40 import io.minio.DeleteBucketPolicyArgs;
41 import io.minio.DeleteBucketReplicationArgs;
42 import io.minio.DeleteBucketTagsArgs;
43 import io.minio.DeleteObjectLockConfigurationArgs;
44 import io.minio.DeleteObjectTagsArgs;
45 import io.minio.DisableObjectLegalHoldArgs;
46 import io.minio.DownloadObjectArgs;
47 import io.minio.EnableObjectLegalHoldArgs;
48 import io.minio.GetBucketCorsArgs;
49 import io.minio.GetBucketEncryptionArgs;
50 import io.minio.GetBucketLifecycleArgs;
51 import io.minio.GetBucketNotificationArgs;
52 import io.minio.GetBucketPolicyArgs;
53 import io.minio.GetBucketReplicationArgs;
54 import io.minio.GetBucketTagsArgs;
55 import io.minio.GetBucketVersioningArgs;
56 import io.minio.GetObjectAclArgs;
57 import io.minio.GetObjectArgs;
58 import io.minio.GetObjectAttributesArgs;
59 import io.minio.GetObjectAttributesResponse;
60 import io.minio.GetObjectLockConfigurationArgs;
61 import io.minio.GetObjectResponse;
62 import io.minio.GetObjectRetentionArgs;
63 import io.minio.GetObjectTagsArgs;
64 import io.minio.GetPresignedObjectUrlArgs;
65 import io.minio.HeadObjectResponse;
66 import io.minio.Http;
67 import io.minio.IsObjectLegalHoldEnabledArgs;
68 import io.minio.ListBucketsArgs;
69 import io.minio.ListObjectsArgs;
70 import io.minio.ListenBucketNotificationArgs;
71 import io.minio.MakeBucketArgs;
72 import io.minio.MinioClient;
73 import io.minio.ObjectWriteResponse;
74 import io.minio.PostPolicy;
75 import io.minio.PromptObjectArgs;
76 import io.minio.PromptObjectResponse;
77 import io.minio.PutObjectArgs;
78 import io.minio.PutObjectFanOutArgs;
79 import io.minio.PutObjectFanOutResponse;
80 import io.minio.RemoveBucketArgs;
81 import io.minio.RemoveObjectArgs;
82 import io.minio.RemoveObjectsArgs;
83 import io.minio.RestoreObjectArgs;
84 import io.minio.Result;
85 import io.minio.SelectObjectContentArgs;
86 import io.minio.SelectResponseStream;
87 import io.minio.SetBucketCorsArgs;
88 import io.minio.SetBucketEncryptionArgs;
89 import io.minio.SetBucketLifecycleArgs;
90 import io.minio.SetBucketNotificationArgs;
91 import io.minio.SetBucketPolicyArgs;
92 import io.minio.SetBucketReplicationArgs;
93 import io.minio.SetBucketTagsArgs;
94 import io.minio.SetBucketVersioningArgs;
95 import io.minio.SetObjectLockConfigurationArgs;
96 import io.minio.SetObjectRetentionArgs;
97 import io.minio.SetObjectTagsArgs;
98 import io.minio.SourceObject;
99 import io.minio.StatObjectArgs;
100 import io.minio.StatObjectResponse;
101 import io.minio.Time;
102 import io.minio.UploadObjectArgs;
103 import io.minio.errors.ErrorResponseException;
104 import io.minio.messages.AccessControlList;
105 import io.minio.messages.AccessControlList.Grant;
106 import io.minio.messages.AccessControlList.Grantee;
107 import io.minio.messages.AccessControlList.Permission;
108 import io.minio.messages.AccessControlList.Type;
109 import io.minio.messages.AccessControlPolicy;
110 import io.minio.messages.CORSConfiguration;
111 import io.minio.messages.CORSConfiguration.CORSRule;
112 import io.minio.messages.DeleteRequest.Object;
113 import io.minio.messages.DeleteResult;
114 import io.minio.messages.ErrorResponse;
115 import io.minio.messages.Filter;
116 import io.minio.messages.GetObjectAttributesOutput;
117 import io.minio.messages.InputSerialization;
118 import io.minio.messages.InputSerialization.JsonType;
119 import io.minio.messages.Item;
120 import io.minio.messages.LifecycleConfiguration;
121 import io.minio.messages.ListAllMyBucketsResult;
122 import io.minio.messages.NotificationConfiguration;
123 import io.minio.messages.NotificationRecords;
124 import io.minio.messages.ObjectLockConfiguration;
125 import io.minio.messages.OutputSerialization;
126 import io.minio.messages.Owner;
127 import io.minio.messages.ReplicationConfiguration;
128 import io.minio.messages.Retention;
129 import io.minio.messages.RetentionMode;
130 import io.minio.messages.SseConfiguration;
131 import io.minio.messages.Status;
132 import io.minio.messages.Tags;
133 import io.minio.messages.VersioningConfiguration;
134 import java.io.ByteArrayInputStream;
135 import java.io.File;
136 import java.io.InputStream;
137 import java.net.URI;
138 import java.nio.charset.StandardCharsets;
139 import java.nio.file.Files;
140 import java.nio.file.StandardOpenOption;
141 import java.text.SimpleDateFormat;
142 import java.time.ZonedDateTime;
143 import java.util.ArrayList;
144 import java.util.Collections;
145 import java.util.Date;
146 import java.util.HashMap;
147 import java.util.LinkedList;
148 import java.util.List;
149 import java.util.Locale;
150 import java.util.Map;
151 import java.util.Optional;
152 import java.util.Random;
153 import java.util.UUID;
154 import okhttp3.Headers;
155 import okhttp3.HttpUrl;
156 import okhttp3.Protocol;
157 import okhttp3.Request;
158 import okhttp3.Response;
159 import org.apache.commons.logging.Log;
160 import org.apache.commons.logging.LogFactory;
161 import org.assertj.core.api.Assertions;
162 import org.junit.jupiter.api.AfterAll;
163 import org.junit.jupiter.api.BeforeAll;
164 import org.junit.jupiter.api.BeforeEach;
165 import org.junit.jupiter.api.MethodOrderer;
166 import org.junit.jupiter.api.Order;
167 import org.junit.jupiter.api.Test;
168 import org.junit.jupiter.api.TestInstance;
169 import org.junit.jupiter.api.TestInstance.Lifecycle;
170 import org.junit.jupiter.api.TestMethodOrder;
171 import org.mockito.Mockito;
172 import org.springframework.http.HttpStatus;
173 import org.springframework.http.MediaType;
174 import org.springframework.util.FileCopyUtils;
175
176
177
178
179
180
181 @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
182 @TestInstance(Lifecycle.PER_CLASS)
183 class MinioTemplateTest {
184
185 private static final Log log = LogFactory.getLog(MinioTemplateTest.class);
186
187 private static final SimpleDateFormat SDF = new SimpleDateFormat(
188 "yyyy-MM-dd-HH-mm-ss", Locale.GERMANY);
189
190 private static final String DEFAULT_BUCKET = "bremersee-"
191 + SDF.format(new Date()) + "-"
192 + UUID.randomUUID().toString().replace("-", "").toLowerCase();
193
194 private MinioTemplate playMinio;
195
196 private MinioClient mockClient;
197
198 private MinioTemplate mockMinio;
199
200 private boolean playMinioEnabled = true;
201
202
203
204
205 @BeforeAll
206 void setUp() {
207 String testExecutor = System.getProperty(
208 "org.bremersee.test.executor",
209 "NOT_SPECIFIED");
210 log.info(String.format("JUnit test executor is %s", testExecutor));
211 if ("BUILD_SYSTEM".equals(testExecutor)) {
212 log.info("Test executor is build system, so mocked minio client will be used.");
213 playMinioEnabled = false;
214 } else {
215 log.info("Test executor is unknown, trying to use play minio client ...");
216 try {
217 MinioClient playMinioClient = MinioClient.builder()
218 .endpoint(HttpUrl.get("https://play.min.io"))
219 .credentials("Q3AM3UQ867SPQQA43P2F", "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG")
220 .build();
221 playMinio = new MinioTemplate(playMinioClient);
222 if (playMinio.bucketExists(BucketExistsArgs.builder().bucket(DEFAULT_BUCKET).build())) {
223 playMinio.removeBucket(RemoveBucketArgs.builder().bucket(DEFAULT_BUCKET).build());
224 }
225 playMinio.makeBucket(MakeBucketArgs.builder().bucket(DEFAULT_BUCKET).build());
226 playMinioEnabled = true;
227 log.info("Using play minio client.");
228
229 } catch (Exception e) {
230 playMinioEnabled = false;
231 log.warn("Using play minio client is not possible. Using mocked minio client.", e);
232 }
233 }
234 }
235
236
237
238
239 @AfterAll
240 void afterAll() {
241 if (playMinioEnabled
242 && playMinio.bucketExists(BucketExistsArgs.builder().bucket(DEFAULT_BUCKET).build())) {
243 playMinio.removeBucket(RemoveBucketArgs.builder().bucket(DEFAULT_BUCKET).build());
244 }
245 }
246
247
248
249
250 @BeforeEach
251 void beforeEach() {
252 mockClient = Mockito.mock(MinioClient.class);
253 mockMinio = new MinioTemplate(mockClient);
254 }
255
256 private String newBucketName() {
257 return "bremersee-" + UUID.randomUUID().toString().toLowerCase();
258 }
259
260 private MinioTemplate minioTemplate(String methodName, MockMinioClientConfigurator config) {
261 if (playMinioEnabled) {
262 log.info(String.format("Running '%s' with play.min.io", methodName));
263 return playMinio;
264 }
265 log.info(String.format("Running '%s' with mocked minio client", methodName));
266 Optional.ofNullable(config)
267 .ifPresent(c -> c.configureMock(mockClient));
268 return mockMinio;
269 }
270
271 private MinioTemplate minioMockTemplate(String methodName, MockMinioClientConfigurator config) {
272 log.info(String.format("Running '%s' with mocked minio client", methodName));
273 Optional.ofNullable(config)
274 .ifPresent(c -> c.configureMock(mockClient));
275 return mockMinio;
276 }
277
278
279
280
281 @Order(1)
282 @Test
283 void copyMinioTemplate() {
284 assertNotNull(mockMinio.copy());
285 assertNotNull(mockMinio.copy(new DefaultMinioErrorHandler()));
286 }
287
288
289
290
291 @Order(10)
292 @Test
293 void makeAndRemoveBucket() {
294 String bucketName = newBucketName();
295
296 MinioTemplate minio = minioTemplate("makeAndRemoveBucket", mock -> {
297 when(mock.bucketExists(any(BucketExistsArgs.class))).thenReturn(true);
298 ListAllMyBucketsResult.Bucket bucket = Mockito.mock(ListAllMyBucketsResult.Bucket.class);
299 when(bucket.name()).thenReturn(bucketName);
300 when(bucket.creationDate()).thenReturn(ZonedDateTime.now());
301 when(mock.listBuckets(any(ListBucketsArgs.class))).thenReturn(List.of(new Result<>(bucket)));
302 });
303
304 minio.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
305 assertTrue(minio.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()));
306
307 Iterable<Result<ListAllMyBucketsResult.Bucket>> buckets = minio
308 .listBuckets(ListBucketsArgs.builder().build());
309 assertNotNull(buckets);
310 List<ListAllMyBucketsResult.Bucket> bucketList = new ArrayList<>();
311 for (Result<ListAllMyBucketsResult.Bucket> result : buckets) {
312 try {
313 bucketList.add(result.get());
314 } catch (Exception e) {
315
316 }
317 }
318 assertFalse(bucketList.isEmpty());
319 assertTrue(bucketList.stream().anyMatch(bucket -> bucket.name().equals(bucketName)));
320
321 minio.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
322 if (playMinioEnabled) {
323 assertFalse(minio.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()));
324 }
325 }
326
327
328
329
330 @Order(12)
331 @Test
332 void makeAndRemoveBucketWithObjectLock() {
333 String bucketName = newBucketName();
334
335 MinioTemplate minio = minioTemplate("makeAndRemoveBucketWithObjectLock", mock -> {
336 ListAllMyBucketsResult.Bucket bucket = Mockito.mock(ListAllMyBucketsResult.Bucket.class);
337 when(bucket.name()).thenReturn(bucketName);
338 when(bucket.creationDate()).thenReturn(ZonedDateTime.now());
339 when(mock.listBuckets()).thenReturn(List.of(bucket));
340 when(mock.bucketExists(any(BucketExistsArgs.class))).thenReturn(false);
341 });
342
343 minio.makeBucket(MakeBucketArgs.builder()
344 .bucket(bucketName)
345 .objectLock(true)
346 .build());
347 List<ListAllMyBucketsResult.Bucket> buckets = minio.listBuckets();
348 assertNotNull(buckets);
349 assertFalse(buckets.isEmpty());
350 assertTrue(buckets.stream().anyMatch(bucket -> bucket.name().equals(bucketName)));
351
352 minio.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
353 assertFalse(minio.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()));
354 }
355
356
357
358
359 @Order(20)
360 @Test
361 void bucketEncryption() {
362 final String bucket = newBucketName();
363
364 MinioTemplate minio = minioTemplate("bucketEncryption", mock ->
365 when(mock.getBucketEncryption(any(GetBucketEncryptionArgs.class)))
366 .thenReturn(SseConfiguration.newConfigWithSseS3Rule())
367 );
368
369 minio.makeBucket(MakeBucketArgs.builder()
370 .bucket(bucket)
371 .objectLock(true)
372 .build());
373
374 try {
375 minio.setBucketEncryption(SetBucketEncryptionArgs.builder()
376 .bucket(bucket)
377 .config(SseConfiguration.newConfigWithSseS3Rule())
378 .build());
379
380 SseConfiguration config = minio.getBucketEncryption(GetBucketEncryptionArgs.builder()
381 .bucket(bucket)
382 .build());
383 assertNotNull(config);
384
385 minio.deleteBucketEncryption(DeleteBucketEncryptionArgs.builder()
386 .bucket(bucket)
387 .build());
388
389 } finally {
390 minio.removeBucket(RemoveBucketArgs.builder()
391 .bucket(bucket)
392 .build());
393 }
394 }
395
396
397
398
399 @Order(30)
400 @Test
401 void bucketLifecycle() {
402 final String bucket = newBucketName();
403 final LifecycleConfiguration.Rule rule0 = new LifecycleConfiguration.Rule(
404 Status.ENABLED,
405 null,
406 new LifecycleConfiguration.Expiration((ZonedDateTime) null, 365, null, null),
407 new Filter("logs/"),
408 null,
409 null,
410 null,
411 null
412 );
413 final LifecycleConfiguration config = new LifecycleConfiguration(List.of(rule0));
414
415 MinioTemplate minio = minioTemplate("bucketLifecycle", mock ->
416 when(mock.getBucketLifecycle(any(GetBucketLifecycleArgs.class)))
417 .thenReturn(config)
418 );
419
420 minio.makeBucket(MakeBucketArgs.builder()
421 .bucket(bucket)
422 .objectLock(true)
423 .build());
424
425 try {
426 minio.setBucketLifecycle(SetBucketLifecycleArgs.builder()
427 .bucket(bucket)
428 .config(config)
429 .build());
430
431 Optional<LifecycleConfiguration> optionalConfig = minio.getBucketLifecycle(
432 GetBucketLifecycleArgs.builder()
433 .bucket(bucket)
434 .build());
435 assertTrue(optionalConfig.isPresent());
436 LifecycleConfiguration readConfig = optionalConfig.get();
437 assertFalse(readConfig.rules().isEmpty());
438 LifecycleConfiguration.Rule readRule0 = readConfig.rules().getFirst();
439 assertEquals(Status.ENABLED, readRule0.status());
440
441 minio.deleteBucketLifecycle(DeleteBucketLifecycleArgs.builder()
442 .bucket(bucket)
443 .build());
444 optionalConfig = minio.getBucketLifecycle(GetBucketLifecycleArgs.builder()
445 .bucket(bucket)
446 .build());
447 if (playMinioEnabled) {
448 assertFalse(optionalConfig.isPresent());
449 }
450
451 } finally {
452 minio.removeBucket(RemoveBucketArgs.builder()
453 .bucket(bucket)
454 .build());
455 }
456 }
457
458
459
460
461
462
463 @Order(40)
464 @Test
465 void bucketNotification() throws Exception {
466 NotificationConfiguration config = new NotificationConfiguration(
467 null,
468 null,
469 null,
470 null);
471 when(mockClient.getBucketNotification(any(GetBucketNotificationArgs.class)))
472 .thenReturn(config);
473 mockMinio.setBucketNotification(SetBucketNotificationArgs.builder()
474 .bucket(DEFAULT_BUCKET)
475 .config(config)
476 .build());
477 NotificationConfiguration readConfig = mockMinio.getBucketNotification(
478 GetBucketNotificationArgs.builder()
479 .bucket(DEFAULT_BUCKET)
480 .build());
481 assertNotNull(readConfig);
482
483 mockMinio.deleteBucketNotification(DeleteBucketNotificationArgs.builder()
484 .bucket(DEFAULT_BUCKET)
485 .build());
486
487 when(mockClient.listenBucketNotification(any(ListenBucketNotificationArgs.class)))
488 .thenReturn(new CloseableIterator<>() {
489
490 private boolean hasNext = true;
491
492 @Override
493 public void close() {
494
495 }
496
497 @Override
498 public boolean hasNext() {
499 return hasNext;
500 }
501
502 @Override
503 public Result<NotificationRecords> next() {
504 if (hasNext) {
505 NotificationRecords records = new NotificationRecords();
506 Result<NotificationRecords> result = new Result<>(records);
507 hasNext = false;
508 return result;
509 }
510 return null;
511 }
512 });
513
514 try (CloseableIterator<Result<NotificationRecords>> in = mockMinio
515 .listenBucketNotification(ListenBucketNotificationArgs.builder()
516 .bucket(DEFAULT_BUCKET)
517 .events(new String[]{"s3:ObjectCreated:*", "s3:ObjectAccessed:*"})
518 .prefix("")
519 .suffix("")
520 .build())) {
521 assertNotNull(in);
522 assertTrue(in.hasNext());
523 }
524 }
525
526
527
528
529
530
531 @Order(50)
532 @Test
533 void bucketPolicy() throws Exception {
534 String policy = "{}";
535 when(mockClient.getBucketPolicy(any(GetBucketPolicyArgs.class))).thenReturn(policy);
536 mockMinio.setBucketPolicy(SetBucketPolicyArgs.builder()
537 .bucket(DEFAULT_BUCKET)
538 .config(policy)
539 .build());
540 String readPolicy = mockMinio.getBucketPolicy(GetBucketPolicyArgs.builder()
541 .bucket(DEFAULT_BUCKET)
542 .build());
543 assertEquals(policy, readPolicy);
544 mockMinio.deleteBucketPolicy(DeleteBucketPolicyArgs.builder()
545 .bucket(DEFAULT_BUCKET)
546 .build());
547 }
548
549
550
551
552
553
554 @Order(60)
555 @Test
556 void bucketReplication() throws Exception {
557 Map<String, String> tags = new HashMap<>();
558 tags.put("key1", "value1");
559 tags.put("key2", "value2");
560 ReplicationConfiguration.Rule rule =
561 new ReplicationConfiguration.Rule(
562 Status.DISABLED,
563 new ReplicationConfiguration.Destination(
564 null,
565 null,
566 "REPLACE-WITH-ACTUAL-DESTINATION-BUCKET-ARN",
567 null,
568 null,
569 null,
570 null),
571 null,
572 null,
573 new Filter(new Filter.And("TaxDocs", tags, null, null)),
574 "rule1",
575 null,
576 1,
577 null,
578 null);
579 List<ReplicationConfiguration.Rule> rules = new LinkedList<>();
580 rules.add(rule);
581 ReplicationConfiguration config = new ReplicationConfiguration("REPLACE-WITH-ACTUAL-ROLE",
582 rules);
583
584 when(mockClient.getBucketReplication(any(GetBucketReplicationArgs.class))).thenReturn(config);
585
586 mockMinio.setBucketReplication(SetBucketReplicationArgs.builder()
587 .bucket(DEFAULT_BUCKET)
588 .config(config)
589 .build());
590 Optional<ReplicationConfiguration> optCfg = mockMinio.getBucketReplication(
591 GetBucketReplicationArgs.builder()
592 .bucket(DEFAULT_BUCKET)
593 .build());
594 assertTrue(optCfg.isPresent());
595 mockMinio.deleteBucketReplication(DeleteBucketReplicationArgs.builder()
596 .bucket(DEFAULT_BUCKET)
597 .build());
598 }
599
600
601
602
603 @Order(65)
604 @Test
605 void bucketCors() {
606 List<CORSRule> rules = List.of(
607 new CORSRule(
608 List.of("*"),
609 List.of("PUT", "POST", "DELETE"),
610 List.of("*"),
611 null,
612 null,
613 3000
614 )
615 );
616 CORSConfiguration corsConfiguration = new CORSConfiguration(rules);
617 MinioTemplate minio = minioTemplate("bucketCors", mock ->
618 when(mock.getBucketCors(any(GetBucketCorsArgs.class)))
619 .thenReturn(corsConfiguration)
620 );
621
622 SetBucketCorsArgs setBucketCorsArgs = SetBucketCorsArgs.builder()
623 .bucket(DEFAULT_BUCKET)
624 .config(corsConfiguration)
625 .build();
626 minio.setBucketCors(setBucketCorsArgs);
627
628 GetBucketCorsArgs getBucketCorsArgs = GetBucketCorsArgs.builder()
629 .bucket(DEFAULT_BUCKET)
630 .build();
631 CORSConfiguration actual = minio.getBucketCors(getBucketCorsArgs);
632 Assertions.assertThat(actual)
633 .usingRecursiveComparison()
634 .isEqualTo(corsConfiguration);
635
636 DeleteBucketCorsArgs deleteBucketCorsArgs = DeleteBucketCorsArgs.builder()
637 .bucket(DEFAULT_BUCKET)
638 .build();
639 minio.deleteBucketCors(deleteBucketCorsArgs);
640 }
641
642
643
644
645 @Order(70)
646 @Test
647 void bucketTags() {
648 Map<String, String> tagMap = Collections.singletonMap("my-key", "my-value");
649 MinioTemplate minio = minioTemplate("bucketTags", mock ->
650 when(mock.getBucketTags(any(GetBucketTagsArgs.class)))
651 .thenReturn(Tags.newBucketTags(tagMap))
652 );
653 minio.setBucketTags(SetBucketTagsArgs.builder()
654 .bucket(DEFAULT_BUCKET)
655 .tags(tagMap)
656 .build());
657 Tags tags = minio.getBucketTags(GetBucketTagsArgs.builder()
658 .bucket(DEFAULT_BUCKET)
659 .build());
660 assertNotNull(tags);
661 assertTrue(tags.get().containsKey("my-key"));
662 assertTrue(tags.get().containsValue("my-value"));
663
664 minio.deleteBucketTags(DeleteBucketTagsArgs.builder()
665 .bucket(DEFAULT_BUCKET)
666 .build());
667 }
668
669
670
671
672 @Order(80)
673 @Test
674 void bucketVersioning() {
675
676 final String bucketName = newBucketName();
677 final VersioningConfiguration config = new VersioningConfiguration(
678 VersioningConfiguration.Status.ENABLED, null, null, false);
679 MinioTemplate minio = minioTemplate("bucketVersioning", mock ->
680 when(mock.getBucketVersioning(any(GetBucketVersioningArgs.class))).thenReturn(config)
681 );
682
683 minio.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
684 try {
685 minio.setBucketVersioning(SetBucketVersioningArgs.builder()
686 .bucket(bucketName)
687 .config(config)
688 .build());
689
690 VersioningConfiguration readConfig = minio.getBucketVersioning(
691 GetBucketVersioningArgs.builder()
692 .bucket(bucketName)
693 .build());
694
695 assertNotNull(readConfig);
696 assertEquals(VersioningConfiguration.Status.ENABLED, readConfig.status());
697
698 } finally {
699 minio.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
700 }
701 }
702
703
704
705
706 @Order(90)
707 @Test
708 void objectLockConfiguration() {
709
710 final String bucketName = newBucketName();
711 final ObjectLockConfiguration config = new ObjectLockConfiguration(
712 RetentionMode.COMPLIANCE,
713 new ObjectLockConfiguration.RetentionDurationDays(100));
714 MinioTemplate minio = minioTemplate("objectLockConfiguration", mock ->
715 when(mock.getObjectLockConfiguration(any(GetObjectLockConfigurationArgs.class))).thenReturn(
716 config)
717 );
718
719 minio.makeBucket(MakeBucketArgs.builder()
720 .bucket(bucketName)
721 .objectLock(true)
722 .build());
723 try {
724 minio.setObjectLockConfiguration(SetObjectLockConfigurationArgs.builder()
725 .bucket(bucketName)
726 .config(config)
727 .build());
728
729 ObjectLockConfiguration readConfig = minio.getObjectLockConfiguration(
730 GetObjectLockConfigurationArgs.builder()
731 .bucket(bucketName)
732 .build());
733 assertNotNull(readConfig);
734 assertEquals(RetentionMode.COMPLIANCE, readConfig.mode());
735
736 minio.deleteObjectLockConfiguration(DeleteObjectLockConfigurationArgs.builder()
737 .bucket(bucketName)
738 .build());
739
740 } finally {
741 minio.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
742 }
743 }
744
745
746
747
748
749
750
751 @Order(1010)
752 @Test
753 void putAndRemoveObject() throws Exception {
754
755 String objectName = UUID.randomUUID() + ".txt";
756
757 MinioTemplate minio = minioTemplate("putAndRemoveObject", mock -> {
758 when(mock.putObject(any(PutObjectArgs.class)))
759 .thenReturn(new ObjectWriteResponse(
760 Headers.of(Collections.emptyMap()),
761 DEFAULT_BUCKET,
762 null,
763 objectName,
764 null,
765 null
766 ));
767 when(mock.listObjects(any(ListObjectsArgs.class))).thenReturn(Collections.emptyList());
768 });
769 byte[] value = "Hello Minio".getBytes(StandardCharsets.UTF_8);
770 ObjectWriteResponse response = minio.putObject(PutObjectArgs.builder()
771 .bucket(DEFAULT_BUCKET)
772 .object(objectName)
773 .stream(new ByteArrayInputStream(value), (long) value.length, -1L)
774 .contentType(MediaType.TEXT_PLAIN_VALUE)
775 .build());
776 assertNotNull(response);
777
778 boolean contains = false;
779 Iterable<Result<Item>> results;
780 if (playMinioEnabled) {
781 results = minio
782 .listObjects(ListObjectsArgs.builder().bucket(DEFAULT_BUCKET).build());
783 for (Result<Item> result : results) {
784 Item item = result.get();
785 if (objectName.equals(item.objectName())) {
786 contains = true;
787 break;
788 }
789 }
790 assertTrue(contains);
791 }
792
793 minio.removeObject(RemoveObjectArgs.builder()
794 .bucket(DEFAULT_BUCKET)
795 .object(objectName)
796 .build());
797
798 results = minio
799 .listObjects(ListObjectsArgs.builder().bucket(DEFAULT_BUCKET).build());
800 contains = false;
801 for (Result<Item> result : results) {
802 Item item = result.get();
803 if (objectName.equals(item.objectName())) {
804 contains = true;
805 break;
806 }
807 }
808 assertFalse(contains);
809 }
810
811
812
813
814
815
816 @Order(1020)
817 @Test
818 void uploadObject() throws Exception {
819
820 String objectName = UUID.randomUUID() + ".txt";
821 MinioTemplate minio = minioTemplate("uploadObject", mock -> {
822 when(mock.uploadObject(any(UploadObjectArgs.class)))
823 .thenReturn(new ObjectWriteResponse(
824 Headers.of(Collections.emptyMap()),
825 DEFAULT_BUCKET,
826 null,
827 objectName,
828 null,
829 null
830 ));
831 when(mock.getPresignedObjectUrl(any(GetPresignedObjectUrlArgs.class)))
832 .thenReturn("http://localhost/somewhere");
833 });
834 byte[] value = "Hello Minio".getBytes(StandardCharsets.UTF_8);
835 try {
836 File file = File.createTempFile(
837 "junit", ".tmp", new File(System.getProperty("java.io.tmpdir")));
838 FileCopyUtils.copy(
839 value,
840 Files.newOutputStream(
841 file.toPath(),
842 StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING));
843 ObjectWriteResponse response = minio.uploadObject(
844 UploadObjectArgs.builder()
845 .bucket(DEFAULT_BUCKET)
846 .object(objectName)
847 .filename(file.getAbsolutePath())
848 .contentType(MediaType.TEXT_PLAIN_VALUE)
849 .build(),
850 DeleteMode.ALWAYS);
851 assertNotNull(response);
852
853 assertFalse(file.exists());
854 String url = minio.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
855 .bucket(DEFAULT_BUCKET)
856 .object(objectName)
857 .method(Http.Method.GET)
858 .expiry(3600 * 24)
859 .build());
860 assertNotNull(url);
861 if (playMinioEnabled) {
862 try (InputStream in = new URI(url).toURL().openStream()) {
863 byte[] readBytes = FileCopyUtils.copyToByteArray(in);
864 assertArrayEquals(value, readBytes);
865 }
866 }
867
868 } finally {
869 minio.removeObject(RemoveObjectArgs.builder()
870 .bucket(DEFAULT_BUCKET)
871 .object(objectName)
872 .build());
873 }
874 }
875
876
877
878
879
880
881 @Order(1030)
882 @Test
883 void downloadObject() throws Exception {
884
885 String objectName = UUID.randomUUID() + ".txt";
886 MinioTemplate minio = minioTemplate("downloadObject", mock -> {
887 when(mock.putObject(any(PutObjectArgs.class)))
888 .thenReturn(new ObjectWriteResponse(
889 Headers.of(Collections.emptyMap()),
890 DEFAULT_BUCKET,
891 null,
892 objectName,
893 null,
894 null
895 ));
896 when(mock.uploadObject(any(UploadObjectArgs.class)))
897 .thenReturn(new ObjectWriteResponse(
898 Headers.of(Collections.emptyMap()),
899 DEFAULT_BUCKET,
900 null,
901 objectName,
902 null,
903 null
904 ));
905 });
906 byte[] value = "Hello Minio".getBytes(StandardCharsets.UTF_8);
907 ObjectWriteResponse response = minio.putObject(PutObjectArgs.builder()
908 .bucket(DEFAULT_BUCKET)
909 .object(objectName)
910 .stream(new ByteArrayInputStream(value), (long) value.length, -1L)
911 .contentType(MediaType.TEXT_PLAIN_VALUE)
912 .build());
913 assertNotNull(response);
914
915 File file = null;
916 try {
917 file = File.createTempFile(
918 "junit", ".tmp", new File(System.getProperty("java.io.tmpdir")));
919 if (playMinioEnabled) {
920 Files.delete(file.toPath());
921 }
922 minio.downloadObject(DownloadObjectArgs.builder()
923 .bucket(DEFAULT_BUCKET)
924 .object(objectName)
925 .filename(file.getAbsolutePath())
926 .build());
927 if (playMinioEnabled) {
928 byte[] fileBytes = FileCopyUtils.copyToByteArray(file);
929 assertArrayEquals(value, fileBytes);
930 }
931
932 } finally {
933 if (file != null) {
934 Files.delete(file.toPath());
935 }
936 minio.removeObject(RemoveObjectArgs.builder()
937 .bucket(DEFAULT_BUCKET)
938 .object(objectName)
939 .build());
940 }
941 }
942
943
944
945
946
947
948 @Order(1040)
949 @Test
950 void presignedObjectUrl() throws Exception {
951
952 String objectName = UUID.randomUUID() + ".txt";
953 MinioTemplate minio = minioTemplate("presignedObjectUrl", mock -> {
954 when(mock.putObject(any(PutObjectArgs.class)))
955 .thenReturn(new ObjectWriteResponse(
956 Headers.of(Collections.emptyMap()),
957 DEFAULT_BUCKET,
958 null,
959 objectName,
960 null,
961 null
962 ));
963 when(mock.getPresignedObjectUrl(any(GetPresignedObjectUrlArgs.class)))
964 .thenReturn("http://localhost/somewhere");
965 });
966 byte[] value = "Hello Minio".getBytes(StandardCharsets.UTF_8);
967 ObjectWriteResponse response = minio.putObject(PutObjectArgs.builder()
968 .bucket(DEFAULT_BUCKET)
969 .object(objectName)
970 .stream(new ByteArrayInputStream(value), (long) value.length, -1L)
971 .contentType(MediaType.TEXT_PLAIN_VALUE)
972 .build());
973 assertNotNull(response);
974
975 try {
976 String url = minio.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
977 .bucket(DEFAULT_BUCKET)
978 .object(objectName)
979 .method(Http.Method.GET)
980 .expiry(3600 * 24)
981 .build());
982 assertNotNull(url);
983 if (playMinioEnabled) {
984 try (InputStream in = new URI(url).toURL().openStream()) {
985 byte[] readBytes = FileCopyUtils.copyToByteArray(in);
986 assertArrayEquals(value, readBytes);
987 }
988 }
989
990 } finally {
991 minio.removeObject(RemoveObjectArgs.builder()
992 .bucket(DEFAULT_BUCKET)
993 .object(objectName)
994 .build());
995 }
996 }
997
998
999
1000
1001 @Order(1050)
1002 @Test
1003 void presignedPostFormData() {
1004
1005 String objectName = UUID.randomUUID() + ".txt";
1006 MinioTemplate minio = minioTemplate("presignedPostFormData", mock ->
1007 when(mock.getPresignedPostFormData(any(PostPolicy.class)))
1008 .thenReturn(Map.of("key", "value"))
1009 );
1010
1011 PostPolicy policy = new PostPolicy(DEFAULT_BUCKET, ZonedDateTime.now().plusDays(7));
1012 policy.addEqualsCondition("key", objectName);
1013 policy.addStartsWithCondition("Content-Type", "text/");
1014 policy.addContentLengthRangeCondition(8, 8 * 1024);
1015
1016 Map<String, String> formData = minio.getPresignedPostFormData(policy);
1017 assertNotNull(formData);
1018 assertFalse(formData.isEmpty());
1019 }
1020
1021
1022
1023
1024 @Order(1060)
1025 @Test
1026 void statObject() {
1027 String objectName = UUID.randomUUID() + ".txt";
1028 byte[] value = "Hello Minio".getBytes(StandardCharsets.UTF_8);
1029 MinioTemplate minio = minioTemplate("statObject", mock -> {
1030 when(mock.putObject(any(PutObjectArgs.class)))
1031 .thenReturn(new ObjectWriteResponse(
1032 Headers.of(Collections.emptyMap()),
1033 DEFAULT_BUCKET,
1034 null,
1035 objectName,
1036 null,
1037 null
1038 ));
1039 when(mock.statObject(any(StatObjectArgs.class)))
1040 .thenReturn(new StatObjectResponse(new HeadObjectResponse(
1041 Headers.of(Map.of(
1042 "Content-Length", String.valueOf(value.length),
1043 "Last-Modified", ZonedDateTime.now().format(Time.HTTP_HEADER_DATE_FORMAT))),
1044 DEFAULT_BUCKET,
1045 null,
1046 objectName
1047 )));
1048 });
1049 ObjectWriteResponse response = minio.putObject(PutObjectArgs.builder()
1050 .bucket(DEFAULT_BUCKET)
1051 .object(objectName)
1052 .stream(new ByteArrayInputStream(value), (long) value.length, -1L)
1053 .contentType(MediaType.TEXT_PLAIN_VALUE)
1054 .build());
1055 assertNotNull(response);
1056
1057 try {
1058 StatObjectResponse statObject = minio.statObject(StatObjectArgs.builder()
1059 .bucket(DEFAULT_BUCKET)
1060 .object(objectName)
1061 .build());
1062 assertNotNull(statObject);
1063 assertEquals(objectName, statObject.object());
1064
1065 } finally {
1066 minio.removeObject(RemoveObjectArgs.builder()
1067 .bucket(DEFAULT_BUCKET)
1068 .object(objectName)
1069 .build());
1070 }
1071 }
1072
1073
1074
1075
1076 @Order(1070)
1077 @Test
1078 void objectExists() {
1079 String objectName = UUID.randomUUID() + ".txt";
1080 byte[] value = "Hello Minio".getBytes(StandardCharsets.UTF_8);
1081 MinioTemplate minio = minioTemplate("objectExists", mock -> {
1082 when(mock.putObject(any(PutObjectArgs.class)))
1083 .thenReturn(new ObjectWriteResponse(
1084 Headers.of(Collections.emptyMap()),
1085 DEFAULT_BUCKET,
1086 null,
1087 objectName,
1088 null,
1089 null
1090 ));
1091 when(mock.statObject(any(StatObjectArgs.class)))
1092 .thenReturn(new StatObjectResponse(new HeadObjectResponse(
1093 Headers.of(Map.of(
1094 "Content-Length", String.valueOf(value.length),
1095 "Last-Modified", ZonedDateTime.now().format(Time.HTTP_HEADER_DATE_FORMAT))),
1096 DEFAULT_BUCKET,
1097 null,
1098 objectName
1099 )));
1100 });
1101 ObjectWriteResponse response = minio.putObject(PutObjectArgs.builder()
1102 .bucket(DEFAULT_BUCKET)
1103 .object(objectName)
1104 .stream(new ByteArrayInputStream(value), (long) value.length, -1L)
1105 .contentType(MediaType.TEXT_PLAIN_VALUE)
1106 .build());
1107 assertNotNull(response);
1108
1109 try {
1110 assertTrue(minio.objectExists(StatObjectArgs.builder()
1111 .bucket(DEFAULT_BUCKET)
1112 .object(objectName)
1113 .build()));
1114
1115 } finally {
1116 minio.removeObject(RemoveObjectArgs.builder()
1117 .bucket(DEFAULT_BUCKET)
1118 .object(objectName)
1119 .build());
1120 }
1121 }
1122
1123
1124
1125
1126 @Order(1080)
1127 @Test
1128 void objectNotExists() {
1129 String objectName = UUID.randomUUID() + ".nil";
1130 MinioTemplate minio = minioTemplate("objectNotExists", mock ->
1131 when(mock.statObject(any(StatObjectArgs.class)))
1132 .thenThrow(new ErrorResponseException(
1133 new ErrorResponse("NoSuchKey", "message", DEFAULT_BUCKET, objectName, "123", "456",
1134 "789"),
1135 new Response.Builder()
1136 .protocol(Protocol.HTTP_1_1)
1137 .code(500)
1138 .message("Internal server error")
1139 .request(new Request.Builder()
1140 .url("https://example.org")
1141 .build())
1142 .build(),
1143 HttpStatus.NOT_FOUND.getReasonPhrase()))
1144 );
1145 assertFalse(minio.objectExists(StatObjectArgs.builder()
1146 .bucket(DEFAULT_BUCKET)
1147 .object(objectName)
1148 .build()));
1149 }
1150
1151
1152
1153
1154
1155
1156 @Order(1090)
1157 @Test
1158 void getObject() throws Exception {
1159 String objectName = UUID.randomUUID() + ".txt";
1160 byte[] value = "Hello Minio".getBytes(StandardCharsets.UTF_8);
1161 MinioTemplate minio = minioTemplate("getObject", mock -> {
1162 when(mock.putObject(any(PutObjectArgs.class)))
1163 .thenReturn(new ObjectWriteResponse(
1164 Headers.of(Collections.emptyMap()),
1165 DEFAULT_BUCKET,
1166 null,
1167 objectName,
1168 null,
1169 null
1170 ));
1171 when(mock.getObject(any(GetObjectArgs.class)))
1172 .then(invocationOnMock -> new GetObjectResponse(
1173 Headers.of(Collections.emptyMap()),
1174 DEFAULT_BUCKET,
1175 null,
1176 objectName,
1177 new ByteArrayInputStream(value)
1178 ));
1179 });
1180 ObjectWriteResponse response = minio.putObject(PutObjectArgs.builder()
1181 .bucket(DEFAULT_BUCKET)
1182 .object(objectName)
1183 .stream(new ByteArrayInputStream(value), (long) value.length, -1L)
1184 .contentType(MediaType.TEXT_PLAIN_VALUE)
1185 .build());
1186 assertNotNull(response);
1187
1188 try (InputStream in = minio.getObject(
1189 GetObjectArgs.builder().bucket(DEFAULT_BUCKET).object(objectName).build())) {
1190 byte[] readValue = FileCopyUtils.copyToByteArray(in);
1191 assertArrayEquals(value, readValue);
1192
1193 } finally {
1194 minio.removeObject(RemoveObjectArgs.builder()
1195 .bucket(DEFAULT_BUCKET)
1196 .object(objectName)
1197 .build());
1198 }
1199 }
1200
1201
1202
1203
1204
1205
1206 @Order(1100)
1207 @Test
1208 void selectObjectContent() throws Exception {
1209 when(mockClient.selectObjectContent(any(SelectObjectContentArgs.class)))
1210 .thenAnswer(invocationOnMock -> new SelectResponseStream(
1211 new ByteArrayInputStream(new byte[0])));
1212 try (SelectResponseStream stream = mockMinio.selectObjectContent(
1213 SelectObjectContentArgs.builder()
1214 .bucket(DEFAULT_BUCKET)
1215 .object(UUID.randomUUID().toString())
1216 .sqlExpression("select * from S3Object")
1217 .inputSerialization(InputSerialization.newJSON(null, JsonType.DOCUMENT))
1218 .outputSerialization(OutputSerialization.newJSON(null))
1219 .build())) {
1220 assertNotNull(stream);
1221 }
1222 }
1223
1224
1225
1226
1227
1228
1229 @Order(1110)
1230 @Test
1231 void composeObject() throws Exception {
1232
1233 String destBucket = newBucketName();
1234 String destObjectName = UUID.randomUUID() + ".txt";
1235
1236 MinioTemplate minio = minioTemplate("composeObject", mock -> {
1237 when(mock.putObject(any(PutObjectArgs.class)))
1238 .thenReturn(new ObjectWriteResponse(
1239 Headers.of(Collections.emptyMap()),
1240 DEFAULT_BUCKET,
1241 null,
1242 "any.dat",
1243 null,
1244 null
1245 ));
1246 when(mock.composeObject(any(ComposeObjectArgs.class)))
1247 .thenReturn(new ObjectWriteResponse(
1248 Headers.of(Collections.emptyMap()),
1249 destBucket,
1250 null,
1251 destObjectName,
1252 null,
1253 null
1254 ));
1255 when(mock.getPresignedObjectUrl(any(GetPresignedObjectUrlArgs.class)))
1256 .thenReturn("http://localhost/somewhere");
1257 });
1258
1259 Random random = new Random();
1260 final int size = 5242882;
1261 String objectName0 = UUID.randomUUID() + ".dat";
1262 byte[] value0 = new byte[size];
1263 random.nextBytes(value0);
1264 ObjectWriteResponse response = minio.putObject(PutObjectArgs.builder()
1265 .bucket(DEFAULT_BUCKET)
1266 .object(objectName0)
1267 .stream(new ByteArrayInputStream(value0), (long) value0.length, -1L)
1268 .contentType(MediaType.APPLICATION_OCTET_STREAM_VALUE)
1269 .build());
1270 assertNotNull(response);
1271
1272 String objectName1 = UUID.randomUUID() + ".dat";
1273 byte[] value1 = new byte[size];
1274 random.nextBytes(value1);
1275 response = minio.putObject(PutObjectArgs.builder()
1276 .bucket(DEFAULT_BUCKET)
1277 .object(objectName1)
1278 .stream(new ByteArrayInputStream(value1), (long) value1.length, -1L)
1279 .contentType(MediaType.APPLICATION_OCTET_STREAM_VALUE)
1280 .build());
1281 assertNotNull(response);
1282
1283 boolean destObjectExists = false;
1284 minio.makeBucket(MakeBucketArgs.builder().bucket(destBucket).build());
1285 try {
1286
1287 List<SourceObject> sources = new ArrayList<>(List.of(
1288 SourceObject.builder()
1289 .bucket(DEFAULT_BUCKET)
1290 .object(objectName0)
1291 .build(),
1292 SourceObject.builder()
1293 .bucket(DEFAULT_BUCKET)
1294 .object(objectName1)
1295 .build()));
1296 response = minio.composeObject(ComposeObjectArgs.builder()
1297 .bucket(destBucket)
1298 .object(destObjectName)
1299 .sources(sources)
1300 .build());
1301 assertNotNull(response);
1302 destObjectExists = true;
1303
1304 String url = minio.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
1305 .bucket(destBucket)
1306 .object(destObjectName)
1307 .method(Http.Method.GET)
1308 .expiry(3600 * 24)
1309 .build());
1310 assertNotNull(url);
1311 if (playMinioEnabled) {
1312 try (InputStream in = new URI(url).toURL().openStream()) {
1313 byte[] readBytes = FileCopyUtils.copyToByteArray(in);
1314 assertEquals(2 * size, readBytes.length);
1315 }
1316 }
1317
1318 } finally {
1319 minio.removeObject(RemoveObjectArgs.builder()
1320 .bucket(DEFAULT_BUCKET)
1321 .object(objectName0)
1322 .build());
1323 minio.removeObject(RemoveObjectArgs.builder()
1324 .bucket(DEFAULT_BUCKET)
1325 .object(objectName1)
1326 .build());
1327 if (destObjectExists) {
1328 minio.removeObject(RemoveObjectArgs.builder()
1329 .bucket(destBucket)
1330 .object(destObjectName)
1331 .build());
1332 }
1333 minio.removeBucket(RemoveBucketArgs.builder().bucket(destBucket).build());
1334 }
1335 }
1336
1337
1338
1339
1340 @Order(1120)
1341 @Test
1342 void copyObject() {
1343
1344 String objectName = UUID.randomUUID() + ".txt";
1345 String destBucket = newBucketName();
1346 String destObjectName = UUID.randomUUID() + ".txt";
1347 byte[] value = "Hello Minio".getBytes(StandardCharsets.UTF_8);
1348
1349 MinioTemplate minio = minioTemplate("copyObject", mock -> {
1350 when(mockClient.putObject(any(PutObjectArgs.class)))
1351 .thenReturn(new ObjectWriteResponse(
1352 Headers.of(Collections.emptyMap()),
1353 DEFAULT_BUCKET,
1354 null,
1355 objectName,
1356 null,
1357 "1234"
1358 ));
1359 when(mock.copyObject(any(CopyObjectArgs.class)))
1360 .thenReturn(new ObjectWriteResponse(
1361 Headers.of(Collections.emptyMap()),
1362 destBucket,
1363 null,
1364 destObjectName,
1365 null,
1366 null));
1367 when(mock.statObject(any(StatObjectArgs.class)))
1368 .thenReturn(new StatObjectResponse(new HeadObjectResponse(
1369 Headers.of(Map.of(
1370 "Content-Length", String.valueOf(value.length),
1371 "Last-Modified", ZonedDateTime.now().format(Time.HTTP_HEADER_DATE_FORMAT))),
1372 destBucket,
1373 null,
1374 destObjectName
1375 )));
1376 when(mock.removeObjects(any(RemoveObjectsArgs.class)))
1377 .thenReturn(Collections.emptyList());
1378 });
1379
1380 ObjectWriteResponse response = minio.putObject(PutObjectArgs.builder()
1381 .bucket(DEFAULT_BUCKET)
1382 .object(objectName)
1383 .stream(new ByteArrayInputStream(value), (long) value.length, -1L)
1384 .contentType(MediaType.TEXT_PLAIN_VALUE)
1385 .build());
1386 assertNotNull(response);
1387
1388 boolean destObjectExists = false;
1389 minio.makeBucket(MakeBucketArgs.builder().bucket(destBucket).build());
1390 try {
1391 ObjectWriteResponse copyResponse = minio.copyObject(CopyObjectArgs.builder()
1392 .bucket(destBucket)
1393 .object(destObjectName)
1394 .source(SourceObject.builder()
1395 .bucket(DEFAULT_BUCKET)
1396 .object(objectName)
1397 .build())
1398 .build());
1399 assertNotNull(copyResponse);
1400
1401 StatObjectResponse objectStat = minio.statObject(StatObjectArgs.builder()
1402 .bucket(destBucket)
1403 .object(destObjectName)
1404 .build());
1405 assertNotNull(objectStat);
1406 destObjectExists = true;
1407 assertEquals(value.length, (int) objectStat.size());
1408
1409 Iterable<Result<DeleteResult.Error>> errors = minio.removeObjects(RemoveObjectsArgs
1410 .builder()
1411 .bucket(destBucket)
1412 .objects(Collections.singletonList(new Object(destObjectName)))
1413 .build());
1414 boolean hasError = false;
1415 for (Result<DeleteResult.Error> error : errors) {
1416 hasError = error != null;
1417 }
1418 assertFalse(hasError);
1419
1420 if (playMinioEnabled) {
1421 StatObjectArgs statObject = StatObjectArgs.builder()
1422 .bucket(destBucket)
1423 .object(destObjectName)
1424 .build();
1425 assertThrows(MinioException.class, () -> minio.statObject(statObject));
1426 }
1427 destObjectExists = false;
1428
1429 } finally {
1430 minio.removeObject(RemoveObjectArgs.builder()
1431 .bucket(DEFAULT_BUCKET)
1432 .object(objectName)
1433 .build());
1434 if (destObjectExists) {
1435 minio.removeObject(RemoveObjectArgs.builder()
1436 .bucket(destBucket)
1437 .object(destObjectName)
1438 .build());
1439 }
1440 minio.removeBucket(RemoveBucketArgs.builder().bucket(destBucket).build());
1441 }
1442 }
1443
1444
1445
1446
1447 @Order(1130)
1448 @Test
1449 void objectRetention() {
1450 String bucket = newBucketName();
1451 String objectName = UUID.randomUUID() + ".txt";
1452 ZonedDateTime until = ZonedDateTime.now().plusSeconds(10L);
1453
1454 MinioTemplate minio = minioTemplate("objectRetention", mock -> {
1455 when(mock.putObject(any(PutObjectArgs.class)))
1456 .thenReturn(new ObjectWriteResponse(
1457 Headers.of(Collections.emptyMap()),
1458 bucket,
1459 null,
1460 objectName,
1461 null,
1462 "1234"
1463 ));
1464 when(mock.getObjectRetention(any(GetObjectRetentionArgs.class)))
1465 .thenReturn(new Retention(RetentionMode.COMPLIANCE, until));
1466 });
1467
1468 minio.makeBucket(MakeBucketArgs.builder()
1469 .bucket(bucket)
1470 .objectLock(true)
1471 .build());
1472 byte[] value = "Hello Minio".getBytes(StandardCharsets.UTF_8);
1473 ObjectWriteResponse response = minio.putObject(PutObjectArgs.builder()
1474 .bucket(bucket)
1475 .object(objectName)
1476 .stream(new ByteArrayInputStream(value), (long) value.length, -1L)
1477 .contentType(MediaType.TEXT_PLAIN_VALUE)
1478 .build());
1479 assertNotNull(response);
1480
1481 try {
1482 minio.setObjectRetention(SetObjectRetentionArgs.builder()
1483 .bucket(bucket)
1484 .object(objectName)
1485 .bypassGovernanceMode(true)
1486 .config(new Retention(RetentionMode.COMPLIANCE, until))
1487 .build());
1488
1489 Retention retention = minio.getObjectRetention(GetObjectRetentionArgs.builder()
1490 .bucket(bucket)
1491 .object(objectName)
1492 .versionId(response.versionId())
1493 .build());
1494 assertNotNull(retention);
1495 assertEquals(RetentionMode.COMPLIANCE, retention.mode());
1496 assertEquals(until.toEpochSecond(), retention.retainUntilDate().toEpochSecond());
1497
1498 if (playMinioEnabled) {
1499 await().until(() -> ZonedDateTime.now().isAfter(until));
1500 }
1501
1502 } finally {
1503 minio.removeObject(RemoveObjectArgs.builder()
1504 .bucket(bucket)
1505 .object(objectName)
1506 .versionId(response.versionId())
1507 .bypassGovernanceMode(true)
1508 .build());
1509 minio.removeBucket(RemoveBucketArgs.builder()
1510 .bucket(bucket)
1511 .build());
1512 }
1513 }
1514
1515
1516
1517
1518 @Order(1133)
1519 @Test
1520 void objectAcl() {
1521
1522 String bucket = newBucketName();
1523 String objectName = UUID.randomUUID() + ".txt";
1524
1525 Owner owner = new Owner();
1526 List<Grant> grants = List.of(
1527 new Grant(
1528 new Grantee("CanonicalUser", Type.CANONICAL_USER, null, null, null, null),
1529 Permission.FULL_CONTROL)
1530 );
1531 AccessControlList accessControlList = new AccessControlList(grants);
1532 AccessControlPolicy accessControlPolicy = new AccessControlPolicy(owner, accessControlList);
1533
1534 MinioTemplate minio = minioTemplate("objectAcl", mock -> {
1535 when(mock.putObject(any(PutObjectArgs.class)))
1536 .thenReturn(new ObjectWriteResponse(
1537 Headers.of(Collections.emptyMap()),
1538 bucket,
1539 null,
1540 objectName,
1541 null,
1542 null
1543 ));
1544 when(mock.getObjectAcl(any(GetObjectAclArgs.class)))
1545 .thenReturn(accessControlPolicy);
1546 });
1547
1548 minio.makeBucket(MakeBucketArgs.builder()
1549 .bucket(bucket)
1550 .objectLock(false)
1551 .build());
1552 byte[] value = "Hello Minio".getBytes(StandardCharsets.UTF_8);
1553 ObjectWriteResponse response = minio.putObject(PutObjectArgs.builder()
1554 .bucket(bucket)
1555 .object(objectName)
1556 .stream(new ByteArrayInputStream(value), (long) value.length, -1L)
1557 .contentType(MediaType.TEXT_PLAIN_VALUE)
1558 .build());
1559 assertNotNull(response);
1560
1561 try {
1562 GetObjectAclArgs getObjectAclArgs = GetObjectAclArgs.builder()
1563 .bucket(bucket)
1564 .object(objectName)
1565 .build();
1566 AccessControlPolicy actual = minio.getObjectAcl(getObjectAclArgs);
1567 Assertions.assertThat(actual)
1568 .usingRecursiveComparison()
1569 .isEqualTo(accessControlPolicy);
1570
1571 } finally {
1572 minio.removeObject(RemoveObjectArgs.builder()
1573 .bucket(bucket)
1574 .object(objectName)
1575 .build());
1576 minio.removeBucket(RemoveBucketArgs.builder()
1577 .bucket(bucket)
1578 .build());
1579 }
1580 }
1581
1582
1583
1584
1585 @Order(1137)
1586 @Test
1587 void objectAttributes() {
1588
1589 String bucket = newBucketName();
1590 String objectName = UUID.randomUUID() + ".txt";
1591
1592 GetObjectAttributesOutput output = mock(GetObjectAttributesOutput.class);
1593 when(output.objectSize()).thenReturn(11L);
1594 GetObjectAttributesResponse attributesResponse = mock(GetObjectAttributesResponse.class);
1595 when(attributesResponse.result()).thenReturn(output);
1596
1597 MinioTemplate minio = minioTemplate("objectAttributes", mock -> {
1598 when(mock.putObject(any(PutObjectArgs.class)))
1599 .thenReturn(new ObjectWriteResponse(
1600 Headers.of(Collections.emptyMap()),
1601 bucket,
1602 null,
1603 objectName,
1604 null,
1605 null
1606 ));
1607 when(mock.getObjectAttributes(any(GetObjectAttributesArgs.class)))
1608 .thenReturn(attributesResponse);
1609 });
1610
1611 minio.makeBucket(MakeBucketArgs.builder()
1612 .bucket(bucket)
1613 .objectLock(false)
1614 .build());
1615 byte[] value = "Hello Minio".getBytes(StandardCharsets.UTF_8);
1616 ObjectWriteResponse response = minio.putObject(PutObjectArgs.builder()
1617 .bucket(bucket)
1618 .object(objectName)
1619 .stream(new ByteArrayInputStream(value), (long) value.length, -1L)
1620 .contentType(MediaType.TEXT_PLAIN_VALUE)
1621 .build());
1622 assertNotNull(response);
1623
1624 try {
1625 GetObjectAttributesArgs getObjectAttributesArgs = GetObjectAttributesArgs.builder()
1626 .bucket(bucket)
1627 .object(objectName)
1628 .objectAttributes(List
1629 .of("ETag", "Checksum", "ObjectParts", "StorageClass", "ObjectSize"))
1630 .build();
1631 GetObjectAttributesResponse actual = minio.getObjectAttributes(getObjectAttributesArgs);
1632 assertNotNull(actual);
1633 assertNotNull(actual.result());
1634 assertEquals(11L, actual.result().objectSize());
1635
1636 } finally {
1637 minio.removeObject(RemoveObjectArgs.builder()
1638 .bucket(bucket)
1639 .object(objectName)
1640 .build());
1641 minio.removeBucket(RemoveBucketArgs.builder()
1642 .bucket(bucket)
1643 .build());
1644 }
1645 }
1646
1647
1648
1649
1650 @Order(1140)
1651 @Test
1652 void objectTags() {
1653
1654 String bucket = newBucketName();
1655 String objectName = UUID.randomUUID() + ".txt";
1656
1657 MinioTemplate minio = minioTemplate("objectTags", mock -> {
1658 when(mock.putObject(any(PutObjectArgs.class)))
1659 .thenReturn(new ObjectWriteResponse(
1660 Headers.of(Collections.emptyMap()),
1661 bucket,
1662 null,
1663 objectName,
1664 null,
1665 null
1666 ));
1667 when(mock.getObjectTags(any(GetObjectTagsArgs.class)))
1668 .thenReturn(Tags.newObjectTags(Map.of("my-key", "my-value")));
1669 });
1670
1671 minio.makeBucket(MakeBucketArgs.builder()
1672 .bucket(bucket)
1673 .objectLock(false)
1674 .build());
1675 byte[] value = "Hello Minio".getBytes(StandardCharsets.UTF_8);
1676 ObjectWriteResponse response = minio.putObject(PutObjectArgs.builder()
1677 .bucket(bucket)
1678 .object(objectName)
1679 .stream(new ByteArrayInputStream(value), (long) value.length, -1L)
1680 .contentType(MediaType.TEXT_PLAIN_VALUE)
1681 .build());
1682 assertNotNull(response);
1683 try {
1684 minio.setObjectTags(SetObjectTagsArgs.builder()
1685 .bucket(bucket)
1686 .object(objectName)
1687 .tags(Map.of("my-key", "my-value"))
1688 .build());
1689
1690 Tags tags = minio.getObjectTags(GetObjectTagsArgs.builder()
1691 .bucket(bucket)
1692 .object(objectName)
1693 .build());
1694 assertNotNull(tags);
1695 assertEquals("my-value", tags.get().get("my-key"));
1696
1697 minio.deleteObjectTags(DeleteObjectTagsArgs.builder()
1698 .bucket(bucket)
1699 .object(objectName)
1700 .build());
1701
1702 if (playMinioEnabled) {
1703 tags = minio.getObjectTags(GetObjectTagsArgs.builder()
1704 .bucket(bucket)
1705 .object(objectName)
1706 .build());
1707 assertNotNull(tags);
1708 assertTrue(tags.get().isEmpty());
1709 }
1710
1711 } finally {
1712 minio.removeObject(RemoveObjectArgs.builder()
1713 .bucket(bucket)
1714 .object(objectName)
1715 .build());
1716 minio.removeBucket(RemoveBucketArgs.builder()
1717 .bucket(bucket)
1718 .build());
1719 }
1720 }
1721
1722
1723
1724
1725 @Order(1150)
1726 @Test
1727 void objectLegalHold() {
1728 String bucket = newBucketName();
1729 String objectName = UUID.randomUUID() + ".txt";
1730
1731 MinioTemplate minio = minioTemplate("objectLegalHold", mock -> {
1732 when(mock.putObject(any(PutObjectArgs.class)))
1733 .thenReturn(new ObjectWriteResponse(
1734 Headers.of(Collections.emptyMap()),
1735 bucket,
1736 null,
1737 objectName,
1738 null,
1739 null
1740 ));
1741 when(mock.isObjectLegalHoldEnabled(any(IsObjectLegalHoldEnabledArgs.class)))
1742 .thenReturn(true);
1743 });
1744
1745 minio.makeBucket(MakeBucketArgs.builder()
1746 .bucket(bucket)
1747 .objectLock(true)
1748 .build());
1749 byte[] value = "Hello Minio".getBytes(StandardCharsets.UTF_8);
1750 ObjectWriteResponse response = minio.putObject(PutObjectArgs.builder()
1751 .bucket(bucket)
1752 .object(objectName)
1753 .stream(new ByteArrayInputStream(value), (long) value.length, -1L)
1754 .contentType(MediaType.TEXT_PLAIN_VALUE)
1755 .build());
1756 assertNotNull(response);
1757
1758 try {
1759 minio.enableObjectLegalHold(EnableObjectLegalHoldArgs.builder()
1760 .bucket(bucket)
1761 .object(objectName)
1762 .build());
1763
1764 boolean enabled = minio.isObjectLegalHoldEnabled(IsObjectLegalHoldEnabledArgs.builder()
1765 .bucket(bucket)
1766 .object(objectName)
1767 .build());
1768 assertTrue(enabled);
1769
1770 minio.disableObjectLegalHold(DisableObjectLegalHoldArgs.builder()
1771 .bucket(bucket)
1772 .object(objectName)
1773 .build());
1774
1775 } finally {
1776 minio.removeObject(RemoveObjectArgs.builder()
1777 .bucket(bucket)
1778 .object(objectName)
1779 .versionId(response.versionId())
1780 .build());
1781 minio.removeBucket(RemoveBucketArgs.builder()
1782 .bucket(bucket)
1783 .build());
1784 }
1785 }
1786
1787
1788
1789
1790 @Order(1200)
1791 @Test
1792 void promptObject() {
1793 PromptObjectResponse response = mock(PromptObjectResponse.class);
1794 MinioTemplate minio = minioMockTemplate(
1795 "promptObject",
1796 minioClient -> when(minioClient.promptObject(any(PromptObjectArgs.class)))
1797 .thenReturn(response));
1798 try (PromptObjectResponse actual = minio.promptObject(mock(PromptObjectArgs.class))) {
1799 assertEquals(response, actual);
1800 } catch (Exception e) {
1801 fail(e.getMessage());
1802 }
1803 }
1804
1805
1806
1807
1808 @Order(1210)
1809 @Test
1810 void putObjectFanOut() {
1811 PutObjectFanOutResponse response = mock(PutObjectFanOutResponse.class);
1812 MinioTemplate minio = minioMockTemplate(
1813 "putObjectFanOut",
1814 minioClient -> when(minioClient.putObjectFanOut(any(PutObjectFanOutArgs.class)))
1815 .thenReturn(response));
1816 PutObjectFanOutResponse actual = minio.putObjectFanOut(mock(PutObjectFanOutArgs.class));
1817 assertEquals(response, actual);
1818 }
1819
1820
1821
1822
1823 @Order(1220)
1824 @Test
1825 void restoreObject() {
1826 MinioTemplate minio = minioMockTemplate("restoreObject", minioClient -> {
1827 });
1828 assertDoesNotThrow(() -> minio.restoreObject(mock(RestoreObjectArgs.class)));
1829 }
1830
1831
1832
1833
1834 interface MockMinioClientConfigurator {
1835
1836
1837
1838
1839
1840
1841
1842 void configure(MinioClient minioClient) throws Exception;
1843
1844
1845
1846
1847
1848
1849 default void configureMock(MinioClient minioClient) {
1850 try {
1851 configure(minioClient);
1852
1853 } catch (Exception e) {
1854 if (e instanceof RuntimeException) {
1855 throw (RuntimeException) e;
1856 }
1857 throw new RuntimeException(e);
1858 }
1859 }
1860 }
1861 }