Skip to content

Commit b4c7d04

Browse files
authored
Merge pull request data-integrations#1359 from data-integrations/fix/plugin-1738
[PLUGIN-1738] Fix bucket creation issue for GCS Copy/Move Plugins
2 parents 1c03c8b + 808ef94 commit b4c7d04

File tree

2 files changed

+89
-8
lines changed

2 files changed

+89
-8
lines changed

src/main/java/io/cdap/plugin/gcp/gcs/StorageClient.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,20 @@ public void mapMetaDataForAllBlobs(String path, Consumer<Map<String, String>> fu
115115
* @param cmekKeyName the name of the cmek key
116116
*/
117117
public void createBucketIfNotExists(GCSPath path, @Nullable String location, @Nullable CryptoKeyName cmekKeyName) {
118-
Bucket bucket = null;
119118
try {
120-
bucket = storage.get(path.getBucket());
121-
} catch (StorageException e) {
122-
throw new RuntimeException(
123-
String.format("Unable to access bucket %s. ", path.getBucket())
124-
+ "Ensure you entered the correct bucket path and have permissions for it.", e);
125-
}
126-
if (bucket == null) {
127119
GCPUtils.createBucket(storage, path.getBucket(), location, cmekKeyName);
120+
LOG.info("Bucket {} has been created successfully", path.getBucket());
121+
} catch (StorageException e) {
122+
// Don't throw error if bucket already exists
123+
// https://cloud.google.com/storage/docs/json_api/v1/status-codes#409_Conflict
124+
if (e.getCode() == 409) {
125+
LOG.warn("Getting 409 Conflict: {} Bucket at destination path {} may already exist.",
126+
e.getMessage(), path.getUri());
127+
} else {
128+
throw new RuntimeException(
129+
String.format("Unable to create bucket %s. Ensure you entered the correct bucket path and " +
130+
"have permissions for it.", path.getBucket()), e);
131+
}
128132
}
129133
}
130134

src/test/java/io/cdap/plugin/gcp/gcs/StorageClientTest.java

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,52 @@
1717
package io.cdap.plugin.gcp.gcs;
1818

1919
import com.google.cloud.storage.BlobId;
20+
import com.google.cloud.storage.BucketInfo;
21+
import com.google.cloud.storage.Storage;
22+
import com.google.cloud.storage.StorageException;
23+
import org.junit.After;
2024
import org.junit.Assert;
25+
import org.junit.Before;
2126
import org.junit.Test;
27+
import org.mockito.Mock;
28+
import org.mockito.MockitoAnnotations;
29+
import org.slf4j.Logger;
30+
31+
import java.io.ByteArrayOutputStream;
32+
import java.io.PrintStream;
33+
34+
import static org.mockito.Mockito.any;
35+
import static org.mockito.Mockito.times;
36+
import static org.mockito.Mockito.verify;
37+
import static org.mockito.Mockito.when;
38+
2239

2340
/**
2441
* Tests for storage client
2542
*/
2643
public class StorageClientTest {
2744

45+
@Mock
46+
private Storage storage;
47+
48+
private StorageClient storageClient;
49+
50+
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
51+
52+
private final PrintStream originalOut = System.out;
53+
54+
@Before
55+
public void setUp() {
56+
MockitoAnnotations.initMocks(this);
57+
storageClient = new StorageClient(storage);
58+
System.setOut(new PrintStream(outContent));
59+
}
60+
61+
@After
62+
public void restoreStreams() {
63+
System.setOut(originalOut);
64+
}
65+
2866
@Test
2967
public void testAppend() {
3068
Assert.assertEquals("a/b/c", StorageClient.append("a/", "/b/c"));
@@ -67,4 +105,43 @@ public void testNonExistingDestinationEndingSlash() {
67105
Assert.assertEquals(BlobId.of("b0", "subdir/dir2/a/b/c"),
68106
StorageClient.resolve("dir1/dir2", "dir1/dir2/a/b/c", GCSPath.from("b0/subdir/"), false));
69107
}
108+
109+
@Test
110+
public void testCreateBucketIfNotExists() {
111+
// Test successful bucket creation
112+
GCSPath path = GCSPath.from("my-bucket");
113+
storageClient.createBucketIfNotExists(path, "us", null);
114+
// No exception is thrown and method storage.create() is invoked once
115+
verify(storage, times(1)).create(any(BucketInfo.class));
116+
117+
// Test bucket already exists
118+
GCSPath existingPath = GCSPath.from("existing-bucket");
119+
120+
when(storage.create(any(BucketInfo.class))).thenThrow(new StorageException(409, "Conflict"));
121+
122+
storageClient.createBucketIfNotExists(existingPath, "existing-location", null);
123+
// The exception thrown should be caught and warning log should be printed
124+
Assert.assertTrue(outContent.toString().contains("Getting 409 Conflict"));
125+
// The method storage.create() is invoked 2 times in total
126+
verify(storage, times(2)).create(any(BucketInfo.class));
127+
128+
// Test bucket creation failure
129+
GCSPath failurePath = GCSPath.from("failed-bucket");
130+
131+
when(storage.create(any(BucketInfo.class))).thenThrow(new StorageException(500, "Internal Server Error"));
132+
133+
try {
134+
storageClient.createBucketIfNotExists(failurePath, "failed-location", null);
135+
} catch (Exception e) {
136+
// Verify that RuntimeException is caught
137+
if (!(e instanceof RuntimeException)) {
138+
Assert.fail(String.format("Test for detecting bucket creation failure did not succeed. " +
139+
"Unexpected Exception caught: %s", e));
140+
}
141+
// The method storage.create() is invoked 3 times in total
142+
verify(storage, times(3)).create(any(BucketInfo.class));
143+
return;
144+
}
145+
Assert.fail("Test for detecting bucket creation failure did not succeed. No exception caught");
146+
}
70147
}

0 commit comments

Comments
 (0)