embulk-input-gcs 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|