embulk-output-azure_blob_storage 0.1.0 → 0.1.1

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 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: