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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 24b44f4db77ef29422e03052b58cdf67378d5a79
4
- data.tar.gz: 031a0686510df86a6b87780aa0da707cd7cd64cc
3
+ metadata.gz: 219d292e87e6a2b326144302280e10bba7e3ea2a
4
+ data.tar.gz: c7e6e1933bc1961e16f18c68022261e1948cd5bc
5
5
  SHA512:
6
- metadata.gz: eb5815752627aeef5c32de944d23e78c03313970e574f61e3706808bb4314643311e4d581ae2fc7589ede24e80ff53236cdd0defecbd647a2d382d26b3630dcc
7
- data.tar.gz: 5ce214a4e252f78bbc9a9215d3edcc0de671220e2f5f9697687e4b4ac0d9d05303a5a724f399ad1a8175a8a8d85bd50d977fc01af8a718e74cb50981e34b3b6d
6
+ metadata.gz: e09e566db719125bc872a33026c4dd15bb1b29bf3ad82ce75a5cdd1fc5c342e2c8c72179accd3b9fafecf8ca3945dd26c0e1cdc70036d3a82d509485c388e925
7
+ data.tar.gz: aa068f8ac05d9fafec71baa24d71f18b59096521277ce836a5b27c1f1c491d4aee8ffe004d71117d5d6d68482e6525071fbcb2da4f3ca30601c638582cf7d260
data/ChangeLog CHANGED
@@ -1,3 +1,7 @@
1
+ Release 0.1.8 - 2015-10-29
2
+
3
+ * Added unit tests
4
+
1
5
  Release 0.1.7 - 2015-10-06
2
6
 
3
7
  * Added new auth method - json_keyfile of GCP(Google Cloud Platform)'s service account
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/bigquery" to the scope list of your
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.7"
19
+ version = "0.1.8"
19
20
 
20
21
  dependencies {
21
- compile "org.embulk:embulk-core:0.7.1"
22
- provided "org.embulk:embulk-core:0.7.1"
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"]) {
@@ -165,7 +165,7 @@ public class GcsFileInputPlugin
165
165
  {
166
166
  }
167
167
 
168
- private static Storage newGcsClient(final PluginTask task)
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
- if (log.isDebugEnabled()) {
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());
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 static class GcsFileInput
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 static org.junit.Assert.*;
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
- // @todo Write unit test.
8
- public class TestGcsFileInputPlugin {
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
  }
@@ -0,0 +1,5 @@
1
+ id,account,time,purchase,comment
2
+ 1,32864,2015-01-27 19:23:49,20150127,embulk
3
+ 2,14824,2015-01-27 19:01:23,20150127,embulk jruby
4
+ 3,27559,2015-01-28 02:20:02,20150128,"Embulk ""csv"" parser plugin"
5
+ 4,11270,2015-01-29 11:54:36,20150129,NULL
@@ -0,0 +1,5 @@
1
+ id,account,time,purchase,comment
2
+ 1,32864,2015-01-27 19:23:49,20150127,embulk
3
+ 2,14824,2015-01-27 19:01:23,20150127,embulk jruby
4
+ 3,27559,2015-01-28 02:20:02,20150128,"Embulk ""csv"" parser plugin"
5
+ 4,11270,2015-01-29 11:54:36,20150129,NULL
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.7
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-06 00:00:00.000000000 Z
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.7.jar
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