embulk-output-azure_blob_storage 0.1.0 → 0.1.1

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: c606ebbfa50cbbc803f2ff2f47d6f4dd445eb9d3
4
- data.tar.gz: e36fc67a7ce53216367c0c5fb8e0c1aa629fb8d4
3
+ metadata.gz: 780301179e35e336690948c80eb1f0be40969fda
4
+ data.tar.gz: 0820d6fe2606320543583146126c0df179ff8dcf
5
5
  SHA512:
6
- metadata.gz: beb7e8ec55ce584f88de927aa6fedf75dc62513636e71d60604b1440d525f04e93b196c95518e1f1d132c1a42d0bdd52090f30facb6a59683b7ce45ece2ac2ce
7
- data.tar.gz: b45f0a27f6024c703c3297962dcb7c8957588df0be1f8a8ba27ac17e57385518bd1aa387bbf9e5e560dfd977f1c91af230ea3e4b76019720281881eff13a3cef
6
+ metadata.gz: 77f5049f878c6a82809226ebe49873ec31e6a16d475dd7991b9a729d3348be98885052bfa83c5bf97777bac053014532dec2c028e9add5b2f21d3729abe919f0
7
+ data.tar.gz: 75dee87d6947f777e5a8e0211bbbb8dc9922bd6cbb7784a2853bb4a9f907f66ce05e572bb431e2d34a7ffe23c096b24b04a30c40d0075007b3f301f5e3b5f8b5
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: java
2
+ jdk:
3
+ - oraclejdk7
4
+ script:
5
+ - ./gradlew --info check jacocoTestReport
data/README.md CHANGED
@@ -50,3 +50,56 @@ out:
50
50
  ```
51
51
  $ ./gradlew gem # -t to watch change of files and rebuild continuously
52
52
  ```
53
+
54
+
55
+ ## Test
56
+
57
+ ```
58
+ $ ./gradlew test # -t to watch change of files and rebuild continuously
59
+ ```
60
+
61
+ To run unit tests, we need to configure the following environment variables.
62
+
63
+ Additionally, following files will be needed to upload to existing GCS bucket.
64
+ * [sample_01.csv](./src/test/resources/sample_01.csv)
65
+ * [sample_02.csv](./src/test/resources/sample_02.csv)
66
+
67
+ When environment variables are not set, skip some test cases.
68
+
69
+ ```
70
+ AZURE_ACCOUNT_NAME
71
+ AZURE_ACCOUNT_KEY
72
+ AZURE_CONTAINER
73
+ AZURE_CONTAINER_DIRECTORY (optional, if needed)
74
+ ```
75
+
76
+ If you're using Mac OS X El Capitan and GUI Applications(IDE), like as follows.
77
+ ```
78
+ $ vi ~/Library/LaunchAgents/environment.plist
79
+ <?xml version="1.0" encoding="UTF-8"?>
80
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
81
+ <plist version="1.0">
82
+ <dict>
83
+ <key>Label</key>
84
+ <string>my.startup</string>
85
+ <key>ProgramArguments</key>
86
+ <array>
87
+ <string>sh</string>
88
+ <string>-c</string>
89
+ <string>
90
+ launchctl setenv AZURE_ACCOUNT_NAME my-account-name
91
+ launchctl setenv AZURE_ACCOUNT_KEY my-account-key
92
+ launchctl setenv AZURE_CONTAINER my-container
93
+ launchctl setenv AZURE_CONTAINER_DIRECTORY unittests
94
+ </string>
95
+ </array>
96
+ <key>RunAtLoad</key>
97
+ <true/>
98
+ </dict>
99
+ </plist>
100
+
101
+ $ launchctl load ~/Library/LaunchAgents/environment.plist
102
+ $ launchctl getenv AZURE_ACCOUNT_NAME //try to get value.
103
+
104
+ Then start your applications.
105
+ ```
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,7 +16,7 @@ configurations {
15
16
  sourceCompatibility = 1.7
16
17
  targetCompatibility = 1.7
17
18
 
18
- version = "0.1.0"
19
+ version = "0.1.1"
19
20
 
20
21
  dependencies {
21
22
  compile "org.embulk:embulk-core:0.7.5"
@@ -23,7 +24,9 @@ dependencies {
23
24
 
24
25
  compile "com.microsoft.azure:azure-storage:4.0.0"
25
26
 
26
- testCompile "junit:junit:4.+"
27
+ testCompile "junit:junit:4.12"
28
+ testCompile "org.embulk:embulk-core:0.7.5:tests"
29
+ testCompile "org.embulk:embulk-standards:0.7.5"
27
30
  }
28
31
 
29
32
  task classpath(type: Copy, dependsOn: ["jar"]) {
@@ -0,0 +1,18 @@
1
+
2
+ Gem::Specification.new do |spec|
3
+ spec.name = "embulk-output-azure_blob_storage"
4
+ spec.version = "0.1.1"
5
+ spec.authors = ["Satoshi Akama"]
6
+ spec.summary = %[Microsoft Azure blob Storage file output plugin for Embulk]
7
+ spec.description = %[Stores files on Microsoft Azure blob Storage.]
8
+ spec.email = ["satoshiakama@gmail.com"]
9
+ spec.licenses = ["Apache-2.0"]
10
+ spec.homepage = "https://github.com/sakama/embulk-output-azure_blob_storage"
11
+
12
+ spec.files = `git ls-files`.split("\n") + Dir["classpath/*.jar"]
13
+ spec.test_files = spec.files.grep(%r"^(test|spec)/")
14
+ spec.require_paths = ["lib"]
15
+
16
+ spec.add_development_dependency 'bundler', ['~> 1.0']
17
+ spec.add_development_dependency 'rake', ['>= 10.0']
18
+ end
@@ -53,24 +53,22 @@ public class AzureBlobStorageFileOutputPlugin
53
53
  }
54
54
 
55
55
  private static final Logger log = Exec.getLogger(AzureBlobStorageFileOutputPlugin.class);
56
- private static CloudBlobClient blobClient;
57
- private static CloudBlobContainer container;
58
56
 
59
57
  @Override
60
58
  public ConfigDiff transaction(ConfigSource config, int taskCount,
61
59
  FileOutputPlugin.Control control)
62
60
  {
63
61
  PluginTask task = config.loadConfig(PluginTask.class);
64
- blobClient = newAzureClient(task.getAccountName(), task.getAccountKey());
65
- String containerName = task.getContainer();
66
62
 
67
63
  try {
68
- container = blobClient.getContainerReference(containerName);
64
+ CloudBlobClient blobClient = newAzureClient(task.getAccountName(), task.getAccountKey());
65
+ String containerName = task.getContainer();
66
+ CloudBlobContainer container = blobClient.getContainerReference(containerName);
69
67
  if (!container.exists()) {
70
68
  log.info(String.format("container [%s] is not exists and created.", containerName));
71
69
  container.createIfNotExists();
72
70
  }
73
- } catch (StorageException | URISyntaxException ex) {
71
+ } catch (StorageException | URISyntaxException | ConfigException ex) {
74
72
  Throwables.propagate(ex);
75
73
  }
76
74
 
@@ -106,94 +104,118 @@ public class AzureBlobStorageFileOutputPlugin
106
104
  }
107
105
 
108
106
  @Override
109
- public TransactionalFileOutput open(TaskSource taskSource, final int taskIndex)
110
- {
107
+ public TransactionalFileOutput open(TaskSource taskSource, final int taskIndex) {
111
108
  final PluginTask task = taskSource.loadTask(PluginTask.class);
109
+ return new AzureFileOutput(task, taskIndex);
110
+ }
112
111
 
113
- final String pathPrefix = task.getPathPrefix();
114
- final String sequenceFormat = task.getSequenceFormat();
115
- final String pathSuffix = task.getFileNameExtension();
116
-
117
- return new TransactionalFileOutput() {
118
- private int fileIndex = 0;
119
- private BufferedOutputStream output = null;
120
- private File file;
121
- private String filePath;
112
+ public static class AzureFileOutput implements TransactionalFileOutput
113
+ {
114
+ private final String pathPrefix;
115
+ private final String sequenceFormat;
116
+ private final String pathSuffix;
117
+ private final CloudBlobClient client;
118
+ private CloudBlobContainer container = null;
119
+ private BufferedOutputStream output = null;
120
+ private int fileIndex;
121
+ private File file;
122
+ private String filePath;
123
+ private int taskIndex;
124
+
125
+ public AzureFileOutput(PluginTask task, int taskIndex)
126
+ {
127
+ this.taskIndex = taskIndex;
128
+ this.pathPrefix = task.getPathPrefix();
129
+ this.sequenceFormat = task.getSequenceFormat();
130
+ this.pathSuffix = task.getFileNameExtension();
131
+ this.client = newAzureClient(task.getAccountName(), task.getAccountKey());
132
+ try {
133
+ this.container = client.getContainerReference(task.getContainer());
134
+ } catch (URISyntaxException | StorageException ex) {
135
+ Throwables.propagate(ex);
136
+ }
137
+ }
122
138
 
123
- public void nextFile()
124
- {
125
- closeFile();
139
+ @Override
140
+ public void nextFile()
141
+ {
142
+ closeFile();
126
143
 
127
- try {
128
- String suffix = pathSuffix;
129
- if (!suffix.startsWith(".")) {
130
- suffix = "." + suffix;
131
- }
132
- filePath = pathPrefix + String.format(sequenceFormat, taskIndex, fileIndex) + suffix;
133
- file = new File(filePath);
134
-
135
- String parentPath = file.getParent();
136
- File dir = new File(parentPath);
137
- if (!dir.exists()) {
138
- dir.mkdir();
139
- }
140
- log.info(String.format("Writing local file [%s]", filePath));
141
- output = new BufferedOutputStream(new FileOutputStream(filePath));
142
- } catch (FileNotFoundException ex) {
143
- throw Throwables.propagate(ex);
144
+ try {
145
+ String suffix = pathSuffix;
146
+ if (!suffix.startsWith(".")) {
147
+ suffix = "." + suffix;
144
148
  }
145
- }
149
+ filePath = pathPrefix + String.format(sequenceFormat, taskIndex, fileIndex) + suffix;
150
+ file = new File(filePath);
146
151
 
147
- private void closeFile()
148
- {
149
- if (output != null) {
150
- try {
151
- output.close();
152
- } catch (IOException ex) {
153
- throw Throwables.propagate(ex);
154
- }
152
+ String parentPath = file.getParent();
153
+ File dir = new File(parentPath);
154
+ if (!dir.exists()) {
155
+ dir.mkdir();
155
156
  }
157
+ log.info(String.format("Writing local file [%s]", filePath));
158
+ output = new BufferedOutputStream(new FileOutputStream(filePath));
159
+ } catch (FileNotFoundException ex) {
160
+ throw Throwables.propagate(ex);
156
161
  }
162
+ }
157
163
 
158
- public void add(Buffer buffer)
159
- {
164
+ private void closeFile()
165
+ {
166
+ if (output != null) {
160
167
  try {
161
- output.write(buffer.array(), buffer.offset(), buffer.limit());
168
+ output.close();
169
+ fileIndex++;
162
170
  } catch (IOException ex) {
163
171
  throw Throwables.propagate(ex);
164
- } finally {
165
- buffer.release();
166
172
  }
167
173
  }
174
+ }
168
175
 
169
- public void finish()
170
- {
171
- closeFile();
172
- if (filePath != null) {
173
- try {
174
- CloudBlockBlob blob = container.getBlockBlobReference(filePath);
175
- log.info(String.format("Upload start [%s]", filePath));
176
- blob.upload(new FileInputStream(file), file.length());
177
- log.info(String.format("Upload completed [%s]", filePath));
178
- file.delete();
179
- log.info(String.format("Delete completed local file [%s]", filePath));
180
- } catch (StorageException | URISyntaxException | IOException ex) {
181
- Throwables.propagate(ex);
182
- }
183
- }
176
+ @Override
177
+ public void add(Buffer buffer)
178
+ {
179
+ try {
180
+ output.write(buffer.array(), buffer.offset(), buffer.limit());
181
+ } catch (IOException ex) {
182
+ throw Throwables.propagate(ex);
183
+ } finally {
184
+ buffer.release();
184
185
  }
186
+ }
185
187
 
186
- public void close()
187
- {
188
- closeFile();
188
+ @Override
189
+ public void finish()
190
+ {
191
+ closeFile();
192
+ if (filePath != null) {
193
+ try {
194
+ CloudBlockBlob blob = container.getBlockBlobReference(filePath);
195
+ log.info(String.format("Upload start [%s]", filePath));
196
+ blob.upload(new FileInputStream(file), file.length());
197
+ log.info(String.format("Upload completed [%s]", filePath));
198
+ file.delete();
199
+ log.info(String.format("Delete completed local file [%s]", filePath));
200
+ } catch (StorageException | URISyntaxException | IOException ex) {
201
+ Throwables.propagate(ex);
202
+ }
189
203
  }
204
+ }
190
205
 
191
- public void abort() {}
206
+ @Override
207
+ public void close()
208
+ {
209
+ closeFile();
210
+ }
192
211
 
193
- public TaskReport commit()
194
- {
195
- return Exec.newTaskReport();
196
- }
197
- };
212
+ @Override
213
+ public void abort() {}
214
+
215
+ @Override
216
+ public TaskReport commit()
217
+ {
218
+ return Exec.newTaskReport();
219
+ }
198
220
  }
199
221
  }
@@ -1,5 +1,379 @@
1
1
  package org.embulk.output.azure_blob_storage;
2
2
 
3
+ import java.io.BufferedReader;
4
+ import java.io.ByteArrayOutputStream;
5
+ import java.io.FileInputStream;
6
+ import java.io.IOException;
7
+ import java.io.InputStream;
8
+ import java.io.InputStreamReader;
9
+ import java.lang.reflect.Method;
10
+ import java.security.GeneralSecurityException;
11
+ import java.util.Arrays;
12
+ import java.util.List;
13
+
14
+ import com.google.common.collect.ImmutableList;
15
+ import com.google.common.collect.ImmutableMap;
16
+ import com.google.common.collect.Lists;
17
+
18
+ import org.embulk.EmbulkTestRuntime;
19
+ import org.embulk.config.ConfigDiff;
20
+ import org.embulk.config.ConfigSource;
21
+ import org.embulk.config.TaskReport;
22
+ import org.embulk.config.TaskSource;
23
+ import org.embulk.spi.Buffer;
24
+ import org.embulk.spi.Exec;
25
+ import org.embulk.spi.Schema;
26
+ import org.embulk.spi.OutputPlugin;
27
+ import org.embulk.spi.FileOutputRunner;
28
+ import org.embulk.spi.FileOutputPlugin;
29
+ import org.embulk.spi.TransactionalFileOutput;
30
+ import org.embulk.standards.CsvParserPlugin;
31
+
32
+ import org.junit.BeforeClass;
33
+ import org.junit.Before;
34
+ import org.junit.Rule;
35
+ import org.junit.Test;
36
+ import static org.junit.Assert.assertEquals;
37
+ import static org.junit.Assume.assumeNotNull;
38
+
39
+ import com.microsoft.azure.storage.blob.CloudBlob;
40
+ import com.microsoft.azure.storage.blob.CloudBlobClient;
41
+ import com.microsoft.azure.storage.blob.CloudBlobContainer;
42
+ import org.embulk.output.azure_blob_storage.AzureBlobStorageFileOutputPlugin.PluginTask;
43
+
3
44
  public class TestAzureBlobStorageFileOutputPlugin
4
45
  {
46
+ private static String AZURE_ACCOUNT_NAME;
47
+ private static String AZURE_ACCOUNT_KEY;
48
+ private static String AZURE_CONTAINER;
49
+ private static String AZURE_CONTAINER_DIRECTORY;
50
+ private static String AZURE_PATH_PREFIX;
51
+ private static String LOCAL_PATH_PREFIX;
52
+ private FileOutputRunner runner;
53
+
54
+ /*
55
+ * This test case requires environment variables
56
+ * AZURE_ACCOUNT_NAME
57
+ * AZURE_ACCOUNT_KEY
58
+ * AZURE_CONTAINER
59
+ * AZURE_CONTAINER_DIRECTORY
60
+ */
61
+ @BeforeClass
62
+ public static void initializeConstant()
63
+ {
64
+ AZURE_ACCOUNT_NAME = System.getenv("AZURE_ACCOUNT_NAME");
65
+ AZURE_ACCOUNT_KEY = System.getenv("AZURE_ACCOUNT_KEY");
66
+ AZURE_CONTAINER = System.getenv("AZURE_CONTAINER");
67
+ // skip test cases, if environment variables are not set.
68
+ assumeNotNull(AZURE_ACCOUNT_NAME, AZURE_ACCOUNT_KEY, AZURE_CONTAINER);
69
+
70
+ AZURE_CONTAINER_DIRECTORY = System.getenv("AZURE_CONTAINER_DIRECTORY") != null ? getDirectory(System.getenv("AZURE_CONTAINER_DIRECTORY")) : getDirectory("");
71
+ AZURE_PATH_PREFIX = AZURE_CONTAINER_DIRECTORY + "sample_";
72
+ LOCAL_PATH_PREFIX = AzureBlobStorageFileOutputPlugin.class.getClassLoader().getResource("sample_01.csv").getPath();
73
+ }
74
+
75
+ @Rule
76
+ public EmbulkTestRuntime runtime = new EmbulkTestRuntime();
77
+ private AzureBlobStorageFileOutputPlugin plugin;
78
+
79
+ @Before
80
+ public void createResources() throws GeneralSecurityException, NoSuchMethodException, IOException
81
+ {
82
+ plugin = new AzureBlobStorageFileOutputPlugin();
83
+ runner = new FileOutputRunner(runtime.getInstance(AzureBlobStorageFileOutputPlugin.class));
84
+ }
85
+
86
+ @Test
87
+ public void checkDefaultValues()
88
+ {
89
+ ConfigSource config = Exec.newConfigSource()
90
+ .set("in", inputConfig())
91
+ .set("parser", parserConfig(schemaConfig()))
92
+ .set("type", "azure_blob_storage")
93
+ .set("account_name", AZURE_ACCOUNT_NAME)
94
+ .set("account_key", AZURE_ACCOUNT_KEY)
95
+ .set("container", AZURE_CONTAINER)
96
+ .set("path_prefix", "my-prefix")
97
+ .set("file_ext", ".csv")
98
+ .set("formatter", formatterConfig());
99
+
100
+ PluginTask task = config.loadConfig(PluginTask.class);
101
+ assertEquals(AZURE_ACCOUNT_NAME, task.getAccountName().toString());
102
+ }
103
+
104
+ @Test
105
+ public void testTransaction()
106
+ {
107
+ ConfigSource config = Exec.newConfigSource()
108
+ .set("in", inputConfig())
109
+ .set("parser", parserConfig(schemaConfig()))
110
+ .set("type", "azure_blob_storage")
111
+ .set("account_name", AZURE_ACCOUNT_NAME)
112
+ .set("account_key", AZURE_ACCOUNT_KEY)
113
+ .set("container", AZURE_CONTAINER)
114
+ .set("path_prefix", "my-prefix")
115
+ .set("file_ext", ".csv")
116
+ .set("formatter", formatterConfig());
117
+
118
+ Schema schema = config.getNested("parser").loadConfig(CsvParserPlugin.PluginTask.class).getSchemaConfig().toSchema();
119
+
120
+ runner.transaction(config, schema, 0, new Control());
121
+ }
122
+
123
+ @Test
124
+ public void testTransactionCreateNonexistsContainer() throws Exception
125
+ {
126
+ String container = "non-exists-container";
127
+ deleteContainerIfExists(container);
128
+
129
+ assertEquals(false, isExistsContainer(container));
130
+
131
+ ConfigSource config = Exec.newConfigSource()
132
+ .set("in", inputConfig())
133
+ .set("parser", parserConfig(schemaConfig()))
134
+ .set("type", "azure_blob_storage")
135
+ .set("account_name", AZURE_ACCOUNT_NAME)
136
+ .set("account_key", AZURE_ACCOUNT_KEY)
137
+ .set("container", container)
138
+ .set("path_prefix", "my-prefix")
139
+ .set("file_ext", ".csv")
140
+ .set("formatter", formatterConfig());
141
+
142
+ Schema schema = config.getNested("parser").loadConfig(CsvParserPlugin.PluginTask.class).getSchemaConfig().toSchema();
143
+
144
+ runner.transaction(config, schema, 0, new Control());
145
+
146
+ assertEquals(true, isExistsContainer(container));
147
+ deleteContainerIfExists(container);
148
+ }
149
+
150
+ @Test
151
+ public void testResume()
152
+ {
153
+ PluginTask task = config().loadConfig(PluginTask.class);
154
+ ConfigDiff configDiff = plugin.resume(task.dump(), 0, new FileOutputPlugin.Control()
155
+ {
156
+ @Override
157
+ public List<TaskReport> run(TaskSource taskSource)
158
+ {
159
+ return Lists.newArrayList(Exec.newTaskReport());
160
+ }
161
+ });
162
+ //assertEquals("in/aa/a", configDiff.get(String.class, "last_path"));
163
+ }
164
+
165
+ @Test
166
+ public void testCleanup()
167
+ {
168
+ PluginTask task = config().loadConfig(PluginTask.class);
169
+ plugin.cleanup(task.dump(), 0, Lists.<TaskReport>newArrayList()); // no errors happens
170
+ }
171
+
172
+ @Test(expected = RuntimeException.class)
173
+ public void testCreateAzureClientThrowsConfigException()
174
+ {
175
+ ConfigSource config = Exec.newConfigSource()
176
+ .set("in", inputConfig())
177
+ .set("parser", parserConfig(schemaConfig()))
178
+ .set("type", "azure_blob_storage")
179
+ .set("account_name", "invalid-account-name")
180
+ .set("account_key", AZURE_ACCOUNT_KEY)
181
+ .set("container", AZURE_CONTAINER)
182
+ .set("path_prefix", "my-prefix")
183
+ .set("file_ext", ".csv")
184
+ .set("formatter", formatterConfig());
185
+
186
+ Schema schema = config.getNested("parser").loadConfig(CsvParserPlugin.PluginTask.class).getSchemaConfig().toSchema();
187
+
188
+ runner.transaction(config, schema, 0, new Control());
189
+ }
190
+
191
+ @Test
192
+ public void testAzureFileOutputByOpen() throws Exception
193
+ {
194
+ ConfigSource configSource = config();
195
+ PluginTask task = configSource.loadConfig(PluginTask.class);
196
+ Schema schema = configSource.getNested("parser").loadConfig(CsvParserPlugin.PluginTask.class).getSchemaConfig().toSchema();
197
+ runner.transaction(configSource, schema, 0, new Control());
198
+
199
+ TransactionalFileOutput output = plugin.open(task.dump(), 0);
200
+
201
+ output.nextFile();
202
+
203
+ FileInputStream is = new FileInputStream(LOCAL_PATH_PREFIX);
204
+ byte[] bytes = convertInputStreamToByte(is);
205
+ Buffer buffer = Buffer.wrap(bytes);
206
+ output.add(buffer);
207
+
208
+ output.finish();
209
+ output.commit();
210
+
211
+ String remotePath = AZURE_PATH_PREFIX + String.format(task.getSequenceFormat(), 0, 0) + task.getFileNameExtension();
212
+ assertRecords(remotePath);
213
+ }
214
+
215
+ public ConfigSource config()
216
+ {
217
+ return Exec.newConfigSource()
218
+ .set("in", inputConfig())
219
+ .set("parser", parserConfig(schemaConfig()))
220
+ .set("type", "azure_blob_storage")
221
+ .set("account_name", AZURE_ACCOUNT_NAME)
222
+ .set("account_key", AZURE_ACCOUNT_KEY)
223
+ .set("container", AZURE_CONTAINER)
224
+ .set("path_prefix", AZURE_PATH_PREFIX)
225
+ .set("last_path", "")
226
+ .set("file_ext", ".csv")
227
+ .set("formatter", formatterConfig());
228
+ }
229
+
230
+ private class Control
231
+ implements OutputPlugin.Control
232
+ {
233
+ @Override
234
+ public List<TaskReport> run(TaskSource taskSource)
235
+ {
236
+ return Lists.newArrayList(Exec.newTaskReport());
237
+ }
238
+ }
239
+
240
+ private ImmutableMap<String, Object> inputConfig()
241
+ {
242
+ ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
243
+ builder.put("type", "file");
244
+ builder.put("path_prefix", LOCAL_PATH_PREFIX);
245
+ builder.put("last_path", "");
246
+ return builder.build();
247
+ }
248
+
249
+ private ImmutableMap<String, Object> parserConfig(ImmutableList<Object> schemaConfig)
250
+ {
251
+ ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
252
+ builder.put("type", "csv");
253
+ builder.put("newline", "CRLF");
254
+ builder.put("delimiter", ",");
255
+ builder.put("quote", "\"");
256
+ builder.put("escape", "\"");
257
+ builder.put("trim_if_not_quoted", false);
258
+ builder.put("skip_header_lines", 1);
259
+ builder.put("allow_extra_columns", false);
260
+ builder.put("allow_optional_columns", false);
261
+ builder.put("columns", schemaConfig);
262
+ return builder.build();
263
+ }
264
+
265
+ private ImmutableList<Object> schemaConfig()
266
+ {
267
+ ImmutableList.Builder<Object> builder = new ImmutableList.Builder<>();
268
+ builder.add(ImmutableMap.of("name", "id", "type", "long"));
269
+ builder.add(ImmutableMap.of("name", "account", "type", "long"));
270
+ builder.add(ImmutableMap.of("name", "time", "type", "timestamp", "format", "%Y-%m-%d %H:%M:%S"));
271
+ builder.add(ImmutableMap.of("name", "purchase", "type", "timestamp", "format", "%Y%m%d"));
272
+ builder.add(ImmutableMap.of("name", "comment", "type", "string"));
273
+ return builder.build();
274
+ }
275
+
276
+ private ImmutableMap<String, Object> formatterConfig()
277
+ {
278
+ ImmutableMap.Builder<String, Object> builder = new ImmutableMap.Builder<>();
279
+ builder.put("type", "csv");
280
+ builder.put("header_line", "false");
281
+ builder.put("timezone", "Asia/Tokyo");
282
+ return builder.build();
283
+ }
284
+
285
+ private void assertRecords(String azurePath) throws Exception
286
+ {
287
+ ImmutableList<List<String>> records = getFileContentsFromAzure(azurePath);
288
+ assertEquals(5, records.size());
289
+ {
290
+ List<String> record = records.get(1);
291
+ assertEquals("1", record.get(0));
292
+ assertEquals("32864", record.get(1));
293
+ assertEquals("2015-01-27 19:23:49", record.get(2));
294
+ assertEquals("20150127", record.get(3));
295
+ assertEquals("embulk", record.get(4));
296
+ }
297
+
298
+ {
299
+ List<String> record = records.get(2);
300
+ assertEquals("2", record.get(0));
301
+ assertEquals("14824", record.get(1));
302
+ assertEquals("2015-01-27 19:01:23", record.get(2));
303
+ assertEquals("20150127", record.get(3));
304
+ assertEquals("embulk jruby", record.get(4));
305
+ }
306
+ }
307
+
308
+ private ImmutableList<List<String>> getFileContentsFromAzure(String path) throws Exception
309
+ {
310
+ Method method = AzureBlobStorageFileOutputPlugin.class.getDeclaredMethod("newAzureClient", String.class, String.class);
311
+ method.setAccessible(true);
312
+ CloudBlobClient client = (CloudBlobClient) method.invoke(plugin, AZURE_ACCOUNT_NAME, AZURE_ACCOUNT_KEY);
313
+ CloudBlobContainer container = client.getContainerReference(AZURE_CONTAINER);
314
+ CloudBlob blob = container.getBlockBlobReference(path);
315
+
316
+ ImmutableList.Builder<List<String>> builder = new ImmutableList.Builder<>();
317
+
318
+ InputStream is = blob.openInputStream();
319
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is));
320
+ String line;
321
+ while ((line = reader.readLine()) != null) {
322
+ List<String> records = Arrays.asList(line.split(",", 0));
323
+
324
+ builder.add(records);
325
+ }
326
+ return builder.build();
327
+ }
328
+
329
+ private boolean isExistsContainer(String containerName) throws Exception
330
+ {
331
+ Method method = AzureBlobStorageFileOutputPlugin.class.getDeclaredMethod("newAzureClient", String.class, String.class);
332
+ method.setAccessible(true);
333
+ CloudBlobClient client = (CloudBlobClient) method.invoke(plugin, AZURE_ACCOUNT_NAME, AZURE_ACCOUNT_KEY);
334
+ CloudBlobContainer container = client.getContainerReference(containerName);
335
+ if (container.exists()) {
336
+ return true;
337
+ }
338
+
339
+ return false;
340
+ }
341
+
342
+ private void deleteContainerIfExists(String containerName) throws Exception
343
+ {
344
+ Method method = AzureBlobStorageFileOutputPlugin.class.getDeclaredMethod("newAzureClient", String.class, String.class);
345
+ method.setAccessible(true);
346
+ CloudBlobClient client = (CloudBlobClient) method.invoke(plugin, AZURE_ACCOUNT_NAME, AZURE_ACCOUNT_KEY);
347
+ CloudBlobContainer container = client.getContainerReference(containerName);
348
+ if (container.exists()) {
349
+ container.delete();
350
+ // container could not create same name after deletion.
351
+ Thread.sleep(30000);
352
+ }
353
+ }
354
+
355
+ private static String getDirectory(String dir)
356
+ {
357
+ if (dir != null && !dir.endsWith("/")) {
358
+ dir = dir + "/";
359
+ }
360
+ if (dir.startsWith("/")) {
361
+ dir = dir.replaceFirst("/", "");
362
+ }
363
+ return dir;
364
+ }
365
+
366
+ private byte[] convertInputStreamToByte(InputStream is) throws IOException
367
+ {
368
+ ByteArrayOutputStream bo = new ByteArrayOutputStream();
369
+ byte [] buffer = new byte[1024];
370
+ while(true) {
371
+ int len = is.read(buffer);
372
+ if(len < 0) {
373
+ break;
374
+ }
375
+ bo.write(buffer, 0, len);
376
+ }
377
+ return bo.toByteArray();
378
+ }
5
379
  }
@@ -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-output-azure_blob_storage
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
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 00:00:00.000000000 Z
11
+ date: 2015-11-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -46,8 +46,10 @@ extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
48
  - .gitignore
49
+ - .travis.yml
49
50
  - README.md
50
51
  - build.gradle
52
+ - embulk-output-azure_blob_storage.gemspec
51
53
  - gradle/wrapper/gradle-wrapper.jar
52
54
  - gradle/wrapper/gradle-wrapper.properties
53
55
  - gradlew
@@ -55,9 +57,11 @@ files:
55
57
  - lib/embulk/output/azure_blob_storage.rb
56
58
  - src/main/java/org/embulk/output/azure_blob_storage/AzureBlobStorageFileOutputPlugin.java
57
59
  - src/test/java/org/embulk/output/azure_blob_storage/TestAzureBlobStorageFileOutputPlugin.java
60
+ - src/test/resources/sample_01.csv
61
+ - src/test/resources/sample_02.csv
58
62
  - classpath/azure-storage-4.0.0.jar
59
63
  - classpath/commons-lang3-3.4.jar
60
- - classpath/embulk-output-azure_blob_storage-0.1.0.jar
64
+ - classpath/embulk-output-azure_blob_storage-0.1.1.jar
61
65
  - classpath/jackson-core-2.6.0.jar
62
66
  homepage: https://github.com/sakama/embulk-output-azure_blob_storage
63
67
  licenses: