embulk-input-gcs 0.1.7 → 0.1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ChangeLog +4 -0
- data/README.md +50 -1
- data/build.gradle +7 -4
- data/classpath/embulk-input-gcs-0.1.8.jar +0 -0
- data/src/main/java/org/embulk/input/gcs/GcsFileInputPlugin.java +40 -43
- data/src/test/java/org/embulk/input/gcs/TestGcsAuthentication.java +177 -0
- data/src/test/java/org/embulk/input/gcs/TestGcsFileInputPlugin.java +349 -3
- data/src/test/resources/sample_01.csv +5 -0
- data/src/test/resources/sample_02.csv +5 -0
- metadata +6 -3
- data/classpath/embulk-input-gcs-0.1.7.jar +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 219d292e87e6a2b326144302280e10bba7e3ea2a
|
4
|
+
data.tar.gz: c7e6e1933bc1961e16f18c68022261e1948cd5bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e09e566db719125bc872a33026c4dd15bb1b29bf3ad82ce75a5cdd1fc5c342e2c8c72179accd3b9fafecf8ca3945dd26c0e1cdc70036d3a82d509485c388e925
|
7
|
+
data.tar.gz: aa068f8ac05d9fafec71baa24d71f18b59096521277ce836a5b27c1f1c491d4aee8ffe004d71117d5d6d68482e6525071fbcb2da4f3ca30601c638582cf7d260
|
data/ChangeLog
CHANGED
data/README.md
CHANGED
@@ -136,7 +136,7 @@ in:
|
|
136
136
|
|
137
137
|
On the other hand, you don't need to explicitly create a service account for embulk when you
|
138
138
|
run embulk in Google Compute Engine. In this third authentication method, you need to
|
139
|
-
add the API scope "https://www.googleapis.com/auth/
|
139
|
+
add the API scope "https://www.googleapis.com/auth/devstorage.read_only" to the scope list of your
|
140
140
|
Compute Engine VM instance, then you can configure embulk like this.
|
141
141
|
|
142
142
|
[Setting the scope of service account access for instances](https://cloud.google.com/compute/docs/authentication)
|
@@ -153,3 +153,52 @@ in:
|
|
153
153
|
./gradlew gem
|
154
154
|
```
|
155
155
|
|
156
|
+
## Test
|
157
|
+
|
158
|
+
To run unit tests, we need to configure the following environment variables.
|
159
|
+
|
160
|
+
Additionally, following files will be needed to upload to existing GCS bucket.
|
161
|
+
* [sample_01.csv](./src/test/resources/sample_01.csv)
|
162
|
+
* [sample_02.csv](./src/test/resources/sample_02.csv)
|
163
|
+
|
164
|
+
When environment variables are not set, skip some test cases.
|
165
|
+
|
166
|
+
```
|
167
|
+
GCP_EMAIL
|
168
|
+
GCP_P12_KEYFILE
|
169
|
+
GCP_JSON_KEYFILE
|
170
|
+
GCP_BUCKET
|
171
|
+
GCP_BUCKET_DIRECTORY(optional, if needed)
|
172
|
+
```
|
173
|
+
|
174
|
+
If you're using Mac OS X El Capitan and GUI Applications(IDE), like as follows.
|
175
|
+
```
|
176
|
+
$ vi ~/Library/LaunchAgents/environment.plist
|
177
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
178
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
179
|
+
<plist version="1.0">
|
180
|
+
<dict>
|
181
|
+
<key>Label</key>
|
182
|
+
<string>my.startup</string>
|
183
|
+
<key>ProgramArguments</key>
|
184
|
+
<array>
|
185
|
+
<string>sh</string>
|
186
|
+
<string>-c</string>
|
187
|
+
<string>
|
188
|
+
launchctl setenv GCP_EMAIL ABCXYZ123ABCXYZ123.gserviceaccount.com
|
189
|
+
launchctl setenv GCP_P12_KEYFILE /path/to/p12_keyfile.p12
|
190
|
+
launchctl setenv GCP_JSON_KEYFILE /path/to/json_keyfile.json
|
191
|
+
launchctl setenv GCP_BUCKET my-bucket
|
192
|
+
launchctl setenv GCP_BUCKET_DIRECTORY unittests
|
193
|
+
</string>
|
194
|
+
</array>
|
195
|
+
<key>RunAtLoad</key>
|
196
|
+
<true/>
|
197
|
+
</dict>
|
198
|
+
</plist>
|
199
|
+
|
200
|
+
$ launchctl load ~/Library/LaunchAgents/environment.plist
|
201
|
+
$ launchctl getenv GCP_EMAIL //try to get value.
|
202
|
+
|
203
|
+
Then start your applications.
|
204
|
+
```
|
data/build.gradle
CHANGED
@@ -2,6 +2,7 @@ plugins {
|
|
2
2
|
id "com.jfrog.bintray" version "1.1"
|
3
3
|
id "com.github.jruby-gradle.base" version "0.1.5"
|
4
4
|
id "java"
|
5
|
+
id "jacoco"
|
5
6
|
}
|
6
7
|
import com.github.jrubygradle.JRubyExec
|
7
8
|
repositories {
|
@@ -15,16 +16,18 @@ configurations {
|
|
15
16
|
sourceCompatibility = 1.7
|
16
17
|
targetCompatibility = 1.7
|
17
18
|
|
18
|
-
version = "0.1.
|
19
|
+
version = "0.1.8"
|
19
20
|
|
20
21
|
dependencies {
|
21
|
-
compile "org.embulk:embulk-core:0.7.
|
22
|
-
provided "org.embulk:embulk-core:0.7.
|
22
|
+
compile "org.embulk:embulk-core:0.7.5"
|
23
|
+
provided "org.embulk:embulk-core:0.7.5"
|
23
24
|
|
24
25
|
compile "com.google.http-client:google-http-client-jackson2:1.19.0"
|
25
26
|
compile ("com.google.apis:google-api-services-storage:v1-rev27-1.19.1") {exclude module: "guava-jdk5"}
|
26
27
|
|
27
|
-
testCompile "junit:junit:4
|
28
|
+
testCompile "junit:junit:4.12"
|
29
|
+
testCompile "org.embulk:embulk-core:0.7.5:tests"
|
30
|
+
testCompile "org.embulk:embulk-standards:0.7.5"
|
28
31
|
}
|
29
32
|
|
30
33
|
task classpath(type: Copy, dependsOn: ["jar"]) {
|
Binary file
|
@@ -165,7 +165,7 @@ public class GcsFileInputPlugin
|
|
165
165
|
{
|
166
166
|
}
|
167
167
|
|
168
|
-
|
168
|
+
protected Storage newGcsClient(final PluginTask task)
|
169
169
|
{
|
170
170
|
Storage client = null;
|
171
171
|
try {
|
@@ -213,12 +213,11 @@ public class GcsFileInputPlugin
|
|
213
213
|
Storage.Buckets.Get getBucket = client.buckets().get(bucket);
|
214
214
|
getBucket.setProjection("full");
|
215
215
|
Bucket bk = getBucket.execute();
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
}
|
216
|
+
|
217
|
+
log.debug("bucket name: " + bucket);
|
218
|
+
log.debug("bucket location: " + bk.getLocation());
|
219
|
+
log.debug("bucket timeCreated: " + bk.getTimeCreated());
|
220
|
+
log.debug("bucket owner: " + bk.getOwner());
|
222
221
|
} catch (IOException e) {
|
223
222
|
log.warn("Could not access to bucket:" + bucket);
|
224
223
|
log.warn(e.getMessage());
|
@@ -238,13 +237,11 @@ public class GcsFileInputPlugin
|
|
238
237
|
break;
|
239
238
|
}
|
240
239
|
for (StorageObject o : items) {
|
241
|
-
if (log.isDebugEnabled()) {
|
242
|
-
log.debug("filename: " + o.getName());
|
243
|
-
log.debug("updated: " + o.getUpdated());
|
244
|
-
}
|
245
240
|
if (o.getSize().compareTo(BigInteger.ZERO) > 0) {
|
246
241
|
builder.add(o.getName());
|
247
242
|
}
|
243
|
+
log.debug("filename: " + o.getName());
|
244
|
+
log.debug("updated: " + o.getUpdated());
|
248
245
|
}
|
249
246
|
lastKey = objects.getNextPageToken();
|
250
247
|
listObjects.setPageToken(lastKey);
|
@@ -264,41 +261,10 @@ public class GcsFileInputPlugin
|
|
264
261
|
return new GcsFileInput(task, taskIndex);
|
265
262
|
}
|
266
263
|
|
267
|
-
public
|
264
|
+
public class GcsFileInput
|
268
265
|
extends InputStreamFileInput
|
269
266
|
implements TransactionalFileInput
|
270
267
|
{
|
271
|
-
private static class SingleFileProvider
|
272
|
-
implements InputStreamFileInput.Provider
|
273
|
-
{
|
274
|
-
private final Storage client;
|
275
|
-
private final String bucket;
|
276
|
-
private final String key;
|
277
|
-
private boolean opened = false;
|
278
|
-
|
279
|
-
public SingleFileProvider(PluginTask task, int taskIndex)
|
280
|
-
{
|
281
|
-
this.client = newGcsClient(task);
|
282
|
-
this.bucket = task.getBucket();
|
283
|
-
this.key = task.getFiles().get(taskIndex);
|
284
|
-
}
|
285
|
-
|
286
|
-
@Override
|
287
|
-
public InputStream openNext() throws IOException
|
288
|
-
{
|
289
|
-
if (opened) {
|
290
|
-
return null;
|
291
|
-
}
|
292
|
-
opened = true;
|
293
|
-
Storage.Objects.Get getObject = client.objects().get(bucket, key);
|
294
|
-
|
295
|
-
return getObject.executeMediaAsInputStream();
|
296
|
-
}
|
297
|
-
|
298
|
-
@Override
|
299
|
-
public void close() { }
|
300
|
-
}
|
301
|
-
|
302
268
|
public GcsFileInput(PluginTask task, int taskIndex)
|
303
269
|
{
|
304
270
|
super(task.getBufferAllocator(), new SingleFileProvider(task, taskIndex));
|
@@ -315,6 +281,37 @@ public class GcsFileInputPlugin
|
|
315
281
|
public void close() { }
|
316
282
|
}
|
317
283
|
|
284
|
+
private class SingleFileProvider
|
285
|
+
implements InputStreamFileInput.Provider
|
286
|
+
{
|
287
|
+
private final Storage client;
|
288
|
+
private final String bucket;
|
289
|
+
private final String key;
|
290
|
+
private boolean opened = false;
|
291
|
+
|
292
|
+
public SingleFileProvider(PluginTask task, int taskIndex)
|
293
|
+
{
|
294
|
+
this.client = newGcsClient(task);
|
295
|
+
this.bucket = task.getBucket();
|
296
|
+
this.key = task.getFiles().get(taskIndex);
|
297
|
+
}
|
298
|
+
|
299
|
+
@Override
|
300
|
+
public InputStream openNext() throws IOException
|
301
|
+
{
|
302
|
+
if (opened) {
|
303
|
+
return null;
|
304
|
+
}
|
305
|
+
opened = true;
|
306
|
+
Storage.Objects.Get getObject = client.objects().get(bucket, key);
|
307
|
+
|
308
|
+
return getObject.executeMediaAsInputStream();
|
309
|
+
}
|
310
|
+
|
311
|
+
@Override
|
312
|
+
public void close() { }
|
313
|
+
}
|
314
|
+
|
318
315
|
public enum AuthMethod
|
319
316
|
{
|
320
317
|
private_key("private_key"),
|
@@ -0,0 +1,177 @@
|
|
1
|
+
package org.embulk.input.gcs;
|
2
|
+
|
3
|
+
import com.google.common.base.Optional;
|
4
|
+
import org.embulk.EmbulkTestRuntime;
|
5
|
+
import com.google.api.services.storage.Storage;
|
6
|
+
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
|
7
|
+
|
8
|
+
import java.io.IOException;
|
9
|
+
import java.io.FileNotFoundException;
|
10
|
+
import java.security.GeneralSecurityException;
|
11
|
+
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
|
12
|
+
|
13
|
+
import java.lang.reflect.Field;
|
14
|
+
import org.junit.BeforeClass;
|
15
|
+
import org.junit.Rule;
|
16
|
+
import org.junit.Test;
|
17
|
+
import static org.junit.Assert.assertEquals;
|
18
|
+
import static org.junit.Assume.assumeNotNull;
|
19
|
+
|
20
|
+
public class TestGcsAuthentication
|
21
|
+
{
|
22
|
+
private static Optional<String> GCP_EMAIL;
|
23
|
+
private static Optional<String> GCP_P12_KEYFILE;
|
24
|
+
private static Optional<String> GCP_JSON_KEYFILE;
|
25
|
+
private static String GCP_BUCKET;
|
26
|
+
private static final String GCP_APPLICATION_NAME = "embulk-input-gcs";
|
27
|
+
|
28
|
+
/*
|
29
|
+
* This test case requires environment variables
|
30
|
+
* GCP_EMAIL
|
31
|
+
* GCP_P12_KEYFILE
|
32
|
+
* GCP_JSON_KEYFILE
|
33
|
+
* GCP_BUCKET
|
34
|
+
*/
|
35
|
+
@BeforeClass
|
36
|
+
public static void initializeConstant()
|
37
|
+
{
|
38
|
+
GCP_EMAIL = Optional.of(System.getenv("GCP_EMAIL"));
|
39
|
+
GCP_P12_KEYFILE = Optional.of(System.getenv("GCP_P12_KEYFILE"));
|
40
|
+
GCP_JSON_KEYFILE = Optional.of(System.getenv("GCP_JSON_KEYFILE"));
|
41
|
+
GCP_BUCKET = System.getenv("GCP_BUCKET");
|
42
|
+
// skip test cases, if environment variables are not set.
|
43
|
+
assumeNotNull(GCP_EMAIL, GCP_P12_KEYFILE, GCP_JSON_KEYFILE, GCP_BUCKET);
|
44
|
+
}
|
45
|
+
|
46
|
+
@Rule
|
47
|
+
public EmbulkTestRuntime runtime = new EmbulkTestRuntime();
|
48
|
+
|
49
|
+
@Test
|
50
|
+
public void testGetServiceAccountCredentialSuccess()
|
51
|
+
throws NoSuchFieldException, IllegalAccessException, GeneralSecurityException, IOException
|
52
|
+
{
|
53
|
+
GcsAuthentication auth = new GcsAuthentication(
|
54
|
+
"private_key",
|
55
|
+
GCP_EMAIL,
|
56
|
+
GCP_P12_KEYFILE,
|
57
|
+
null,
|
58
|
+
GCP_APPLICATION_NAME
|
59
|
+
);
|
60
|
+
|
61
|
+
Field field = GcsAuthentication.class.getDeclaredField("credentials");
|
62
|
+
field.setAccessible(true);
|
63
|
+
|
64
|
+
assertEquals(GoogleCredential.class, field.get(auth).getClass());
|
65
|
+
}
|
66
|
+
|
67
|
+
@Test(expected = FileNotFoundException.class)
|
68
|
+
public void testGetServiceAccountCredentialThrowFileNotFoundException()
|
69
|
+
throws GeneralSecurityException, IOException
|
70
|
+
{
|
71
|
+
Optional<String> notFoundP12Keyfile = Optional.of("/path/to/notfound.p12");
|
72
|
+
GcsAuthentication auth = new GcsAuthentication(
|
73
|
+
"private_key",
|
74
|
+
GCP_EMAIL,
|
75
|
+
notFoundP12Keyfile,
|
76
|
+
null,
|
77
|
+
GCP_APPLICATION_NAME
|
78
|
+
);
|
79
|
+
}
|
80
|
+
|
81
|
+
@Test
|
82
|
+
public void testGetGcsClientUsingServiceAccountCredentialSuccess()
|
83
|
+
throws NoSuchFieldException, IllegalAccessException, GeneralSecurityException, IOException
|
84
|
+
{
|
85
|
+
GcsAuthentication auth = new GcsAuthentication(
|
86
|
+
"private_key",
|
87
|
+
GCP_EMAIL,
|
88
|
+
GCP_P12_KEYFILE,
|
89
|
+
null,
|
90
|
+
GCP_APPLICATION_NAME
|
91
|
+
);
|
92
|
+
|
93
|
+
Storage client = auth.getGcsClient(GCP_BUCKET);
|
94
|
+
|
95
|
+
assertEquals(Storage.class, client.getClass());
|
96
|
+
}
|
97
|
+
|
98
|
+
@Test(expected = GoogleJsonResponseException.class)
|
99
|
+
public void testGetGcsClientUsingServiceAccountCredentialThrowJsonResponseException()
|
100
|
+
throws NoSuchFieldException, IllegalAccessException, GeneralSecurityException, IOException
|
101
|
+
{
|
102
|
+
GcsAuthentication auth = new GcsAuthentication(
|
103
|
+
"private_key",
|
104
|
+
GCP_EMAIL,
|
105
|
+
GCP_P12_KEYFILE,
|
106
|
+
null,
|
107
|
+
GCP_APPLICATION_NAME
|
108
|
+
);
|
109
|
+
|
110
|
+
Storage client = auth.getGcsClient("non-exists-bucket");
|
111
|
+
|
112
|
+
assertEquals(Storage.class, client.getClass());
|
113
|
+
}
|
114
|
+
|
115
|
+
@Test
|
116
|
+
public void testGetServiceAccountCredentialFromJsonFileSuccess()
|
117
|
+
throws NoSuchFieldException, IllegalAccessException, GeneralSecurityException, IOException
|
118
|
+
{
|
119
|
+
GcsAuthentication auth = new GcsAuthentication(
|
120
|
+
"json_key",
|
121
|
+
GCP_EMAIL,
|
122
|
+
null,
|
123
|
+
GCP_JSON_KEYFILE,
|
124
|
+
GCP_APPLICATION_NAME
|
125
|
+
);
|
126
|
+
Field field = GcsAuthentication.class.getDeclaredField("credentials");
|
127
|
+
field.setAccessible(true);
|
128
|
+
|
129
|
+
assertEquals(GoogleCredential.class, field.get(auth).getClass());
|
130
|
+
}
|
131
|
+
|
132
|
+
@Test(expected = FileNotFoundException.class)
|
133
|
+
public void testGetServiceAccountCredentialFromJsonThrowFileFileNotFoundException()
|
134
|
+
throws GeneralSecurityException, IOException
|
135
|
+
{
|
136
|
+
Optional<String> notFoundJsonKeyfile = Optional.of("/path/to/notfound.json");
|
137
|
+
GcsAuthentication auth = new GcsAuthentication(
|
138
|
+
"json_key",
|
139
|
+
GCP_EMAIL,
|
140
|
+
null,
|
141
|
+
notFoundJsonKeyfile,
|
142
|
+
GCP_APPLICATION_NAME
|
143
|
+
);
|
144
|
+
}
|
145
|
+
|
146
|
+
@Test
|
147
|
+
public void testGetServiceAccountCredentialFromJsonSuccess()
|
148
|
+
throws NoSuchFieldException, IllegalAccessException, GeneralSecurityException, IOException
|
149
|
+
{
|
150
|
+
GcsAuthentication auth = new GcsAuthentication(
|
151
|
+
"json_key",
|
152
|
+
GCP_EMAIL,
|
153
|
+
null,
|
154
|
+
GCP_JSON_KEYFILE,
|
155
|
+
GCP_APPLICATION_NAME
|
156
|
+
);
|
157
|
+
|
158
|
+
Storage client = auth.getGcsClient(GCP_BUCKET);
|
159
|
+
|
160
|
+
assertEquals(Storage.class, client.getClass());
|
161
|
+
}
|
162
|
+
|
163
|
+
@Test(expected = GoogleJsonResponseException.class)
|
164
|
+
public void testGetServiceAccountCredentialFromJsonThrowGoogleJsonResponseException()
|
165
|
+
throws NoSuchFieldException, IllegalAccessException, GeneralSecurityException, IOException
|
166
|
+
{
|
167
|
+
GcsAuthentication auth = new GcsAuthentication(
|
168
|
+
"json_key",
|
169
|
+
GCP_EMAIL,
|
170
|
+
null,
|
171
|
+
GCP_JSON_KEYFILE,
|
172
|
+
GCP_APPLICATION_NAME
|
173
|
+
);
|
174
|
+
|
175
|
+
Storage client = auth.getGcsClient("non-exists-bucket");
|
176
|
+
}
|
177
|
+
}
|
@@ -1,9 +1,355 @@
|
|
1
1
|
package org.embulk.input.gcs;
|
2
2
|
|
3
|
-
import
|
3
|
+
import java.util.ArrayList;
|
4
|
+
import java.util.Arrays;
|
4
5
|
import java.util.List;
|
6
|
+
import com.google.common.collect.ImmutableMap;
|
7
|
+
import com.google.common.base.Optional;
|
8
|
+
import com.google.common.collect.ImmutableList;
|
9
|
+
import com.google.common.collect.Lists;
|
10
|
+
import java.io.IOException;
|
11
|
+
import java.security.GeneralSecurityException;
|
12
|
+
|
13
|
+
import org.embulk.EmbulkTestRuntime;
|
14
|
+
import org.embulk.config.TaskReport;
|
15
|
+
import org.embulk.config.TaskSource;
|
16
|
+
import org.embulk.config.ConfigDiff;
|
17
|
+
import org.embulk.config.ConfigSource;
|
18
|
+
import org.embulk.config.ConfigException;
|
19
|
+
import org.embulk.spi.Exec;
|
20
|
+
import org.embulk.spi.FileInputPlugin;
|
21
|
+
import org.embulk.spi.FileInputRunner;
|
22
|
+
import org.embulk.spi.InputPlugin;
|
23
|
+
import org.embulk.spi.util.Pages;
|
24
|
+
import org.embulk.spi.Schema;
|
25
|
+
import org.embulk.spi.TestPageBuilderReader.MockPageOutput;
|
26
|
+
import org.embulk.input.gcs.GcsFileInputPlugin.PluginTask;
|
27
|
+
import org.embulk.standards.CsvParserPlugin;
|
28
|
+
|
29
|
+
import com.google.api.services.storage.Storage;
|
30
|
+
|
31
|
+
import org.junit.BeforeClass;
|
32
|
+
import org.junit.Before;
|
33
|
+
import org.junit.Rule;
|
5
34
|
import org.junit.Test;
|
35
|
+
import static org.junit.Assert.assertEquals;
|
36
|
+
import static org.junit.Assume.assumeNotNull;
|
37
|
+
|
38
|
+
public class TestGcsFileInputPlugin
|
39
|
+
{
|
40
|
+
private static Optional<String> GCP_EMAIL;
|
41
|
+
private static Optional<String> GCP_P12_KEYFILE;
|
42
|
+
private static Optional<String> GCP_JSON_KEYFILE;
|
43
|
+
private static String GCP_BUCKET;
|
44
|
+
private static String GCP_BUCKET_DIRECTORY;
|
45
|
+
private static String GCP_PATH_PREFIX;
|
46
|
+
private final String GCP_APPLICATION_NAME = "embulk-input-gcs";
|
47
|
+
private FileInputRunner runner;
|
48
|
+
private MockPageOutput output;
|
49
|
+
|
50
|
+
/*
|
51
|
+
* This test case requires environment variables
|
52
|
+
* GCP_EMAIL
|
53
|
+
* GCP_P12_KEYFILE
|
54
|
+
* GCP_JSON_KEYFILE
|
55
|
+
* GCP_BUCKET
|
56
|
+
*/
|
57
|
+
@BeforeClass
|
58
|
+
public static void initializeConstant()
|
59
|
+
{
|
60
|
+
GCP_EMAIL = Optional.of(System.getenv("GCP_EMAIL"));
|
61
|
+
GCP_P12_KEYFILE = Optional.of(System.getenv("GCP_P12_KEYFILE"));
|
62
|
+
GCP_JSON_KEYFILE = Optional.of(System.getenv("GCP_JSON_KEYFILE"));
|
63
|
+
GCP_BUCKET = System.getenv("GCP_BUCKET");
|
64
|
+
// skip test cases, if environment variables are not set.
|
65
|
+
assumeNotNull(GCP_EMAIL, GCP_P12_KEYFILE, GCP_JSON_KEYFILE, GCP_BUCKET);
|
66
|
+
|
67
|
+
GCP_BUCKET_DIRECTORY = System.getenv("GCP_BUCKET_DIRECTORY") != null ? getDirectory(System.getenv("GCP_BUCKET_DIRECTORY")) : getDirectory("");
|
68
|
+
GCP_PATH_PREFIX = GCP_BUCKET_DIRECTORY + "sample_";
|
69
|
+
}
|
70
|
+
|
71
|
+
@Rule
|
72
|
+
public EmbulkTestRuntime runtime = new EmbulkTestRuntime();
|
73
|
+
private ConfigSource config;
|
74
|
+
private GcsFileInputPlugin plugin;
|
75
|
+
|
76
|
+
@Before
|
77
|
+
public void createResources() throws GeneralSecurityException, NoSuchMethodException, IOException
|
78
|
+
{
|
79
|
+
config = config();
|
80
|
+
plugin = new GcsFileInputPlugin();
|
81
|
+
runner = new FileInputRunner(runtime.getInstance(GcsFileInputPlugin.class));
|
82
|
+
output = new MockPageOutput();
|
83
|
+
}
|
84
|
+
|
85
|
+
@Test
|
86
|
+
public void checkDefaultValues()
|
87
|
+
{
|
88
|
+
ConfigSource config = Exec.newConfigSource()
|
89
|
+
.set("bucket", GCP_BUCKET)
|
90
|
+
.set("path_prefix", "my-prefix");
|
91
|
+
|
92
|
+
GcsFileInputPlugin.PluginTask task = config.loadConfig(PluginTask.class);
|
93
|
+
assertEquals("private_key", task.getAuthMethod().toString());
|
94
|
+
assertEquals("Embulk GCS input plugin", task.getApplicationName());
|
95
|
+
}
|
96
|
+
|
97
|
+
// p12_keyfile is null when auth_method is private_key
|
98
|
+
@Test(expected = ConfigException.class)
|
99
|
+
public void checkDefaultValuesP12keyNull()
|
100
|
+
{
|
101
|
+
ConfigSource config = Exec.newConfigSource()
|
102
|
+
.set("bucket", GCP_BUCKET)
|
103
|
+
.set("path_prefix", "my-prefix")
|
104
|
+
.set("auth_method", "private_key")
|
105
|
+
.set("service_account_email", GCP_EMAIL)
|
106
|
+
.set("p12_keyfile", null);
|
107
|
+
|
108
|
+
runner.transaction(config, new Control());
|
109
|
+
}
|
110
|
+
|
111
|
+
// both p12_keyfile and p12_keyfile_fullpath set
|
112
|
+
@Test(expected = ConfigException.class)
|
113
|
+
public void checkDefaultValuesConflictSetting()
|
114
|
+
{
|
115
|
+
ConfigSource config = Exec.newConfigSource()
|
116
|
+
.set("bucket", GCP_BUCKET)
|
117
|
+
.set("path_prefix", "my-prefix")
|
118
|
+
.set("auth_method", "private_key")
|
119
|
+
.set("service_account_email", GCP_EMAIL)
|
120
|
+
.set("p12_keyfile", GCP_P12_KEYFILE)
|
121
|
+
.set("p12_keyfile_fullpath", GCP_P12_KEYFILE);
|
122
|
+
|
123
|
+
runner.transaction(config, new Control());
|
124
|
+
}
|
125
|
+
|
126
|
+
// invalid p12keyfile when auth_method is private_key
|
127
|
+
@Test(expected = ConfigException.class)
|
128
|
+
public void checkDefaultValuesInvalidPrivateKey()
|
129
|
+
{
|
130
|
+
ConfigSource config = Exec.newConfigSource()
|
131
|
+
.set("bucket", GCP_BUCKET)
|
132
|
+
.set("path_prefix", "my-prefix")
|
133
|
+
.set("auth_method", "private_key")
|
134
|
+
.set("service_account_email", GCP_EMAIL)
|
135
|
+
.set("p12_keyfile", "invalid-key.p12");
|
136
|
+
|
137
|
+
runner.transaction(config, new Control());
|
138
|
+
}
|
139
|
+
|
140
|
+
// json_keyfile is null when auth_method is json_key
|
141
|
+
@Test(expected = ConfigException.class)
|
142
|
+
public void checkDefaultValuesJsonKeyfileNull()
|
143
|
+
{
|
144
|
+
ConfigSource config = Exec.newConfigSource()
|
145
|
+
.set("bucket", GCP_BUCKET)
|
146
|
+
.set("path_prefix", "my-prefix")
|
147
|
+
.set("auth_method", "json_key")
|
148
|
+
.set("service_account_email", GCP_EMAIL)
|
149
|
+
.set("json_keyfile", null);
|
150
|
+
|
151
|
+
runner.transaction(config, new Control());
|
152
|
+
}
|
153
|
+
|
154
|
+
@Test
|
155
|
+
public void testGcsClientCreateSuccessfully()
|
156
|
+
throws GeneralSecurityException, IOException, NoSuchFieldException
|
157
|
+
{
|
158
|
+
PluginTask task = config().loadConfig(PluginTask.class);
|
159
|
+
runner.transaction(config, new Control());
|
160
|
+
plugin.newGcsClient(task); // no errors happens
|
161
|
+
}
|
162
|
+
|
163
|
+
@Test(expected = ConfigException.class)
|
164
|
+
public void testGcsClientCreateThrowConfigException()
|
165
|
+
throws GeneralSecurityException, IOException, NoSuchFieldException
|
166
|
+
{
|
167
|
+
ConfigSource config = Exec.newConfigSource()
|
168
|
+
.set("bucket", "non-exists-bucket")
|
169
|
+
.set("path_prefix", "my-prefix")
|
170
|
+
.set("auth_method", "json_key")
|
171
|
+
.set("service_account_email", GCP_EMAIL)
|
172
|
+
.set("json_keyfile", GCP_JSON_KEYFILE);
|
173
|
+
|
174
|
+
PluginTask task = config().loadConfig(PluginTask.class);
|
175
|
+
runner.transaction(config, new Control());
|
176
|
+
plugin.newGcsClient(task);
|
177
|
+
}
|
178
|
+
|
179
|
+
@Test
|
180
|
+
public void testResume()
|
181
|
+
{
|
182
|
+
PluginTask task = config.loadConfig(PluginTask.class);
|
183
|
+
task.setFiles(Arrays.asList(new String[]{"in/aa/a"}));
|
184
|
+
ConfigDiff configDiff = plugin.resume(task.dump(), 0, new FileInputPlugin.Control()
|
185
|
+
{
|
186
|
+
@Override
|
187
|
+
public List<TaskReport> run(TaskSource taskSource, int taskCount)
|
188
|
+
{
|
189
|
+
return emptyTaskReports(taskCount);
|
190
|
+
}
|
191
|
+
});
|
192
|
+
assertEquals("in/aa/a", configDiff.get(String.class, "last_path"));
|
193
|
+
}
|
194
|
+
|
195
|
+
@Test
|
196
|
+
public void testCleanup()
|
197
|
+
{
|
198
|
+
PluginTask task = config.loadConfig(PluginTask.class);
|
199
|
+
plugin.cleanup(task.dump(), 0, Lists.<TaskReport>newArrayList()); // no errors happens
|
200
|
+
}
|
201
|
+
|
202
|
+
@Test
|
203
|
+
public void testListFilesByPrefix()
|
204
|
+
{
|
205
|
+
List<String> expected = Arrays.asList(
|
206
|
+
GCP_BUCKET_DIRECTORY + "sample_01.csv",
|
207
|
+
GCP_BUCKET_DIRECTORY + "sample_02.csv"
|
208
|
+
);
|
209
|
+
|
210
|
+
PluginTask task = config.loadConfig(PluginTask.class);
|
211
|
+
ConfigDiff configDiff = plugin.transaction(config, new FileInputPlugin.Control() {
|
212
|
+
@Override
|
213
|
+
public List<TaskReport> run(TaskSource taskSource, int taskCount) {
|
214
|
+
assertEquals(2, taskCount);
|
215
|
+
return emptyTaskReports(taskCount);
|
216
|
+
}
|
217
|
+
});
|
218
|
+
|
219
|
+
Storage client = plugin.newGcsClient(task);
|
220
|
+
List<String> actual = plugin.listGcsFilesByPrefix(client, GCP_BUCKET, GCP_PATH_PREFIX, Optional.<String>absent());
|
221
|
+
assertEquals(expected, actual);
|
222
|
+
|
223
|
+
assertEquals(GCP_BUCKET_DIRECTORY + "sample_02.csv", configDiff.get(String.class, "last_path"));
|
224
|
+
}
|
225
|
+
|
226
|
+
@Test
|
227
|
+
public void testListFilesByPrefixNonExistsBucket()
|
228
|
+
{
|
229
|
+
PluginTask task = config.loadConfig(PluginTask.class);
|
230
|
+
runner.transaction(config, new Control());
|
231
|
+
Storage client = plugin.newGcsClient(task);
|
232
|
+
plugin.listGcsFilesByPrefix(client, "non-exists-bucket", "prefix", Optional.<String>absent()); // no errors happens
|
233
|
+
}
|
234
|
+
|
235
|
+
@Test
|
236
|
+
public void testGcsFileInputByOpen() throws IOException
|
237
|
+
{
|
238
|
+
ConfigSource config = Exec.newConfigSource()
|
239
|
+
.set("bucket", GCP_BUCKET)
|
240
|
+
.set("path_prefix", GCP_PATH_PREFIX)
|
241
|
+
.set("auth_method", "json_key")
|
242
|
+
.set("service_account_email", GCP_EMAIL)
|
243
|
+
.set("json_keyfile", GCP_JSON_KEYFILE)
|
244
|
+
.set("parser", parserConfig(schemaConfig()));
|
245
|
+
|
246
|
+
PluginTask task = config.loadConfig(PluginTask.class);
|
247
|
+
runner.transaction(config, new Control());
|
248
|
+
task.setFiles(plugin.listFiles(task));
|
249
|
+
|
250
|
+
assertRecords(config, output);
|
251
|
+
}
|
252
|
+
|
253
|
+
public ConfigSource config()
|
254
|
+
{
|
255
|
+
return Exec.newConfigSource()
|
256
|
+
.set("bucket", GCP_BUCKET)
|
257
|
+
.set("path_prefix", GCP_PATH_PREFIX)
|
258
|
+
.set("auth_method", "private_key")
|
259
|
+
.set("service_account_email", GCP_EMAIL)
|
260
|
+
.set("p12_keyfile", GCP_P12_KEYFILE)
|
261
|
+
.set("json_keyfile", GCP_JSON_KEYFILE)
|
262
|
+
.set("application_name", GCP_APPLICATION_NAME)
|
263
|
+
.set("parser", parserConfig(schemaConfig()));
|
264
|
+
}
|
265
|
+
|
266
|
+
static List<TaskReport> emptyTaskReports(int taskCount)
|
267
|
+
{
|
268
|
+
ImmutableList.Builder<TaskReport> reports = new ImmutableList.Builder<>();
|
269
|
+
for (int i = 0; i < taskCount; i++) {
|
270
|
+
reports.add(Exec.newTaskReport());
|
271
|
+
}
|
272
|
+
return reports.build();
|
273
|
+
}
|
274
|
+
|
275
|
+
private class Control
|
276
|
+
implements InputPlugin.Control
|
277
|
+
{
|
278
|
+
@Override
|
279
|
+
public List<TaskReport> run(TaskSource taskSource, Schema schema, int taskCount)
|
280
|
+
{
|
281
|
+
List<TaskReport> reports = new ArrayList<>();
|
282
|
+
for (int i = 0; i < taskCount; i++) {
|
283
|
+
reports.add(runner.run(taskSource, schema, i, output));
|
284
|
+
}
|
285
|
+
return reports;
|
286
|
+
}
|
287
|
+
}
|
288
|
+
|
289
|
+
private ImmutableMap<String, Object> parserConfig(ImmutableList<Object> schemaConfig)
|
290
|
+
{
|
291
|
+
ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
|
292
|
+
builder.put("type", "csv");
|
293
|
+
builder.put("newline", "CRLF");
|
294
|
+
builder.put("delimiter", ",");
|
295
|
+
builder.put("quote", "\"");
|
296
|
+
builder.put("escape", "\"");
|
297
|
+
builder.put("trim_if_not_quoted", false);
|
298
|
+
builder.put("skip_header_lines", 1);
|
299
|
+
builder.put("allow_extra_columns", false);
|
300
|
+
builder.put("allow_optional_columns", false);
|
301
|
+
builder.put("columns", schemaConfig);
|
302
|
+
return builder.build();
|
303
|
+
}
|
304
|
+
|
305
|
+
private ImmutableList<Object> schemaConfig()
|
306
|
+
{
|
307
|
+
ImmutableList.Builder<Object> builder = new ImmutableList.Builder<>();
|
308
|
+
builder.add(ImmutableMap.of("name", "id", "type", "long"));
|
309
|
+
builder.add(ImmutableMap.of("name", "account", "type", "long"));
|
310
|
+
builder.add(ImmutableMap.of("name", "time", "type", "timestamp", "format", "%Y-%m-%d %H:%M:%S"));
|
311
|
+
builder.add(ImmutableMap.of("name", "purchase", "type", "timestamp", "format", "%Y%m%d"));
|
312
|
+
builder.add(ImmutableMap.of("name", "comment", "type", "string"));
|
313
|
+
return builder.build();
|
314
|
+
}
|
315
|
+
|
316
|
+
private void assertRecords(ConfigSource config, MockPageOutput output)
|
317
|
+
{
|
318
|
+
List<Object[]> records = getRecords(config, output);
|
319
|
+
assertEquals(8, records.size());
|
320
|
+
{
|
321
|
+
Object[] record = records.get(0);
|
322
|
+
assertEquals(1L, record[0]);
|
323
|
+
assertEquals(32864L, record[1]);
|
324
|
+
assertEquals("2015-01-27 19:23:49 UTC", record[2].toString());
|
325
|
+
assertEquals("2015-01-27 00:00:00 UTC", record[3].toString());
|
326
|
+
assertEquals("embulk", record[4]);
|
327
|
+
}
|
328
|
+
|
329
|
+
{
|
330
|
+
Object[] record = records.get(1);
|
331
|
+
assertEquals(2L, record[0]);
|
332
|
+
assertEquals(14824L, record[1]);
|
333
|
+
assertEquals("2015-01-27 19:01:23 UTC", record[2].toString());
|
334
|
+
assertEquals("2015-01-27 00:00:00 UTC", record[3].toString());
|
335
|
+
assertEquals("embulk jruby", record[4]);
|
336
|
+
}
|
337
|
+
}
|
338
|
+
|
339
|
+
private List<Object[]> getRecords(ConfigSource config, MockPageOutput output)
|
340
|
+
{
|
341
|
+
Schema schema = config.getNested("parser").loadConfig(CsvParserPlugin.PluginTask.class).getSchemaConfig().toSchema();
|
342
|
+
return Pages.toObjects(schema, output.pages);
|
343
|
+
}
|
6
344
|
|
7
|
-
|
8
|
-
|
345
|
+
private static String getDirectory(String dir)
|
346
|
+
{
|
347
|
+
if (dir != null && !dir.endsWith("/")) {
|
348
|
+
dir = dir + "/";
|
349
|
+
}
|
350
|
+
if (dir.startsWith("/")) {
|
351
|
+
dir = dir.replaceFirst("/", "");
|
352
|
+
}
|
353
|
+
return dir;
|
354
|
+
}
|
9
355
|
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: embulk-input-gcs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Satoshi Akama
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-10-
|
11
|
+
date: 2015-10-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -57,10 +57,13 @@ files:
|
|
57
57
|
- settings.gradle
|
58
58
|
- src/main/java/org/embulk/input/gcs/GcsAuthentication.java
|
59
59
|
- src/main/java/org/embulk/input/gcs/GcsFileInputPlugin.java
|
60
|
+
- src/test/java/org/embulk/input/gcs/TestGcsAuthentication.java
|
60
61
|
- src/test/java/org/embulk/input/gcs/TestGcsFileInputPlugin.java
|
62
|
+
- src/test/resources/sample_01.csv
|
63
|
+
- src/test/resources/sample_02.csv
|
61
64
|
- classpath/commons-codec-1.3.jar
|
62
65
|
- classpath/commons-logging-1.1.1.jar
|
63
|
-
- classpath/embulk-input-gcs-0.1.
|
66
|
+
- classpath/embulk-input-gcs-0.1.8.jar
|
64
67
|
- classpath/google-api-client-1.19.1.jar
|
65
68
|
- classpath/google-api-services-storage-v1-rev27-1.19.1.jar
|
66
69
|
- classpath/google-http-client-1.19.0.jar
|
Binary file
|