embulk-input-gcs 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +4 -4
- data/CHANGELOG.md +4 -0
- data/build.gradle +41 -12
- data/gradle/wrapper/gradle-wrapper.jar +0 -0
- data/gradle/wrapper/gradle-wrapper.properties +2 -2
- data/gradlew +41 -33
- data/gradlew.bat +4 -10
- data/src/main/java/org/embulk/input/gcs/AuthUtils.java +108 -0
- data/src/main/java/org/embulk/input/gcs/FileList.java +12 -9
- data/src/main/java/org/embulk/input/gcs/GcsFileInput.java +46 -126
- data/src/main/java/org/embulk/input/gcs/GcsFileInputPlugin.java +3 -38
- data/src/main/java/org/embulk/input/gcs/PluginTask.java +1 -29
- data/src/main/java/org/embulk/input/gcs/RetryUtils.java +153 -0
- data/src/main/java/org/embulk/input/gcs/SingleFileProvider.java +30 -63
- data/src/test/java/org/embulk/input/gcs/TestAuthUtils.java +153 -0
- data/src/test/java/org/embulk/input/gcs/TestGcsFileInputPlugin.java +42 -94
- data/src/test/java/org/embulk/input/gcs/TestInputStreamReopener.java +145 -0
- data/src/test/java/org/embulk/input/gcs/TestRetryUtils.java +164 -0
- data/src/test/resources/secrets.tar.enc +0 -0
- metadata +53 -28
- data/secretkeys.tar +0 -0
- data/secretkeys.tar.enc +0 -0
- data/src/main/java/org/embulk/input/gcs/GcsAuthentication.java +0 -206
- data/src/test/java/org/embulk/input/gcs/TestGcsAuthentication.java +0 -185
- data/src/test/resources/secretkeys.tar.enc +0 -0
@@ -1,23 +1,19 @@
|
|
1
1
|
package org.embulk.input.gcs;
|
2
2
|
|
3
|
-
import com.google.
|
4
|
-
import com.google.
|
5
|
-
import com.google.common.base.Throwables;
|
3
|
+
import com.google.cloud.ReadChannel;
|
4
|
+
import com.google.cloud.storage.Storage;
|
6
5
|
import org.embulk.spi.Exec;
|
7
6
|
import org.embulk.spi.util.InputStreamFileInput;
|
8
7
|
import org.embulk.spi.util.InputStreamFileInput.InputStreamWithHints;
|
9
|
-
import org.embulk.spi.util.
|
8
|
+
import org.embulk.spi.util.ResumableInputStream;
|
10
9
|
import org.slf4j.Logger;
|
11
10
|
|
12
|
-
import java.io.BufferedInputStream;
|
13
|
-
import java.io.BufferedOutputStream;
|
14
|
-
import java.io.File;
|
15
|
-
import java.io.FileInputStream;
|
16
|
-
import java.io.FileOutputStream;
|
17
11
|
import java.io.IOException;
|
12
|
+
import java.io.InputStream;
|
13
|
+
import java.nio.channels.Channels;
|
18
14
|
import java.util.Iterator;
|
19
15
|
|
20
|
-
import static
|
16
|
+
import static java.lang.String.format;
|
21
17
|
|
22
18
|
public class SingleFileProvider
|
23
19
|
implements InputStreamFileInput.Provider
|
@@ -25,20 +21,17 @@ public class SingleFileProvider
|
|
25
21
|
private final Storage client;
|
26
22
|
private final String bucket;
|
27
23
|
private final Iterator<String> iterator;
|
28
|
-
private final int maxConnectionRetry;
|
29
24
|
private boolean opened = false;
|
30
|
-
private final Logger log = Exec.getLogger(SingleFileProvider.class);
|
31
25
|
|
32
|
-
|
26
|
+
SingleFileProvider(PluginTask task, int taskIndex)
|
33
27
|
{
|
34
|
-
this.client =
|
28
|
+
this.client = AuthUtils.newClient(task);
|
35
29
|
this.bucket = task.getBucket();
|
36
30
|
this.iterator = task.getFiles().get(taskIndex).iterator();
|
37
|
-
this.maxConnectionRetry = task.getMaxConnectionRetry();
|
38
31
|
}
|
39
32
|
|
40
33
|
@Override
|
41
|
-
public InputStreamWithHints openNextWithHints()
|
34
|
+
public InputStreamWithHints openNextWithHints()
|
42
35
|
{
|
43
36
|
if (opened) {
|
44
37
|
return null;
|
@@ -48,10 +41,9 @@ public class SingleFileProvider
|
|
48
41
|
return null;
|
49
42
|
}
|
50
43
|
String key = iterator.next();
|
51
|
-
|
52
|
-
getRemoteContentsWithRetry(tempFile, client, bucket, key, maxConnectionRetry);
|
44
|
+
ReadChannel ch = client.get(bucket, key).reader();
|
53
45
|
return new InputStreamWithHints(
|
54
|
-
new
|
46
|
+
new ResumableInputStream(Channels.newInputStream(ch), new InputStreamReopener(client, bucket, key)),
|
55
47
|
String.format("gcs://%s/%s", bucket, key)
|
56
48
|
);
|
57
49
|
}
|
@@ -61,53 +53,28 @@ public class SingleFileProvider
|
|
61
53
|
{
|
62
54
|
}
|
63
55
|
|
64
|
-
|
56
|
+
static class InputStreamReopener
|
57
|
+
implements ResumableInputStream.Reopener
|
65
58
|
{
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
.withMaxRetryWait(30 * 1000)
|
71
|
-
.runInterruptible(new RetryExecutor.Retryable<Void>() {
|
72
|
-
@Override
|
73
|
-
public Void call() throws IOException
|
74
|
-
{
|
75
|
-
Storage.Objects.Get getObject = client.objects().get(bucket, key);
|
76
|
-
try (BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(tempFile))) {
|
77
|
-
IOUtils.copy(getObject.executeMediaAsInputStream(), outputStream);
|
78
|
-
}
|
79
|
-
return null;
|
80
|
-
}
|
59
|
+
private Logger logger = Exec.getLogger(getClass());
|
60
|
+
private final Storage client;
|
61
|
+
private final String bucket;
|
62
|
+
private final String key;
|
81
63
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
@Override
|
89
|
-
public void onRetry(Exception exception, int retryCount, int retryLimit, int retryWait)
|
90
|
-
throws RetryExecutor.RetryGiveupException
|
91
|
-
{
|
92
|
-
String message = String.format("GCS GET request failed. Retrying %d/%d after %d seconds. Message: %s",
|
93
|
-
retryCount, retryLimit, retryWait / 1000, exception.getMessage());
|
94
|
-
if (retryCount % 3 == 0) {
|
95
|
-
log.warn(message, exception);
|
96
|
-
}
|
97
|
-
else {
|
98
|
-
log.warn(message);
|
99
|
-
}
|
100
|
-
}
|
101
|
-
|
102
|
-
@Override
|
103
|
-
public void onGiveup(Exception firstException, Exception lastException)
|
104
|
-
throws RetryExecutor.RetryGiveupException
|
105
|
-
{
|
106
|
-
}
|
107
|
-
});
|
64
|
+
InputStreamReopener(Storage client, String bucket, String key)
|
65
|
+
{
|
66
|
+
this.client = client;
|
67
|
+
this.bucket = bucket;
|
68
|
+
this.key = key;
|
108
69
|
}
|
109
|
-
|
110
|
-
|
70
|
+
|
71
|
+
@Override
|
72
|
+
public InputStream reopen(long offset, Exception closedCause) throws IOException
|
73
|
+
{
|
74
|
+
logger.warn(format("GCS read failed. Retrying GET request with %,d bytes offset", offset), closedCause);
|
75
|
+
ReadChannel ch = client.get(bucket, key).reader();
|
76
|
+
ch.seek(offset);
|
77
|
+
return Channels.newInputStream(ch);
|
111
78
|
}
|
112
79
|
}
|
113
80
|
}
|
@@ -0,0 +1,153 @@
|
|
1
|
+
package org.embulk.input.gcs;
|
2
|
+
|
3
|
+
import com.google.auth.Credentials;
|
4
|
+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
5
|
+
import org.embulk.EmbulkTestRuntime;
|
6
|
+
import org.embulk.config.ConfigException;
|
7
|
+
import org.embulk.config.ConfigSource;
|
8
|
+
import org.embulk.spi.Exec;
|
9
|
+
import org.embulk.spi.unit.LocalFile;
|
10
|
+
import org.junit.Before;
|
11
|
+
import org.junit.BeforeClass;
|
12
|
+
import org.junit.Rule;
|
13
|
+
import org.junit.Test;
|
14
|
+
import org.mockito.Mockito;
|
15
|
+
|
16
|
+
import java.io.FileNotFoundException;
|
17
|
+
import java.io.IOException;
|
18
|
+
import java.nio.file.Path;
|
19
|
+
import java.security.GeneralSecurityException;
|
20
|
+
import java.util.Optional;
|
21
|
+
|
22
|
+
import static org.hamcrest.CoreMatchers.instanceOf;
|
23
|
+
import static org.junit.Assert.assertThat;
|
24
|
+
import static org.junit.Assume.assumeNotNull;
|
25
|
+
|
26
|
+
public class TestAuthUtils
|
27
|
+
{
|
28
|
+
private static Optional<String> GCP_EMAIL;
|
29
|
+
private static Optional<String> GCP_P12_KEYFILE;
|
30
|
+
private static Optional<String> GCP_JSON_KEYFILE;
|
31
|
+
private static String GCP_BUCKET;
|
32
|
+
private static final String GCP_APPLICATION_NAME = "embulk-input-gcs";
|
33
|
+
|
34
|
+
/*
|
35
|
+
* This test case requires environment variables
|
36
|
+
* GCP_EMAIL
|
37
|
+
* GCP_P12_KEYFILE
|
38
|
+
* GCP_JSON_KEYFILE
|
39
|
+
* GCP_BUCKET
|
40
|
+
*/
|
41
|
+
@BeforeClass
|
42
|
+
public static void initializeConstant()
|
43
|
+
{
|
44
|
+
String gcpEmail = System.getenv("GCP_EMAIL");
|
45
|
+
String gcpP12KeyFile = System.getenv("GCP_P12_KEYFILE");
|
46
|
+
String gcpJsonKeyFile = System.getenv("GCP_JSON_KEYFILE");
|
47
|
+
String gcpBucket = System.getenv("GCP_BUCKET");
|
48
|
+
|
49
|
+
// skip test cases, if environment variables are not set.
|
50
|
+
assumeNotNull(gcpEmail, gcpP12KeyFile, gcpJsonKeyFile, gcpBucket);
|
51
|
+
|
52
|
+
GCP_EMAIL = Optional.of(gcpEmail);
|
53
|
+
GCP_P12_KEYFILE = Optional.of(gcpP12KeyFile);
|
54
|
+
GCP_JSON_KEYFILE = Optional.of(gcpJsonKeyFile);
|
55
|
+
GCP_BUCKET = gcpBucket;
|
56
|
+
}
|
57
|
+
|
58
|
+
@SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
|
59
|
+
@Rule
|
60
|
+
public EmbulkTestRuntime runtime = new EmbulkTestRuntime();
|
61
|
+
private ConfigSource config;
|
62
|
+
|
63
|
+
@Before
|
64
|
+
public void setUp()
|
65
|
+
{
|
66
|
+
config = config();
|
67
|
+
}
|
68
|
+
|
69
|
+
@Test
|
70
|
+
public void testGetServiceAccountCredentialSuccess() throws IOException, GeneralSecurityException
|
71
|
+
{
|
72
|
+
PluginTask task = config.loadConfig(PluginTask.class);
|
73
|
+
assertThat(AuthUtils.fromP12(task), instanceOf(Credentials.class));
|
74
|
+
}
|
75
|
+
|
76
|
+
@Test(expected = FileNotFoundException.class)
|
77
|
+
public void testGetServiceAccountCredentialThrowFileNotFoundException()
|
78
|
+
throws IOException, GeneralSecurityException
|
79
|
+
{
|
80
|
+
Path mockNotFound = Mockito.mock(Path.class);
|
81
|
+
Mockito.when(mockNotFound.toString()).thenReturn("/path/to/notfound.p12");
|
82
|
+
LocalFile p12File = Mockito.mock(LocalFile.class);
|
83
|
+
Mockito.doReturn(mockNotFound).when(p12File).getPath();
|
84
|
+
|
85
|
+
PluginTask task = Mockito.mock(PluginTask.class);
|
86
|
+
Mockito.doReturn(Optional.of(p12File)).when(task).getP12Keyfile();
|
87
|
+
AuthUtils.fromP12(task);
|
88
|
+
}
|
89
|
+
|
90
|
+
@Test
|
91
|
+
public void testGetGcsClientUsingServiceAccountCredentialSuccess()
|
92
|
+
{
|
93
|
+
PluginTask task = config.loadConfig(PluginTask.class);
|
94
|
+
assertThat(AuthUtils.newClient(task), instanceOf(com.google.cloud.storage.Storage.class));
|
95
|
+
}
|
96
|
+
|
97
|
+
@Test(expected = ConfigException.class)
|
98
|
+
public void testGetGcsClientUsingServiceAccountCredentialThrowJsonResponseException()
|
99
|
+
{
|
100
|
+
PluginTask task = config.set("bucket", "non-exists-bucket")
|
101
|
+
.loadConfig(PluginTask.class);
|
102
|
+
AuthUtils.newClient(task);
|
103
|
+
}
|
104
|
+
|
105
|
+
@Test
|
106
|
+
public void testGetServiceAccountCredentialFromJsonFileSuccess()
|
107
|
+
throws IOException
|
108
|
+
{
|
109
|
+
PluginTask task = config.loadConfig(PluginTask.class);
|
110
|
+
assertThat(AuthUtils.fromJson(task), instanceOf(Credentials.class));
|
111
|
+
}
|
112
|
+
|
113
|
+
@Test(expected = FileNotFoundException.class)
|
114
|
+
public void testGetServiceAccountCredentialFromJsonThrowFileFileNotFoundException()
|
115
|
+
throws IOException
|
116
|
+
{
|
117
|
+
Path mockNotFound = Mockito.mock(Path.class);
|
118
|
+
Mockito.when(mockNotFound.toString()).thenReturn("/path/to/notfound.json");
|
119
|
+
LocalFile jsonFile = Mockito.mock(LocalFile.class);
|
120
|
+
Mockito.doReturn(mockNotFound).when(jsonFile).getPath();
|
121
|
+
|
122
|
+
PluginTask task = Mockito.mock(PluginTask.class);
|
123
|
+
Mockito.doReturn(Optional.of(jsonFile)).when(task).getJsonKeyfile();
|
124
|
+
AuthUtils.fromJson(task);
|
125
|
+
}
|
126
|
+
|
127
|
+
@Test
|
128
|
+
public void testGetServiceAccountCredentialFromJsonSuccess()
|
129
|
+
{
|
130
|
+
PluginTask task = config.set("auth_method", AuthUtils.AuthMethod.json_key).loadConfig(PluginTask.class);
|
131
|
+
assertThat(AuthUtils.newClient(task), instanceOf(com.google.cloud.storage.Storage.class));
|
132
|
+
}
|
133
|
+
|
134
|
+
@Test(expected = ConfigException.class)
|
135
|
+
public void testGetServiceAccountCredentialFromJsonThrowGoogleJsonResponseException()
|
136
|
+
{
|
137
|
+
PluginTask task = config.set("auth_method", AuthUtils.AuthMethod.json_key)
|
138
|
+
.set("bucket", "non-exists-bucket")
|
139
|
+
.loadConfig(PluginTask.class);
|
140
|
+
AuthUtils.newClient(task);
|
141
|
+
}
|
142
|
+
|
143
|
+
private ConfigSource config()
|
144
|
+
{
|
145
|
+
return Exec.newConfigSource()
|
146
|
+
.set("bucket", GCP_BUCKET)
|
147
|
+
.set("auth_method", "private_key")
|
148
|
+
.set("service_account_email", GCP_EMAIL)
|
149
|
+
.set("p12_keyfile", GCP_P12_KEYFILE)
|
150
|
+
.set("json_keyfile", GCP_JSON_KEYFILE)
|
151
|
+
.set("application_name", GCP_APPLICATION_NAME);
|
152
|
+
}
|
153
|
+
}
|
@@ -1,6 +1,5 @@
|
|
1
1
|
package org.embulk.input.gcs;
|
2
2
|
|
3
|
-
import com.google.api.services.storage.Storage;
|
4
3
|
import com.google.common.collect.ImmutableList;
|
5
4
|
import com.google.common.collect.ImmutableMap;
|
6
5
|
import com.google.common.collect.Lists;
|
@@ -11,7 +10,6 @@ import org.embulk.config.ConfigSource;
|
|
11
10
|
import org.embulk.config.TaskReport;
|
12
11
|
import org.embulk.config.TaskSource;
|
13
12
|
import org.embulk.spi.Exec;
|
14
|
-
import org.embulk.spi.FileInputPlugin;
|
15
13
|
import org.embulk.spi.FileInputRunner;
|
16
14
|
import org.embulk.spi.InputPlugin;
|
17
15
|
import org.embulk.spi.Schema;
|
@@ -23,20 +21,15 @@ import org.junit.BeforeClass;
|
|
23
21
|
import org.junit.Rule;
|
24
22
|
import org.junit.Test;
|
25
23
|
|
26
|
-
import java.io.IOException;
|
27
|
-
import java.security.GeneralSecurityException;
|
28
24
|
import java.util.ArrayList;
|
29
25
|
import java.util.Arrays;
|
30
26
|
import java.util.List;
|
31
27
|
import java.util.Optional;
|
32
28
|
|
33
29
|
import static org.junit.Assert.assertEquals;
|
30
|
+
import static org.junit.Assert.assertTrue;
|
34
31
|
import static org.junit.Assume.assumeNotNull;
|
35
32
|
|
36
|
-
import java.lang.reflect.InvocationTargetException;
|
37
|
-
|
38
|
-
import java.lang.reflect.Method;
|
39
|
-
|
40
33
|
public class TestGcsFileInputPlugin
|
41
34
|
{
|
42
35
|
private static Optional<String> GCP_EMAIL;
|
@@ -45,8 +38,7 @@ public class TestGcsFileInputPlugin
|
|
45
38
|
private static String GCP_BUCKET;
|
46
39
|
private static String GCP_BUCKET_DIRECTORY;
|
47
40
|
private static String GCP_PATH_PREFIX;
|
48
|
-
private static String GCP_APPLICATION_NAME;
|
49
|
-
private static int MAX_CONNECTION_RETRY = 3;
|
41
|
+
private static String GCP_APPLICATION_NAME = "embulk-input-gcs";
|
50
42
|
private FileInputRunner runner;
|
51
43
|
private MockPageOutput output;
|
52
44
|
|
@@ -83,7 +75,7 @@ public class TestGcsFileInputPlugin
|
|
83
75
|
private GcsFileInputPlugin plugin;
|
84
76
|
|
85
77
|
@Before
|
86
|
-
public void createResources()
|
78
|
+
public void createResources()
|
87
79
|
{
|
88
80
|
config = config();
|
89
81
|
plugin = new GcsFileInputPlugin();
|
@@ -99,7 +91,7 @@ public class TestGcsFileInputPlugin
|
|
99
91
|
.set("path_prefix", "my-prefix");
|
100
92
|
|
101
93
|
PluginTask task = config.loadConfig(PluginTask.class);
|
102
|
-
|
94
|
+
assertTrue(task.getIncremental());
|
103
95
|
assertEquals("private_key", task.getAuthMethod().toString());
|
104
96
|
assertEquals("Embulk GCS input plugin", task.getApplicationName());
|
105
97
|
}
|
@@ -215,22 +207,15 @@ public class TestGcsFileInputPlugin
|
|
215
207
|
|
216
208
|
@Test
|
217
209
|
public void testGcsClientCreateSuccessfully()
|
218
|
-
throws GeneralSecurityException, IOException, NoSuchMethodException,
|
219
|
-
IllegalAccessException, InvocationTargetException
|
220
210
|
{
|
221
211
|
PluginTask task = config().loadConfig(PluginTask.class);
|
222
|
-
|
223
|
-
|
224
|
-
Method method = GcsFileInputPlugin.class.getDeclaredMethod("newGcsAuth", PluginTask.class);
|
225
|
-
method.setAccessible(true);
|
226
|
-
GcsFileInput.newGcsClient(task, (GcsAuthentication) method.invoke(plugin, task)); // no errors happens
|
212
|
+
AuthUtils.newClient(task);
|
227
213
|
}
|
228
214
|
|
229
215
|
@Test(expected = ConfigException.class)
|
230
216
|
public void testGcsClientCreateThrowConfigException()
|
231
|
-
throws GeneralSecurityException, IOException, NoSuchMethodException,
|
232
|
-
IllegalAccessException, InvocationTargetException
|
233
217
|
{
|
218
|
+
// verify AuthUtils#newClient() to throws ConfigException for non-exists-bucket
|
234
219
|
ConfigSource config = Exec.newConfigSource()
|
235
220
|
.set("bucket", "non-exists-bucket")
|
236
221
|
.set("path_prefix", "my-prefix")
|
@@ -240,11 +225,7 @@ public class TestGcsFileInputPlugin
|
|
240
225
|
.set("parser", parserConfig(schemaConfig()));
|
241
226
|
|
242
227
|
PluginTask task = config.loadConfig(PluginTask.class);
|
243
|
-
|
244
|
-
|
245
|
-
Method method = GcsFileInputPlugin.class.getDeclaredMethod("newGcsAuth", PluginTask.class);
|
246
|
-
method.setAccessible(true);
|
247
|
-
GcsFileInput.newGcsClient(task, (GcsAuthentication) method.invoke(plugin, task));
|
228
|
+
AuthUtils.newClient(task);
|
248
229
|
}
|
249
230
|
|
250
231
|
@Test
|
@@ -254,14 +235,7 @@ public class TestGcsFileInputPlugin
|
|
254
235
|
FileList.Builder builder = new FileList.Builder(config);
|
255
236
|
builder.add("in/aa/a", 1);
|
256
237
|
task.setFiles(builder.build());
|
257
|
-
ConfigDiff configDiff = plugin.resume(task.dump(), 0,
|
258
|
-
{
|
259
|
-
@Override
|
260
|
-
public List<TaskReport> run(TaskSource taskSource, int taskCount)
|
261
|
-
{
|
262
|
-
return emptyTaskReports(taskCount);
|
263
|
-
}
|
264
|
-
});
|
238
|
+
ConfigDiff configDiff = plugin.resume(task.dump(), 0, (taskSource, taskCount) -> emptyTaskReports(taskCount));
|
265
239
|
assertEquals("in/aa/a", configDiff.get(String.class, "last_path"));
|
266
240
|
}
|
267
241
|
|
@@ -269,12 +243,11 @@ public class TestGcsFileInputPlugin
|
|
269
243
|
public void testCleanup()
|
270
244
|
{
|
271
245
|
PluginTask task = config.loadConfig(PluginTask.class);
|
272
|
-
plugin.cleanup(task.dump(), 0, Lists
|
246
|
+
plugin.cleanup(task.dump(), 0, Lists.newArrayList()); // no errors happens
|
273
247
|
}
|
274
248
|
|
275
249
|
@Test
|
276
250
|
public void testListFilesByPrefix()
|
277
|
-
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
|
278
251
|
{
|
279
252
|
List<String> expected = Arrays.asList(
|
280
253
|
GCP_BUCKET_DIRECTORY + "sample_01.csv",
|
@@ -282,21 +255,12 @@ public class TestGcsFileInputPlugin
|
|
282
255
|
);
|
283
256
|
|
284
257
|
PluginTask task = config.loadConfig(PluginTask.class);
|
285
|
-
ConfigDiff configDiff = plugin.transaction(config,
|
286
|
-
|
287
|
-
|
288
|
-
{
|
289
|
-
assertEquals(2, taskCount);
|
290
|
-
return emptyTaskReports(taskCount);
|
291
|
-
}
|
258
|
+
ConfigDiff configDiff = plugin.transaction(config, (taskSource, taskCount) -> {
|
259
|
+
assertEquals(2, taskCount);
|
260
|
+
return emptyTaskReports(taskCount);
|
292
261
|
});
|
293
262
|
|
294
|
-
|
295
|
-
method.setAccessible(true);
|
296
|
-
Storage client = GcsFileInput.newGcsClient(task, (GcsAuthentication) method.invoke(plugin, task));
|
297
|
-
FileList.Builder builder = new FileList.Builder(config);
|
298
|
-
GcsFileInput.listGcsFilesByPrefix(builder, client, GCP_BUCKET, GCP_PATH_PREFIX, Optional.empty());
|
299
|
-
FileList fileList = builder.build();
|
263
|
+
FileList fileList = GcsFileInput.listFiles(task);
|
300
264
|
assertEquals(expected.get(0), fileList.get(0).get(0));
|
301
265
|
assertEquals(expected.get(1), fileList.get(1).get(0));
|
302
266
|
assertEquals(GCP_BUCKET_DIRECTORY + "sample_02.csv", configDiff.get(String.class, "last_path"));
|
@@ -304,7 +268,6 @@ public class TestGcsFileInputPlugin
|
|
304
268
|
|
305
269
|
@Test
|
306
270
|
public void testListFilesByPrefixWithPattern()
|
307
|
-
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
|
308
271
|
{
|
309
272
|
List<String> expected = Arrays.asList(
|
310
273
|
GCP_BUCKET_DIRECTORY + "sample_01.csv"
|
@@ -312,27 +275,18 @@ public class TestGcsFileInputPlugin
|
|
312
275
|
|
313
276
|
ConfigSource configWithPattern = config.deepCopy().set("path_match_pattern", "1");
|
314
277
|
PluginTask task = configWithPattern.loadConfig(PluginTask.class);
|
315
|
-
ConfigDiff configDiff = plugin.transaction(configWithPattern,
|
316
|
-
|
317
|
-
|
318
|
-
{
|
319
|
-
assertEquals(1, taskCount);
|
320
|
-
return emptyTaskReports(taskCount);
|
321
|
-
}
|
278
|
+
ConfigDiff configDiff = plugin.transaction(configWithPattern, (taskSource, taskCount) -> {
|
279
|
+
assertEquals(1, taskCount);
|
280
|
+
return emptyTaskReports(taskCount);
|
322
281
|
});
|
323
282
|
|
324
|
-
|
325
|
-
method.setAccessible(true);
|
326
|
-
Storage client = GcsFileInput.newGcsClient(task, (GcsAuthentication) method.invoke(plugin, task));
|
327
|
-
FileList.Builder builder = new FileList.Builder(configWithPattern);
|
328
|
-
GcsFileInput.listGcsFilesByPrefix(builder, client, GCP_BUCKET, GCP_PATH_PREFIX, Optional.empty());
|
329
|
-
FileList fileList = builder.build();
|
283
|
+
FileList fileList = GcsFileInput.listFiles(task);
|
330
284
|
assertEquals(expected.get(0), fileList.get(0).get(0));
|
331
285
|
assertEquals(GCP_BUCKET_DIRECTORY + "sample_01.csv", configDiff.get(String.class, "last_path"));
|
332
286
|
}
|
333
287
|
|
334
288
|
@Test
|
335
|
-
public void testListFilesByPrefixIncrementalFalse()
|
289
|
+
public void testListFilesByPrefixIncrementalFalse()
|
336
290
|
{
|
337
291
|
ConfigSource config = config().deepCopy()
|
338
292
|
.set("incremental", false);
|
@@ -342,22 +296,22 @@ public class TestGcsFileInputPlugin
|
|
342
296
|
assertEquals("{}", configDiff.toString());
|
343
297
|
}
|
344
298
|
|
345
|
-
@Test
|
299
|
+
@Test(expected = ConfigException.class)
|
346
300
|
public void testListFilesByPrefixNonExistsBucket()
|
347
|
-
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
|
348
301
|
{
|
349
|
-
PluginTask task = config
|
302
|
+
PluginTask task = config
|
303
|
+
.set("bucket", "non-exists-bucket")
|
304
|
+
.set("path_prefix", "prefix")
|
305
|
+
.loadConfig(PluginTask.class);
|
350
306
|
runner.transaction(config, new Control());
|
351
307
|
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
FileList.Builder builder = new FileList.Builder(config);
|
356
|
-
GcsFileInput.listGcsFilesByPrefix(builder, client, "non-exists-bucket", "prefix", Optional.empty()); // no errors happens
|
308
|
+
// after refactoring, GcsFileInput#listFiles() won't accept initialized client
|
309
|
+
// hence, this test will throw ConfigException
|
310
|
+
GcsFileInput.listFiles(task);
|
357
311
|
}
|
358
312
|
|
359
313
|
@Test
|
360
|
-
public void testNonExistingFilesWithPathPrefix()
|
314
|
+
public void testNonExistingFilesWithPathPrefix()
|
361
315
|
{
|
362
316
|
ConfigSource config = Exec.newConfigSource()
|
363
317
|
.set("bucket", GCP_BUCKET)
|
@@ -394,7 +348,6 @@ public class TestGcsFileInputPlugin
|
|
394
348
|
|
395
349
|
@Test
|
396
350
|
public void testGcsFileInputByOpen()
|
397
|
-
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, IOException
|
398
351
|
{
|
399
352
|
ConfigSource config = Exec.newConfigSource()
|
400
353
|
.set("bucket", GCP_BUCKET)
|
@@ -407,31 +360,24 @@ public class TestGcsFileInputPlugin
|
|
407
360
|
PluginTask task = config.loadConfig(PluginTask.class);
|
408
361
|
runner.transaction(config, new Control());
|
409
362
|
|
410
|
-
|
411
|
-
method.setAccessible(true);
|
412
|
-
Storage client = GcsFileInput.newGcsClient(task, (GcsAuthentication) method.invoke(plugin, task));
|
413
|
-
task.setFiles(GcsFileInput.listFiles(task, client));
|
363
|
+
task.setFiles(GcsFileInput.listFiles(task));
|
414
364
|
|
415
365
|
assertRecords(config, output);
|
416
366
|
}
|
417
367
|
|
418
368
|
@Test
|
419
369
|
public void testBase64()
|
420
|
-
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
|
421
370
|
{
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
assertEquals("
|
426
|
-
assertEquals("CgJjMg==", method.invoke(plugin, "c2"));
|
427
|
-
assertEquals("Cgh0ZXN0LmNzdg==", method.invoke(plugin, "test.csv"));
|
428
|
-
assertEquals("ChZnY3MtdGVzdC9zYW1wbGVfMDEuY3N2", method.invoke(plugin, "gcs-test/sample_01.csv"));
|
371
|
+
assertEquals("CgFj", GcsFileInput.base64Encode("c"));
|
372
|
+
assertEquals("CgJjMg==", GcsFileInput.base64Encode("c2"));
|
373
|
+
assertEquals("Cgh0ZXN0LmNzdg==", GcsFileInput.base64Encode("test.csv"));
|
374
|
+
assertEquals("ChZnY3MtdGVzdC9zYW1wbGVfMDEuY3N2", GcsFileInput.base64Encode("gcs-test/sample_01.csv"));
|
429
375
|
String params = "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc127";
|
430
376
|
String expected = "Cn9jY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjMTI3";
|
431
|
-
assertEquals(expected,
|
377
|
+
assertEquals(expected, GcsFileInput.base64Encode(params));
|
432
378
|
}
|
433
379
|
|
434
|
-
|
380
|
+
private ConfigSource config()
|
435
381
|
{
|
436
382
|
return Exec.newConfigSource()
|
437
383
|
.set("bucket", GCP_BUCKET)
|
@@ -444,7 +390,7 @@ public class TestGcsFileInputPlugin
|
|
444
390
|
.set("parser", parserConfig(schemaConfig()));
|
445
391
|
}
|
446
392
|
|
447
|
-
static List<TaskReport> emptyTaskReports(int taskCount)
|
393
|
+
private static List<TaskReport> emptyTaskReports(int taskCount)
|
448
394
|
{
|
449
395
|
ImmutableList.Builder<TaskReport> reports = new ImmutableList.Builder<>();
|
450
396
|
for (int i = 0; i < taskCount; i++) {
|
@@ -525,11 +471,13 @@ public class TestGcsFileInputPlugin
|
|
525
471
|
|
526
472
|
private static String getDirectory(String dir)
|
527
473
|
{
|
528
|
-
if (dir != null
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
474
|
+
if (dir != null) {
|
475
|
+
if (!dir.endsWith("/")) {
|
476
|
+
dir = dir + "/";
|
477
|
+
}
|
478
|
+
if (dir.startsWith("/")) {
|
479
|
+
dir = dir.replaceFirst("/", "");
|
480
|
+
}
|
533
481
|
}
|
534
482
|
return dir;
|
535
483
|
}
|